't Bijstere spoor

't Bijstere spoor

A blog about Web development

Frame busting and clickjacking prevention

Clickjacking allows an attacker to trick your users into clicking parts of your interface without their consent. A simple way to describe describe this is, an attacker will embed your application in their site as an iframe. On top of the iframe they can show a completely different interface. You're thinking you're clicking buttons on your own interface, while in fact you are hitting the 'Delete my account' button in for example GMail.

Because this technique completely operates with frames, it can be circumvented by using a 'Frame busting' technique. As a bonus, this will also disallow for example Digg to steal and monetize your content.

Frame busting can be achieved with a simple javascript technique:

<script type="text/javascript">
if (top !== self) top.location.replace(self.location.href);
</script>

Security through javascript?

If you think this sounds like a bad idea, you are probably right. Users might simply have javascript disabled, and I also don't like relying on UI developers too much to implement preventive security measures (although I realize in most cases you do have to).

In Internet Explorer the situation is worse, IE allows you to specify the non-standard attribute security="restricted":

<iframe src="http://www.rooftopsolutions.nl/ security="restricted"></iframe>

This attribute tells IE to not allow executing of javascript in the iframe, which actually is not a bad security measure for other types of attacks. In this case however, it allows the attacker to disable the framebusting script.

X-Frame-Options

Thankfully, Internet Explorer 8 introduces a new feature that allows the site owner to disallow frames altogether, which is in my opinion an even better protection mechanism, because it doesn't rely on javascript to be executed.

The name of the http header is specified as such:

X-FRAME-OPTIONS: SAMEORIGIN
X-FRAME-OPTIONS: DENY

You only have to specify one of these two, 'sameorigin' means the page can only be framed from an html page hosted on the same domain, deny will kill framing altogether.

PHP example:

<?php
header
('X-FRAME-OPTIONS: DENY');
?>

Firefox also appears to have started implementing this feature, and there's a feature request for webkit open as well.

Protecting yourself

Unfortunately you can safely assume most sites don't implement either of these security measures. For firefox users I would therefore strongly recommend using the NoScript plugin. Not only does it implement the X-FRAME-OPTIONS for firefox, it also actively detects clickjacking attempts.

Reference: hackademix.net


Preventing XSS in Javascript strings

Escaping user-input in your HTML is essential for preventing worlds #1 vulnerability.

When you're embedding user input into javascript, a simple htmlspecialchars won't cut it, you'll need to make sure you're escaping other things, like \n (line endings), and \ (slashes). Google doctype has a good list of characters in need of proper escaping to prevent users breaking your javascript.

However, when I dropped the question if a simple string replacement would be good enough, the members of the Web security mailing list gave me a different answer.

When escaping or filtering output using a blacklist (such as the one published on google doctype) browser/unicode escaping bugs are not taking into consideration. Some new vulnerability might appear in the future, which would immediately open a hole in your app. For this reason its wiser to go with a much more defensive white-list approach, essentially only letting things through you know is safe.

Introducing Reform

Reform is a tool that does exactly this. Reform allows you to escape your data for a javascript, xml, html or vbscript (yes it still exists) context. It provides libraries for Java, .NET, PHP, Perl, Python, Javascript and ASP. Pretty cool!

One dislike I have is that it only considers I really small set of unicode codepoints safe, especially when dealing with non-latin languages this is going to add a great deal to the bandwidth usage and the legibility of your sourcecode. One would think there has to be more ranges considered 'safe'.

PHP example:

<?php
  
// Assuming the Reform class is included..

  
echo '<script type="text/javascript"> var myString = 'Reform::JsString($userInput), '; </script>';

?>

