22

On a whim I've recently decided to throw up the first proper website I created onto my local web server I use for development. I thought it'd be a great environment to throw some SQL at for injection as I know there are flaws and the site was only really meant for my own personal development.

Anyway, to get to the point, after a few attempts the furthest I could get was to have the page return an error with the statement. I was trying to get into a specific test account I set up, (if the result returns more than one account an error's thrown, so I didn't expect selecting every username where 1=1 to work), but every time I got a response as if I had entered a normal, incorrect password. I took a look at the PHP code and turns out I was hashing the password before the query so the attack was being hashed before it could do any harm.

Being new to web security as a whole, and having an interest in web development, I was wondering whether there are any vulnerabilities with this method of SQL injection prevention as I expect to have not thought something through. Just to clarify, this isn't meant to be a "look guys I've found something new" as there are plenty more brighter sparks in information security than myself, who would have likely figured this out already, but I'd like to know why this likely isn't suitable as a security mechanism.

Peter Mortensen
  • 895
  • 5
  • 10
lewis
  • 351
  • 1
  • 2
  • 7
  • An answer to a distantly related question that I was reading earlier today, especially "The act of hashing a password is the act of making the password safe to store in your database. The hash function doesn't give special meaning to any bytes, so no cleansing of its input is required for security reasons" – Honinbo Shusaku Dec 19 '16 at 19:01
  • Any information that is hashed can't be displayed. You end up hashing only for some and not for other. If you are thinking of using other cipher then you end up with the same problem as just replacing ' with '', you hope that this solution works, which often time doesn't because of special cases that you didn't think of. Better have a consistent method that has proven to work which is parameterize query. – the_lotus Dec 20 '16 at 13:52

5 Answers5

36

So, hashing the user password before entering it into the query is a coincidental security feature to prevent SQL injection, but you can't necessarily do that with all user input. If I'm looking up a Customer by their Name and I have a query like

Select * from Customer Where Name like '%userInput%'

If I set userInput as a hashed version of what was typed in, it wouldn't work correctly even if Name was also hashed in the database, it would only work for exact search query. So if I had a Customer with Name "Sue" and I typed in a search for "sue", it wouldn't work. I also wouldn't know the name of the customers unless there was an exact match in my search, which isn't practical.

The way you want to prevent SQL injection is to not make your queries like above, you'll want to process and parameterize inputs into a query, stripping out things like =s and other symbols that don't make sense in context of the input. A good guide for preventing SQL injection can be found here.

Ryan Kelso
  • 1,230
  • 9
  • 14
  • 21
  • Nowadays, any reasonably maintained query engine does parameterization out of the box, meaning you don't need to do any sanitizing yourself. You just learn the parameterization syntax, write your query that way, and pass the values in separately from the string containing the query. So I think saying you "process" these inputs is misleading. 2. Sanitizing input doesn't "strip" symbols; it escapes them.
  • – jpmc26 Dec 20 '16 at 00:09
  • "So if I had a Customer with Name "Sue" and I typed in a search for "sue", it wouldn't work" — this actually can work if the name is always converted to lowercase before storing it to DB. (but I'm not saying that it's a good practice of course)

    – Display Name Dec 20 '16 at 08:06
  • @Sarge Sure, that's called normalization. But it still wouldn't match on a query for "Borsch" - because it's hashed, you're matching all or nothing. – Riking Dec 20 '16 at 08:45
  • 1
    Thanks for the response, and the guide also. Though I'm still curious as to why methods of obfuscation aren't used in protecting against SQL Injection more, as it seems to do the job quite well, and even something such as a caesars cipher could provide a quite effective prevention of SQL injection. Of course I'm not suggesting this solely be used as a single point of defence as that seems like a terrible idea with any method of security, but rather wonder why it's not such a popular prevention method used alongside others. – lewis Dec 20 '16 at 08:51
  • @Riking from a development and not security point of view, I'd say converting to upper / lower case before hashing should solve that, for usernames where case sensitivity shouldn't be an issue. – lewis Dec 20 '16 at 08:55
  • @lewis The reason is that obfuscation techniques are much, much more complicated then just using whatever method the API you are using offers by default. All user input requires escaping, whether we output it to SQL, CSV, HTML or whatever. The rules of how escaping should be performed differ per output format and are generally pretty complex to code from scratch... which is why we put it into some common libraries. Just use something like Query q = new Query("SELECT * FROM customer WHERE name like :name"); q.setParameter("name", "%" + name + "%"); q.execute(); or whatever your API does. – Stijn de Witt Dec 20 '16 at 10:57
  • @jpmc26 You are entirely correct of course, query engines are the way to go with working with database interactions as they provide a bunch of security out of the box and can overall reduce code complexity with the database interaction, on your second point again correct and I should correct my answer as escaping is the more standard way of accepting the input. – Ryan Kelso Dec 21 '16 at 13:53
  • @lewis So the reason we don't really care about obfuscation is that it's not super simple to obfuscate both the input and the data in the back end and match those and return a plaintext response (as in the case of searching for customer of name Sue), while if we always escape the characters that can be used to create a SQL query in code (which you should be using query engines as jpmc26 pointed out and Stijn de Witt as they make this fool proof and you don't reinvent the wheel) that's fast and no worries about data in the backend being reconverted for the front when it's returned. – Ryan Kelso Dec 21 '16 at 14:00