In the news over the last week, names, birth dates, email addresses, and encrypted password hashes were stolen from Sega’s “Sega Pass” network. (In other news, Sega still exists.) Several weeks ago, 180 passwords were stolen from an organization called InfraGard that partners with the FBI. Last month, over one million passwords were stolen from Sony and, shockingly, they were stored in the database in plain text. In another story, Google was hacked by Chinese hackers, who obtained data on senior United States officials.
These stories have become so frequent that it is almost possible to become numb to them.
The Sony incident is probably the most interesting of these four. There is no reason ever to store passwords in plain text – that’s just asking for something bad to happen. If you never have a need to retrieve your user’s password (which is usually the case), then you should store a “hash key” – a sequence that is derived from the password. (See our discussion of the cryptography services in .NET.) A cryptographic hash function is a “one-way” function that can be used only to encrypt and, ideally, cannot be used to recover the original password other than by brute force hacking.
Equally shocking about the Sony incident is that the data was obtained from a SQL injection attack – just three years after they experienced another SQL injection attack. (Fool me once, shame on you; fool me twice, shame on me.) SQL injection attacks are among the easiest problems to prevent. A normal SQL query might look like this:
SELECT * FROM tablename WHERE value = ‘abcd1234’
In this example, “abcd1234” is data that the user provided in a form on your website. In an injection attack, the hacker, instead of entering abcd1234, will “inject” code into the statement. So they might replace “abcd1234” with something like this:
abcd1234′ AND exists (SELECT * FROM sys.sysusers WHERE [name] like ‘a%’) AND ‘a’ = ‘a
When this input is “injected” into the SQL statement, it results in:
SELECT * FROM tablename WHERE value = ‘abcd1234’ AND exists (SELECT * FROM sys.sysusers WHERE [name] LIKE ‘a%’) AND ‘a’ = ‘a’
A hacker could repeatedly submit queries like this and eventually derive all of the user names in the database (or table names, or column names, or server names, or any other data of interest).
Injection attacks are completely prevented very easily through the use of bound parameters. With a bound parameter, the query is changed to use a named variable like this:
SELECT * FROM tablename WHERE value = @val
The named variable is then “bound” to the value in question, so even if a user enters malicious data, that data is never executed. (It is at least important to note that stored procedures sometimes use dynamic SQL and if you are calling such a stored procedure, you also need to ensure that you are not dynamically generating a query that is subject to injection.)
What are some of the security issues you encounter? Let us know in your comments.
image credit: D. Sharon Pruitt