Prepare for Attack!—Making Your Web Applications More Secure

Computer SecurityArm yourself and prepare for battle! This post is intended as a reminder about the possible security attacks your Web application may be vulnerable to. While it is not meant as a comprehensive guide to Web-application security, it can give you some ideas on how to better protect your applications.

SQL Injection Attacks

The joy of using an ORM like SQLAlchemy or SQLObject—in addition to the benefit of not having to write a single SQL statement yourself—is its ability to protect you from SQL Injection attacks. Although this built-in security measure affords you protection, it is important to understand how SQL injection attacks work.

If an application contains code that looks like this…

def get_user(self):
    mysql.execute(
        "SELECT * FROM users WHERE user_id='%s'" %
            cherrypy.request.cookies['user_id'].value)
    ...

…then you are vulnerable to the stinging strikes of a malicious user. That’s because he or she can craft a cookie with the value of "someonebad';
TRUNCATE TABLE users; SELECT '"
. The SQL statement that will be executed will then be:

SELECT * FROM users WHERE user_id='someonebad';
     TRUNCATE TABLE users; SELECT ''

…which is not good, not good indeed!

To see just how bad the situation really is for our fellows in PHP land, have a look at these Google code search results, or for our little brothers in ASP land, have a look here. Please act responsibly and don’t hack into the sites listed there. 🙂

Luckily, ORMs escape all the strings we send to the database engine, and as a result, we are protected from this kind of harmful attack.

XSRF: Cross-Site Request Forgery

This exploit is very common in Web applications, especially in those that provide AJAX API. It is best to describe this type of attack with an example. Suppose that an imaginary project, TGBank (which is a Web interface for a bank), has a send_money() method:

    @expose()
    def send_money(self, to_whom, how_much):
        # validate that user has enough money
        transfer_money(
            from_user=identity.current.user.user_id,
            to_user=to_whom,
            amount=float(how_much))
        turbogears.redirect('/')

The bank site using this application might contain a page with a “send money” form, where the user fills in information such as to whom he is transferring the money and how much money he is transferring. Everything’s find and dandy there. But what if the user is connected to the bank site, and in another browser tab, he is simultaneously browsing a malicious site, one that contains the following img tag?

<img src="http://www.tgbank.com/send_money?
       to_whom=thesamet&how_much=0.04" width="0">

Then the user’s browser will trigger that operation on behalf of the unsuspecting and innocent Web visitor. And because it’s such and inconsequential amount, he probably won’t even bother to check about those four cents.

Allowing only POST requests to go into send_money() will not help the matter. That’s because it is easy to send POST requests using Javascript. On the other hand, checking that the HTTP referrer header of the request is within one’s domain is too restrictive. That’s because many browsers often do not send this header.

A possible solution is to add a hidden field that only your application can generate and validate. For example, you might consider that the application will process the request only if received a query argument with the value of a sha1 digest of a string that is composed of the user id and a secret word. This string can be easily validated by your application, but it will be hard for a malicious site to generate.

Utterly Ridiculous!—More XSRF: Stealing Information with Scriptaculous

In addition to doing serious damage, this type of attack can be used to steal information. Suppose the bank application previously mentioned has a URL that returns Javascript code that defines a list with your monthly statement (list of expenses). It may be used on the bank site for doing client side sorting. A malicious site might contain something like this:


Here, that dastardly attacker placed code on his site, that executes the monthly statement script from the bank’s site. Once that script is executed, we have an object named statement containing a list of monthly expenses. Then, after the document finished loading, it is transmitted right into the waiting attacker’s hands.

Recently, an XSRF flaw was discovered (and fixed) in GMail. This vulnerability allowed an attacker to steal the user’s contact list precisely as just mentioned.

Assault–Take Two! XSS: Cross-Site Scripting

