How not to protect against SQL injection (view source)
cadw.wales.gov.uk
cadw.wales.gov.uk
It was my first website at an agency, I'd just taught myself ASP and SQL in just a few months previous (with no help or guidance). If my memory serves me correct, that dodgy JavaScript was put in there by a more senior developer. I had no idea what SQL Injection was and it wasn't until at least a few years later that SQL Injection was even something any developers I knew were aware of - The Wikipedia page for SQL Injection (http://en.wikipedia.org/wiki/SQL_injection) under "Known real-world examples" has the earliest dated at 2005 (but obviously, this vulnerability has been around forever).
And yes, I'm still a Web Developer (front-end nowadays - that also knows much better than this) and no, I no longer work for that agency and haven't for a long time.
In response to some of the comments: * I've seen many many developers write SQL Injection prone code at least 6 years after this was written. * Any developer that was around during 2000-2001 would know that this was before the time of CMS's (free or otherwise), libraries, frameworks, SQL abstraction layers etc. * I'm pretty sure there is some server-side sanitising done too (before we'd heard of the term SQL Injection). * I don't think it was using an SQL login with drop permissions.
I see this as a civic duty, and think that this is the kind of action you're required to perform if you see a serious problem. Writing an e-mail takes ten seconds, but the potential damage could well cost serious money.
If you're very lucky, the place you are in won't honor their demands for extradition on the hacking charges.
Here's the mail I sent:
Hi there,
It appears that you have some pretty severe security problems on your site. This is a heads up so you can get it fixed. I would recommend doing so ASAP.
Your site has been posted to hacker news (which is a friendly programming site for start-up people and nerds) as an example of bad security practices. The link is here: http://news.ycombinator.com/item?id=2383857
It has also been posted to Reddit, which might be more of a problem since that site has a lot of 14 year old bored teens hanging around that know just enough about programming to do a lot of damage... Link: http://www.reddit.com/r/programming/comments/gdviz/how_not_t...
It appears that your site is easy to compromise, which might lead to anything from defacement to someone stealing all your content, usernames, passwords, etc.
I have nothing to do with these postings, I just don't like to see innocent sites get in trouble, hence this mail. Feel free to contact me if you need anything or have questions.
Hope you get it fixed before someone breaks it.
Yours,
Max
Oh, I understand the word hacker in all its culturally and context relevant forms, and you understand the word hacker, but they do not understand the word hacker. :-(
If we, as hackers of the sort that inhabit hacker news, have a post like this on the frontpage and noone cares to actually write them and tell them they have a security problem that may cause them serious damage we don't deserve better.
Edit: But your email is very amiable and clear, so I think you're probably safe.
I lost a lot of my faith in humanity that day.
In fact, a security consultant was convicted[1] for using ../../ in a URL after he thought a site had been hacked.
I sent an email to the stuff out there. I typed "I just hacked your software. It's insecure and not obfuscated. Tell the devs".
The guy replied accusing me of hacking the software and told me that he is going to sue me. I just replied "F*ck you and your team. I was just playing around with no intent to make any damage for your company; but now I'll release a cracked version and distribute it".
I hadn't released a cracked version, though.
Doing web security well is hard, too hard. Everyone gets caught with a security bug sooner or later, even google. It's easy to laugh with silly coding like this, but I blame the technology for allowing SQL injection in the first place. SQL is simply a bad API to be using in a web app.
sql_query('SELECT * FROM mytable WHERE name = ?', name)
(I'm aware that this defeats the purpose of prepared statements to be reusable - this is just an API that's better than the current methods)Huh? Most web frameworks use ORMs and discourage you from touching SQL at all.
Yes, there might be cases that a very specifically optimized query needs SQL, but those should be the exception not the rule.
A password must:
be 6-8 characters in length.
contain a non-alphanumeric character such as ( ! ] & * , + =
A password cannot:... include a dollar sign ( $ ), a single quote ( ‘ ), a double quote ( “ ), a number sign ( # ), a less-than sign ( < ), a question mark ( ? ), a pipe ( | ), a back quote ( ` ), or a backslash ( \ ). ...
If it was a startup web app I was signing up for, I'd send the developer a polite email saying that I didn't feel comfortable putting my data in such a system. Unfortunately, all I can usually do is gripe a little in private.
† Which are not a cure-all for SQLI.
Side note: We're jumping to conclusions by thinking that the javascript is the entire implementation. It's perfectly possible that the server is already safe against SQL injection and the javascript is just an extra line of defense. Maybe the client and server were done by separate programmers and the client programmer wanted to make sure he wouldn't get blamed. It's a government website: nobody in government ever got fired for being too careful. Or maybe the programmer had to do it to satisfy some non-technical bureaucrat who wanted to think that hacking attempts couldn't even reach his server.
I do not address web stacks directly there, but Python itself will happily let you use prepared statements, it is up to the programmer to take effective steps to prevent SQL Injection.
This is a principal issue. Doing client-side parameter validation for security is a stupid idea in every case. Client-side validation is for user convenience only. This has nothing to do with SQL. Security must be implemented server-side. There are no exceptions to this.
As for SQL being a "bad API" that might be one of the more ridiculous comments I have heard.
It is indeed unreasonable to expect a junior developer to make form submission secure. Aside from SQL injection there's DoS, MiTM, CSRF, XSS, session fixation, cache poisoning, clickjacking, timing attacks (to detect valid vs invalid values), rainbow table attacks, and many more. Just go through the list of requirements in OWASP ASVS. It's intimidating how much stuff there is to keep track of. We have a dedicated security engineer on our team who reviews all new code, out of necessity.
Also, about SQL being a bad API, I didn't say it was a bad API in general, just bad for the web. SQL is like eval(), it evaluates code from a parsed string. If eval() is bad for the web, SQL is just as bad.
There is no excuse why programming languages should require the programmer to work around the inherent deficiencies of SQL. Just like the x86-64 architecture introduced the no-execute bit to the mainstream computing world and made the rampant buffer overflow remote code execution exploits of the 1990s into an endangered species, we should look to a technological solution to solve SQL's deficiencies.
Why should we need to trust that thousands of CMS module developers all use, know, and understand detainting of input in their native language? If we want to allow reuse of code, we put our absolute trust into thousands of developers other than ourselves.
I don't know why but I just don't trust them...
function getTime() {
<?php return time(); ?>
}
It's not at all improbable that somebody told them their site was vulnerable to SQL injection, so they took a brief glance at the Wikipedia page and said, "I know, I'll just stop people from writing this stuff." So they open up the page where people might be entering the malicious text and write some code that will stop them. They run it in their browser and it works — none of their SQL strings make it through. They have now fixed the problem, as far as they are concerned, and the site owner doesn't know enough to tell them how utterly braindead their approach is. window.pageBirthday = <?php echo time(); ?>
Also, if they're on Stack Overflow asking why it doesn't correctly report the current time, that's a pretty good indicator that they're simply mistaken.Based on some of the comments there, it doesn't look like it (or at least, it wasn't there several hours ago when Reddit stumbled upon the site). See http://www.reddit.com/r/programming/comments/gdviz/how_not_t... for some examples.
And leaking the MS SQL server errors and IIS errors are just adverts for MS (I only did genuine searches, "hotel" got me to an error page).
I'm sure the silly long names are part of the ruse too.
There is much that could be done with this site. Perhaps I could drop them a CV.
Of course, this does not eliminate the need for solid code-based prevention of injections...
A moderately large amount of this information is available on the Internet, start at http://www.cabinetoffice.gov.uk/resource-library/security-po... if you want a look. A brief look through the sitemap suggests they are holding or processing Personally Identifiable Information (PII) which puts them under the Data Protection Act. Again, the presence of the javascript doesn't imply actual SQL injection, but it definitely doesn't imply a measure against it.
In this instance, the compliance requirements are fairly low. I guess the exam question is, can they pass the bar, or do they limbo under it?
It depends on the language, but this is what you'd do in .NET, for example. In this case, the framework does the work for you by encoding the value of lastnameparam (it makes sure that whatever is supplied to lastnameparam isn't read as SQL).
Looking at it that way makes it a much more understandable (and all-too-common, unfortunately) oversight.
It's not like you can't store semi-colons in an SQL database :)
Every Web Dev needs to remember this and Yet people tend to forget
Would an open source programmer do something like this?
EDIT: No this doesn't limit you to 'simple queries'! How do you figure that? There are only a VERY small subset of problems you can't solve like this. So small that in 10 years I've only had to do it once and I write SQL Server 5 hours a day.
Want to give me an example please?
In MySQL, for instance, LIMIT and OFFSET have to be integer constants; the wire protocol won't allow you to bind variables to them. Does your SQL engine allow you to parameterize a table name? Can you parameterize columns? What about ASC and DESC? And this is just simple stuff. What about pages with "Advanced Search" that have to implement query builders?
I've never had a situation where the client enters the column names to return in the UI. I mean the users should not have to know the column names in your database so surely you'll do that some other way instead? It's pretty rare (and probably wrong) to have hundreds of columns being returned, so we'd just return them all and show/hide the relevant ones on the application-side.
Same for table names. Why would you need to have a parameterized table name? This has never come up in all my years of SQL Server. Sounds like bad DB design or something exotic that I've never had to do. I mean how would you index queries like that anyway?
For your 'Advanced Search' I'd probably use a temp table or table variable and do the query in multiple steps using 'IF' switches depending on the flags or setting passed to it.
stmt = "SELECT col1 FROM table ORDER BY col2 " + (isDescendingSort ? "DESC" : "ASC")
As long as all your user input has been filtered through type checking, enumerations, etc. (aside from parameters), is that not a safe approach?
Of course you should use prepared statements when possible.
But web devs do have a bad habit of saying "we're safe, we used prepared statements", and then losing their app within 5 minutes because of the code than handles sortable columns in their table views.
I just dislike the whole "upvote for x" comment that dredges up from Reddit.
'Just lowers the signal-to-noise ratio, and I hate to see things like that creep up on HN.
The only thing that I've written that could be applied to this is our POS system at the restaurant I work at as a dishwasher and cleaner for. It's in Django though, and the Django project takes care of most issues with that...not that they're really priority #1 security-wise...
I think a better approach is to verify that the framework is correct. You can do this experimentally, by writing unit tests, or by reading and running the unit tests of the framework itself.
http://taylorza.blogspot.com/2009/04/sql-injection-are-param...