SQL Injection Attacks Increasing
An anonymous reader writes "Help Net Security has a story that covers the dramatic increase in the number of hacker attacks attempted against its banking, credit union and utility clients in the past three months using SQL Injection." Article follows up on press release with a little more information. Not a lot here shockingly surprising, but it's worth mentioning that SQL injection is a real pain for web developers. You have to be very careful about checking user input.
Sudden traffic surge from certain news sites can be a pain.
Simply forcing request variables to the correct type and escaping all strings is pretty much the only thing you need to do.
Most languages provide the functionality to do that (in php: intval() for all integer request vars, and _escape_string() for string data.).
It's just a small amouth of work, yet a lot of people are way to lazy.
"SQL injection is a real pain for web developers. You have to be very careful about checking user input." Say what? All you have to do is use parameters, not string catenation. Of course, checking the user input is good for other reasons but not for SQL injection attacks. Or are there web application frameworks which don't support parameterized SQL statements?
Perhaps all programmers working on professional database systems should have to get a professional qualification to show that they can write secure code. I wouldn't say the same should be manditory for things like usability or stability (except for special sensitive areas), but being able to write code that actually allows serious danger without qualification is pretty weird. Builders need qualifications, electricians do, gas installers do, ...
The only people who consider it a pain in the ass are people who are (a) lazy, (b) not adequately security-conscious, (c) programming without a framework that provides good tools to do this. The reason we have so many SQL injections is because we have legions of web programmers who were never taught how to write code in a hostile environment. Web programming is never presented in that light; it's always, "here's a quick little script that fetches twenty records from a database and displays them." Security is far too often a footnote or an appendix that beginning programmers never get to. Building apps for the web is not like doing your Data Structures I homework. You need a different mindset. It's a lot more like designing locks--for prisons full of inmates eager to get out.
People are never as simple as their stereotypes. This applies equally to Christians, Muslims, and Emacs-lovers.
How can it be that hard for web developers to check data before it is submitted? I wouldn't imagine trusting the data that an anonymous user can enter into my website.. so maybe I'm just trained to check data. Of course, I'm also glad I use MySQL with PHP where a simple mysql_real_escape_string can prevent any popular SQL Injection attempt.
but it's worth mentioning that SQL injection is a real pain for web developers
Which web developers would these be? MuppetsR'US ? SQL injection is a pain if you take the input and lob it directly to the database without doing any sort of validation that the information is sensible.
Its a great example of all those people who scream "THIS IS SO MUCH QUICKER TO DEVELOP IN THAN THE OLD WAY" and then bite it after the system goes live.
SQL injection isn't a pain, except for those who think they've found a new quick magic bullet that solves all the problems and the old fuddy duddy practices are now all redundant.
An Eye for an Eye will make the whole world blind - Gandhi
Checking input for escape attempts is error-prone. Passing in parameters as bind variables *isn't* error-prone (with regard to blocking SQL injection attacks); makes string quoting completely moot; and can result in a massive performance increase (particularly against Oracle) to boot.
I continue to be in disbelief that anyone doing professional database work can *not* follow this widely accepted best practice and continue to be employed.
If your webapp is Java based, use PreparedStatements. Never use Statements. PreparedStatements are immune to SQL Injection based attacks since the variable replacements are never interpreted. PreparedStatements are also much, much faster.
Make sure you specify where you get your incoming data from, like using $_POST, $_GET, $_SESSION, etc, don't just grab them from the air (with globals on).
Make sure you use mysql_real_escape_string() on all incoming data that is headed for the mysql database (to get rid of SQL injection).
Make sure you use strip_tags() on all incoming data that is headed for output on your page (to get rid of cross-site scripting).
Meh.
Just don't build your query on the fly.
Bind ALL parameters to placeholders in a prebuilt query. Binding is an instant kill for any SQL injection attack. It is also much more effecient on many databases.
There is nothing so silly as other peoples traditions, and nothing so sacred as our own.
Since when is it the job of the language to protect you from SQL injection? I think you're confusing the language of PHP with the standard libraries it ships with, mysql_*() and co. It's worth noting that PHP *does* support prepared statement's using the 'new' object oriented mysqi interface much like the Perl DBI. This handles the casting of types and escaping of strings for you.
What about people who have surnames like O'Neil - would you try stripping out the single quotes or would you insist that people use the escaped SQL form O''Neil? The correct way to foil SQL injection is to use parameters.
You're a temporary arrangement of matter sliding towards oblivion in a cold, uncaring universe
Of course it's the job of the language to make it as easy as possible to write secure code, and as hard as possible to write insecure code. That should be blindingly obvious, especially for a language that's pretty much aimed at people with little programming experience who are likely to have no idea what they're doing.
There are some possibilities if some part of your stack is using UTF-8, for example. What one portion doesn't interpret as a ' will effectively hide or be translated into ' at a later point. You can come up with more variations of the basic idea.
You have to be very careful ...
This phrase is a common tipoff to one of the main problems.
The computer doesn't give a damn how careful you are. If you spend hours carefully crafting a chunk of code that, through your ignorance, has a big security hole, all your care hasn't helped a bit. You have merely produced bad code.
OTOH, someone with good knowledge of the subject might toss off a 30-second routine that, due to their understanding, is highly secure.
Carefulness has little to do with doing a good job. Carefully doing it wrong is merely doing it wrong, no matter how careful you are. And doing it right is doing it right, even if you hardly gave it a thought.
What we need here isn't useless exhortations to "be careful". What we need is education about how code gets into trouble, and training in writing code that doesn't have problems.
Yeah, I routinely write code that checks input. But if there's some hidden gotcha that I don't know about (typically in some library routine that's not visible to me), I'm quite aware that my careful checking might do little good.
Those who do study history are doomed to stand helplessly by while everyone else repeats it.
First rule of writing CGI: never trust the data! I work in Perl, and when an app is exposed to the outside world, I have to assume someone is going to try and get in through some hole if they can (or worse, will do something stupid that would have a negative affect oon my systems).
It starts with the web page -- validate input data. I know, I know, anyone can copy your page and rip out the JavaScript validation, but it doesn't hurt to put up a first line of defense. Next, before you actually use the data from the form for anythig validate it separately. In Perl, I have taint mode enabled by default for external apps and I treat all the data I receive as if it were dog crap. I massage it with regexes to make sure it is what it's supposed to be, and then pass it on to be processed. I find the best way to put up a wall is to have the form parameters sent to a validation script, then have the validation script call the script which would run the actual query, throwing back an error message to the user (and sending me a message in the process) if something's not right.
Data validation is really not that hard, especially if you know exactly what the inout is supposed to be. It gets iffier if the user can put in pretty much anything -- then you have to be a little more paranoid.
GetOuttaMySpace - The Anti-Social Network
- Stored Procedures
- Parameterized Queries
- Learn the SQL-92 Specification (so that you're familar with the language beyond just SELECT, INSERT, UPDATE, and DELETE. There are all kinds of things out there to help you get rid of that dynamic code, like COALESCE, and CASE WHEN, etc.)
Here's the SQL-92 Specification (pops in a new window)Except, the web is international. So "traditional" alphanumerics are not good enough. Or are you telling me that René should spell his name Rene? (in French, the two are pronounced completely differently - Ren (Rene) and Renay (René)) Or how about non-alphabetic languages like Chinese?
Many people use non-alphanumerics in their email. I, for example use underscore.
With the gradual movement of the web to non-latin URLs, too, the need for the acceptance of all printable Unicode in webforms has never been greater.
And as has often been pointed out, you can reduce the risk of your passwords being susceptible to dictionary attacks by using wierd (or perhaps unprintable) Unicode characters. Web & DB devs should do well to note that - I dislike sites immensely that restrict me to alphanumeric passwords - I'd like to use whatever alphabet I choose, to make my password more secure.
I'm not saying that input validation is a bad idea. It just needs to accept and validate input in any appropriate language - which for things like "Name" could be anything, even if the user is an anglophone. Some fields, like DOB, or numeric fields are easily validated - others like "Name" would be better cross-checked against a list of banned inputs, and escaped (or use parameters).
Often when I am on a page that looks SQL-injectionable, I'll try a few things just for giggles. I've been doing this for a few years now. I'd say that there are much, much fewer injectionable sites then there used to be...
The last time I did a SQL injection, I hallucinated that everything around me was displayed in an orderly array.
He who knows best knows how little he knows. - Thomas Jefferson
There is a way to solve SQL injection problems: Disallow text literals in the database engine. Or even, disallow literals (including numbers) at all. This could be a setting in the database that is on by default, and only off for certain applications (ad hoc query tools). What do you think about that?
I'm thinking about implementing this feature in the database I write (http://www.h2database.com/):
This would be a persistent setting, and only an admin can change it.(Of course there are other security risks, like using 'customer id' in URL or hidden fields in a web application. Or relying on Javascript data validation. I don't know what to do about those problems.)
are there web application frameworks which don't support parameterized SQL statements?
that would be PHP.
Quit spreading FUD. PHP supports parameterized SQL just as well as any other language I've worked with. See, for example this doc page (search for "Example 2"). Even for databases whose native C APIs don't support the feature (i.e. MySQL), the database abstraction layer PEAR::DB that is distributed with PHP provides emulation.
I'm a student web programmer for the webdevelopment lab in a major U.S. University. The platform they basically told me I had to program on is PHP with MySQL. The server doesn't support anything else and getting the server guy to update or add anything new is a major pain and usually impossible. Point in case: I'm still working with PHP 4.1.2 and MySQL 3!!!!!!!
I still have to write some fairly secure applications (if they get breached there won't be any terribly sensitive information, but there are some things that we would rather be kept private (such as an online-store system for one of the on campus labs.... no purchases online, but the entire store (4000+ items in inventory) is there, along with purchase records, etc). I tried to get the server admin to either upgrade PHP and install the mysqli library so I could actually do compiled queries and all of that, but no go.... Maybe by next year -_- (the guy thought SQL Injections were a local exploit and then thought that since we were running over HTTPS it was okay....)
My point is that sometimes it is not the programmers fault that they cannot make use of the some of available options to make their application supposedly more secure. You have to do the best you can with what you have and write code that is put together well enough that when new features do become available on the server or someone does get breached and it needs to be improved, it is easy enough to upgrade and maintain the code. Right now I'm stuck using mysql_escape_string and type checking (heh, not even _REAL_escape_string...... the PHP version is that old!) and keeping my fingers crossed (and continuing to pester the admin hoping for better results faster). So don't always blame the programmers!! We do have to work within limitations too!
If you can't say something nice, make sure you have something heavy to throw.
Input checking is a half-assed solution.
maybe, but you need to do it anyway. You menton bind variables, and that's definitely something that people should do, but bind variables wont stop out-of-bounds inputs. For example, if you are expecting an integer between 1 and 3, you still need to do input checking.
You get what you pay for. A lot of people already suggested easy solutions to the problem that are just as easy to implement and that would immediately make the problem disappear. So why is it not done?
Simple: The people who write those insecure databases don't even know that those functions and features exist. Some ages ago, they learned a bit about SQL, maybe did a course about it (so they have a sheet of paper saying "Look, I can do it!") and that's it.
HR managers tend to go by papers, and by price. Now, who do you think is cheaper to hire? A person with a well rounded education concerning computers, programs and the fallacies, pitfalls and security issues around them, or someone who learned his SQL statements by heart and has no clue what exactly is going down inside the server?
Sure, both of them will create code that does what the specs say. As long as you only enter data according to spec (which is, interestingly enough, ALL that is checked, even under the SOA). The true quality of code is revealed as soon as you pit something unexpected and malicious against it.
We used to have a Bill of Rights. Now, with the rights gone, all we have left is the bill.
Mark me OT or mod me down with something, I'm fine with that.
/.. In many circles, this question would have gotten "do you want me to write your code for you?" or "RTFM", or "Google (something here)", or statements that question the poster's value in the world. I learned something from the replies, and I appreciated the tone of voice of the replies. I, for one, am so glad so many smart people post here.
The responses to the serious question post are an example of what's good about
OK, back to your regularly-scheduled time sink...
A Passionate Independent Musician
Those statistics are pretty meaningless when you look at this.
G =Search
g le+Search
http://www.google.com/search?hl=en&lr=&q=perl&btn
Results 1 - 10 of about 370,000,000 for perl.
http://www.google.com/search?hl=en&q=php&btnG=Goo
Results 1 - 10 of about 5,540,000,000 for php
So based on those numbers there should be more results for anything on PHP.
I did a quick google and found this as a description for sql injection. I would think that, at the very least, if you handle all your strings (and numbers) properly then this problem goes away. Say you have a field "LastName". If you just concatenate the value entered into the field into your SQL then you're asking for all kinds of problems (Any O'briens etc. out there?).
For all my fields I use a simple function to ensure that the data being put into the query is safe for the query (Replace(foobar, "'", "''") - for SQL Server). For numeric values, well, you just make sure that they are numerical as part of the validation (or you limit the characters they can type into a numeric field).
dnuof eruc rof aixelsid
This doesn't fix the problem as there are some vulnerabilities in it with regards to unicode.
- Stored procedure: a function that runs within the database server.
- Prepared/bound statement: something in code -- usually provided by the programming language's database layer -- that looks like the following:
Then you set item 1 to some value, item 2 to another, etc. Other variations exist as well:Here you can set values by name rather than by index. The implementation of this on the back end (where you should not be able to see it) may in fact be a stored procedure in databases that support it -- especially for SQL statements that are run repeatedly. However, even if the database doesn't support stored procedures, binding variables will always work since the issue is handled completely in code.And then of course there are folks who don't want SQL anywhere near their code. That's when you may opt for an object-relational mapping library and/or stored procedures within a database.
Bottom line: escaping each time on your own is error-prone. Better to solve the problem right the first time. And it's easier than manually escaping/validating as well!
- I don't need to go outside, my CRT tan'll do me just fine.
It amazes me that there are banks out there don't do code reviews and pen-test to prevent simplistic attacks like this prior to rolling something into production?
God lord!
We require 3 layers of data validation (as part of the web interface, as part of the middle-ware layer, and within the database as triggered stored procedures for updates and inserts.)
Not doing this SHOULD be criminal in my mind.
Sure you can use stored procedures. And sooner or later you might regret it:
- Your company merges with another company using a different DBMS and you're told the infrastructures should be merged.
- You business grows. While you can always add new application servers, J2EEs etc pretty easily, you'll have a hard time upgrading your DBMS over a certain point - and it's going to be more costly.
- Maybe something is twice as fast on the database compared to the application server. However, you will always have 1 database for all your application servers. So where will the bottleneck be? I'd rather have the operation take twice as long for each request - on each of my half dozend app-servers - than have it run twice as fast on my single database that's slowing down to a grinding halt while the app-servers are idling away. Bye bye minimum response time.
I had a friend that was convinced her web front end to a database centric application was bullet proof. The user interface was accessed by clicking on a java script link which controlled the browser behavior. It brought up a browser window without toolbars. In the browser window all of the options were choosen via select boxes. Nothing new was added by the user through the application. She started to brag about the amount of code she didn't have to write to filter user input.
I started a tcpdump -xX port 80 and host her.host Because everything was being passed plain text we could see everything in the uri. After a quick nmap -vv -sV -P0 her.host I connected via telnet her.host 80 After the required http 1.1 hello stuff I started submiting commands to her cgi script; alpha characters instead of numeric, big decimal numbers, negative values... It didn't take long for her to decide to rewrite it.
Having to work for a living is the root of all evil.
In fact, Perl's DBI is not only fast, but when used properly (variable substitutions, binding variables, etc) it works extremely well. Also the fact that everytime you change your data source (CSV, XLS, MySQL, SQLite, MSSQL Server, Oracle, PostGres, etc) all your functions don't change. You can always count on:
If you're not doing some kind of column binding or type-casting on your form-derived query arguments, you are always leaving yourself open to sql injection.
With the help of a whiteboard (!) I explained to about half a dozen ( okay, mostly junior ) developers and -- here's the real kicker for me -- *the three most senior members of out QA department, including the department head* that you could use the password
' or 1 = 1 --
for many, many sites on the Internet, regardless of user name.
The whiteboard came in when I had to explain *why it worked*...
_shakes head_
remember the wisdom of Mahatma Gandhi: If enough peasants die horribly, someone will probably notice
.. because avoiding SQL injection is relatively easy to do.
1. Use only prepared statements or stored procedures (Note even without concerned of SQL injection this is a good idea).
2. If you use stored procedures do not use any of the passed in values to generate dynamic SQL (otherwise you have just moved the problem from the app to the database).
meh