Cross-site scripting vulnerability occurs when a Web application generates output that contains user-supplied data without HTML encoding. For example, if we allow a post in a forum to contain HTML tags, then we can use KID to display it:

    <div>
        ${XML(forum_post.body)}
    </div>

Raising the ax yet again, a vile attacker can embed javascript code into his post. Then, when an innocent user visits the page, his or her browser runs the script, unbeknownst to him or her. This script can, for example, send the contents of the page back to the attacker. It might also post a comment to a blog, in the unsuspecting user’s name, or make new friends for him or her in MySpace.

If we do not use the XML() function in KID, then HTML entities are escaped and we are safe. The users will see just the script text and the browser will not interpret it as code. That said, if XML() is to be used, then it is suggested one check whether the string contains '<script' (case insensitive) before actually sending it. You should also beware of spaces between the script and its surrounding < and >, although I haven’t tested which browsers allow it. Note that most HTML elements allow attributes that can contain javascript code like onmouseover or onclick. The safest thing would be to escape all < to < (Python has a cgi.escape function for this). If HTML tags are to be allowed, then the application should carefully check that they contain only permitted attributes. Also the href attribute of <a> tag should be checked that it does not contain something like “javascript:do_something()”. That way, those malicious attackers can be forced to drop their weapons before they have time to draw them.

Now that you’ve learned how to preempt attacks before they strike, you’re well on your way to a more enjoyable Web application development experience. Comments and questions about the strategies outlined here are welcomed. We also encourage suggestions on how you’ve successful waged war against security attackers.

This entry was posted in python, turbogears, tutorial. Bookmark the permalink.