I made a couple of changes in the PHP version, specifically:

  • Prepended the 'static' keyword to every method to make it work in PHP5's strict mode.
  • Removed the UTF-8 checks, I'm in a controlled environment, mbstring is installed, and the internal encoding is utf-8.
  • Added a parameter to Reform::JsString to not automatically put the string between quotes (').

IE8 comprehensive protection

Today on the IE blog a big announcement was made regarding the upcoming security features in Internet Explorer 8.

Definitely check it out! Among things it includes an XSS protection filter, HTML sanitizing built straight into the scripting engine and a way to disable the infamous 'content sniffing'. I'd still hope to see the content-sniffing 'feature' to be opt-in, instead of the proposed opt-out solution.. but hey, at least it allows us to plug the hole.

To serve files as text/plain, serve the document with the Content-Type header as:

Content-Type: text/plain; authoritative=true;

I have to say, I'm quite impressed how IE is catching up with things like standards and security.


Site Security Policy

Via: Jeremiah Grossman.

A proposal for a Site Security Policy has been proposed by mozilla employee Brandon Sterne. This is an extremely important specification for the web, and could be a big step ahead for security on the web.

<rant>

Over the last decade websites have transformed into feature-rich web applications, with the introduction of Javascript and XMLHTTPRequest, Flash and whatnot. While great for user experience, this has also brought huge security implications, resulting in over 80% of all documented security vulnerabilities in 2007 being carried out using XSS.

While implementing all this new fancy stuff, browser vendors have been slacking thinking about the security implications and essentially the responsibility of safe browsing has been put on the user. (Remember the 90's advice of disabling cookies while browsing?). Browsers have become better over time, but one single XSS hole on any site can still have devastating effects for you and your users.

With the demand for web development and web developers still way higher than the supply, education is in a sorry state too. In job interviews I've conducted it's been rare to find a junior who knows of the concept XSS, and finding one who can explain the implications of CSRF, is, well, I've yet to meet one. I don't claim to be a security expert myself, but I feel everybody who's in the profession of web development, should at least be aware of the basic attack vectors and how to prevent them.

“If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization.”

- Weinberg’s Second Law

</rant>

With the Site Security Policy we're given the ability to lock down certain types of behaviours. It allows us to disable javascript included from unknown domains (a whitelist approach), and HTTP requests initiated by external domains, essentially fixing the CSRF problem completely. Additionally, it defines a way for a browser to log attempts to violate the policy.

For the actual implementation details, I'd suggest just reading the spec, even though its still a proposal, it's good reading material.

So whats next?

The spec needs to be finished. While the current policy is distributed through HTTP headers, some people seem to prefer an external file, like how crossdomain.xml or robots.txt is implemented. The latter would have my vote, because the policy can then be easily cached, which can save some bytes in the end. It would also be easier for people to upload a policy file to a server where there's no scripting available and allows the policy to be enforced for a complete domain, instead having to add it to each and every script.

And last but not least, browser vendors would need to implement it. Sterne works at Mozilla, so that's a good sign already. Personally, I can't wait.


Getting around "su : must be run from a terminal"

I killed the sshd daemon from one of our servers by accident today. I wanted to avoid going to the data center, so I was able to upload and run a PHP script to give me a shell..

Problem was, that it would run under the www-data user and trying to su to root gave me the following message:

su : must be run from a terminal

After some googling, I found the solution from Tero's glob. If you have python installed, just run the following from your shell:

echo "import pty; pty.spawn('/bin/bash')" > /tmp/asdf.py
python /tmp/asdf.py

You now have a proper terminal, and things like 'su' will work as usual.


HTML Purifier rocks!

HTML purifier

I had to create an RSS aggregator for my job, and I had to find (or create) a good tool that sanitizes the HTML that comes in. I stumbled upon HTML purifier, and I haven't seen a better tool for the job yet.

Some of the features:

  • It can turn the html into valid XHTML (transitional or string)
  • So it also balances tags out..
  • Removes any code that could expose a security risk. (tested with RSnakes XSS cheatcheat).
  • Allows you to truncate HTML (if you don't want to show an entire post) and still results in proper HTML!

So yea, if you need something similar; I'd suggest you check it out..


Firefox gets httpOnly cookies

httpOnly cookies allow you to hide your (session-)cookies from javascript. In the case of an XSS hole in your application, it will make a hackers life much harder to steal someones session.

Internet Explorer support httpOnly cookies for a long time, but since version 2.0.0.5 Firefox also supports this feature. Apparently Mozilla hasn't openly promoted this new feature yet, because its still possible to fetch the cookies with XMLHttpRequest. PHP has support for httpOnly cookies and sessions since 5.2.


On HttpOnly, Firefox-specific XSS and this years major Livejournal XSS attack

Yep, thats a long title, but they are all related to each other in some way. In the first few paragraphs I will explain what cookies are and XSS. You might want to skip ahead if you already know what this is.

Sessions, Cookies

HTTP is stateless. This means that every request to the server is a 'new' one and normally there is no relation to a first or second request. To allow maintaining a session or 'state' between multiple requests, HTTP cookies are used.

A cookie is basically a HTTP header with a tiny piece of information that gets re-sent with every request to the server. A popular way to make use of this is through PHP's$_SESSION system. This sends a cookie with a unique id to the client that allows PHP to retain a users' information across pages.

XSS

If you allow users to for example comment on one of your pages and allow (certain) html, it is sometimes possible to inject a piece of javascript. There are many tricks to evade the so-called html sanitizers.. strip_tags() is PHP's built-in sanitizer, but it doesn't work really well.. if, for example, you would allow users to use a <p> tag, which might seem harmless, there would be tricks to abuse the style="" or onclick="" attributes, just to name a few.

XSS and cookies

So how do you abuse javascript and cookies combined?

Because with for example PHP's session system, you can use the contents of the cookie to steal someone's session. The hacker would be logged in as you and might able to change your password and log you out afterwards. The contents of the cookies is stored in the javascript variable document.cookie.

HttpOnly, a solution

Microsoft came up with a way to prevent this from happening, ever since Internet Explorer 6.0 (starting from Windows XP SP1). They added an extra piece of information to a cookie, that will still allow the use of cookies in the way you are used to, but it will prevent the cookie from being read by javascript (basically it is invisible for javascript). Be sure to check out microsofts spec at MSDN

Safari and Opera quickly started supporting this. Because of this it is becoming pretty useful to use in practice. Remember that this doesn't mean you can just accept any html on your site, you should still always sanitize the bad stuff or not allow it at all! But in the case you missed something, it can make it a lot more difficult for your attacker to steal sessions.

UPDATE: Safari/Opera actually ignore it, my excuses, I didn't check my sources.

Under the hood

Normally, a cookie header will look like this:

Set-Cookie: USER=username; expires=Wednesday, 09-Nov-99 23:12:40 GMT;

But with the HttpOnly, it will look like this:

Set-Cookie: USER=username; expires=Wednesday, 09-Nov-99 23:12:40 GMT; HttpOnly .

It's a small change, and all normal browsers should still accept this even if they don't understand the HttpOnly part. There is an exception though, and it goes by the name of IE 5 for mac. This browser won't understand the cookie and totally ignores it. Personally I don't support this browser for any application anymore, as there are too many bugs in this browser. But if your boss wants it, this might prevent you from using HttpOnly

PHP support

A guy named Scott MacVicar created a patch for PHP that will add an extra parameter to set_cookie() to enable HttpOnly for your cookies. The patch should also enable this by default for the session system.

If the patch will get accepted we will likely be able to use this in PHP 6.0 and perhaps even PHP 5.2, I'm looking forward to that. There is a chance though, because of the IE5/mac breakage that it eventually won't be auto-enabled for the session system.

So what about firefox?

Firefox doesn't support it, there is currently a bug open for it (Bug #178993). There was an initial solution posted over 2 years ago (January 2004). And a few other patches later on, but the mozilla folks refused all of them because they want to maintain the exact format of cookies.txt (the file they use to store cookies), because other applications might rely on that format. A few solutions for that have been posted, but it doesn't seem like a high priority for them.

A workaround for firefox (kind of)

There have been solutions for firefox that also blocked reading of cookies by javascript. Firefox has a magic function __defineGetter__ that can block reading of variables. To do this for all cookies on your site, include the following snippet on top of your html page:

HTMLDocument.prototype.__defineGetter__("cookie",function (){return null;});

However, you can't rely on this! There are still ways to get this cookie if the hacker can somehow create an iframe in your html page. The hacker has a reference to the same cookies if he uses the data: protocol in the src="" attribute. This will still make it a bit harder to steal cookies, so it's not a bad idea to implement. For a longer explanation of this workaround, check out http://www.wisec.it/sectou.php?lang=en.

The LiveJournal case

The same people who submitted the initial firefox-patch (see above) 2 years ago, also got hit by the attack in January 2006. Over 46% accounts were hijacked. This were over 900.000 stolen accounts. (check out their post about their solution.)

The reason they got hit by this is because they allowed users to use remote CSS stylesheets for their pages. CSS used to be only a specification for how html elements would look like on a page, but since a few years it has become more dynamic and now there are ways to exploit CSS with XSS attacks through for example IE's non-standard behavior: attribute and Firefox' -moz-binding: attribute (there are more you can exploit, but its outside the scope of the article). These attributes allow an author to create a custom behavior for a HTML element. The technique to do this for Firefox is called XBL.

Normally, when a page is loaded from domain A, and another (in a different frame for example) is loaded from domain B. Malicious scripts from domain B can never access cookies from domain A. This is called a 'same origin check'. This generally works in all browsers for all kinds of content, but an exception is XBL. (see bug #324253.)

Apparently this requires some major changes in how firefox works. The last comment in this bug is from February this year (2006). I hope they will wake up some day soon and make our life a little bit easier by both supporting HttpOnly and securing XBL.

So the LiveJournal attack could happen because the hackers used XBL in their CSS, which in turn accessed the HTTP cookies through javascript. The attack didn't affect users of other browsers, because: A) they support HttpOnly, B) even if they wouldn't.. the microsoft equivalent of XBL, which is .HTC files, don't work across different domains.