28 Responses to Prepare for Attack!—Making Your Web Applications More Secure

  1. Jay says:

    I had never understood how XSS actually worked. Thanks for the simple explanation!

  2. Aaron Digulla says:

    In the end, you should never allow users to input HTML in your pages. If you really have to, search the input for allowed tags (like <b>, <i>, <em>, etc., remove any unknown attributes in them and replace ‘&’, ‘<’ and ‘>’ in all other places with the escapes ‘&amp;’, ‘&lt;’ and ‘&gt;’ respectively.

    This sounds like a cool util function for TurboGears

  3. Tom says:

    > Here, that dastardly attacker placed code on his site, that puts the monthly statement from the bank’s site, inside a DIV. Then, once that data arrives, it is transmitted right into the waiting attacker’s hands.

    What on earth are you talking about? No browser will allow this sort of cross site scripting. The GMail vunerability was related to the fact that the GMail was returning data as javascript and the script tag doesn’t restrict loading of scripts from other hosts.

    Really, you should at least test your code before writing blog posts like this.

  4. thesamet says:

    Hi Tom,

    Thanks for pointing out this inaccuracy. I’ve corrected the example.

  5. Gumnos (Tim Chase) says:

    [grr…random escaping problems…”preview” would be nice]

    > then it is suggested one check whether the string contains ‘<script>’ before actually sending it.

    You may want to be careful here, as HTML allows all sorts of forgiving factors, so you could have

    <
    script
    >

    or you could have

    < sCrIpT
    >

    or you could have

    < <!– a tag? –> script >

    or you might even be able to have things like

    < sc<!– hah –>ript >

  6. Pingback: Ajaxian » Making your web applications more secure:

  7. Jamie says:

    Well, you do realise that PHP also escapes all those $_GET and $_POST strings too? It is called Magic Quotes

    http://uk2.php.net/magic_quotes

    This has been on by default since PHP4 first came out IIRC.

    Also, in PHP the mysql_query() function will only process a single SQL command. So even supposing you got your SQL injection into the applications listed on that google search, only:

    SELECT * FROM users WHERE user_id=’someonebad’;

    Would be sent to the MySQL server. The rest would be thrown away.

    PHP is reasonably secure on a default install (ie. you have to go out of your way to be insecure).

  8. Great article, but I have yet to see an online banking interface that sends sensitive data via JS. Of course, I only really know the ones that I’m using myself, and, in general, you’re right about making sure it’s secure.

    Jamie:
    I thought Magic Quotes are considered bad? But you’re right about the single query. Also, as a possible solution for this kind of attacks, couldn’t you just use regexp to search for semicolons outside quotation marks in the sql? Or, for that matter, just escaping quotation marks and escape characters should be fine already.

    I also wonder, you allow for links in comments on this site, but do you take out a potential inline events such as onclick=”whatever()”, or the old href=”javascript:whatever()”?

  9. Jamie says:

    I think Magic Quotes was a good effort to prevent beginner programmers from making the mistake of not escaping input that would end up in a database query.

    Now, it can be annoying when you end up with slashes all over your incoming data, I agree. But I would rather it was escaping input by default, and it took effort to turn it off (only a couple lines of php). Rather than leaving input unescaped, and making it an effort to escape later (which we know many beginners do not do).

    Personally, I detect magic quotes at runtime, and if it is on, I reverse it’s escaping mechanism as I have a more elegant solution for my application. But I still see the value of having beginners given at least some basic protection against SQL injections.

    Now, in PHP6 Magic Quotes will be removed. This is because people should by then (beginners included) be using prepared statements, whereby individual input parameters are escaped as they are passed into an SQL query – so Magic Quotes becomes unnecessary.

    So I disagree Magic Quotes are a bad thing.

  10. Pingback: Elkinsware » New blog about different types of web attacks

  11. Pingback: ericsk’s blog » Blog Archive » XSRF Attack

  12. thesamet says:

    Hi Matthias, thanks for your comments! It makes sense that the bank will send the data in javascript and the client can plot a graph using this data (with FusionCharts perhaps). Even if it is done over https, the malicious site can use https as well and the user will not be warned.

    This site runs a standard installation of WordPress. AFAIK, it removes such things from the comments. (But I still can add malicious code to the posts :).

  13. Marc says:

    That said, if XML() is to be used, then it is suggested one check whether the string contains ” before actually sending it.

    Thats not enough. What about onload, onmouseover, … and href=”javascript:…” ?

  14. Ron says:

    Just a note, magic_quotes are off by default in PHP5 I think. I use them too and I actually find them helpful contrary to what other PHP programmers say.

  15. thesamet says:

    Thanks for pointing this out Marc! I’ve updated the post.

  16. Steve says:

    This is one of the better articles on online security. Beats those countless sql injection articles that are clearly geared towards newcomers

  17. Pingback: mcdave.net » links for 2007-02-03

  18. Pingback: Webmaster Libre » Archivo de » links for 2007-02-02

  19. Pingback: All in a days work…

  20. Pingback: Ajax Journal

  21. Pingback: Trafikant - develop success » Blog Archive » JavaScript Security

  22. Frank Nimphius says:

    Nice article. However your blog post is titled “Prepare for Attack!—Making Your Web Applications More Secure”. I don’t see your suggestions of how to prevent those attacks.

    Frank

  23. thesamet says:

    Hi Frank, Thanks for your comment. Prevention of SQL injection and XSS attacks is straight forward. Never assume that data comes from the web is safe. Even if you think no one will discover a URL which is hidden somehow in your javascript code. User input such as comments or posts should be stripped of all < symbols. And if it is used in SQL statements then it is best to use sql string escaping function like mysql_escape_string in PHP.

    XSRF attacks can be avoided by not giving sensitive data or allowing any action without making sure the user actually requested it. A prevention technique is described in the article.

  24. Pingback: Making your web applications more secure:

  25. Pingback: mhinze.com » Blog Archive » links for 2007-02-03

  26. Pingback: making services » Prepare for Attack!—Making Your Web Applications More Secure

  27. Pingback: Description of different types of web attacks

  28. Pingback: Max Kiesler - Designer » Blog Archive » Javascript and AJAX Security - How to Make Your Website Safe