Friday, June 22, 2012

With New Features Come New Vulnerabilites. The Web is Broken.

I spam in twitter and RSS.
HN discussi0n

Security Digest:
  • Rails coders, I remind you the very last time :) Run command Find ".to_json" agains your 'app/views' and please sanitize it, I stumble upon case 2 from my Rails & Security talk really often.
  • Use JSONP only with unique token per user. Don't give out private data via static URL.
  • It goes without saying but.. Seriously, Regexp /^ is not enough to mitigate CSRFs (Yeah, also if you are rubyist you should use \A instead of ^! Rails has reminder now Why? Because and both are legit domains too. Do add "\/" in the end of your Regexp. Anyway, don't rely on Referer.
  • X-Frame-Options (XFO) Detection from Javascript
  • I found out that 'autofocus onfocus=inject' is a really nice vector and works great. Thanks .mario's, some of cases over there are really worth getting addressed.
  • This is new section, please drop me a line if you have any epic thing about security :3
Current status:
On the left - Me, pointing various problems, starving to get feedback and proposing some fixing in a painless way.
On the right - browsers, ruby, community, whatever's response :)

Look, web security is all about philosophy and concept. Root of plenty of the problems is a poor problem solution/design or irresponsible adding of new features.

When browsers implement a new feature they should also care how it'll work along with existing websites, in terms of security too.

Cross POST obviously breaks Web.
I used words and actions to prove my point that POST CSRF is just a really poor part of Web  but barely got succeed. 
Yeah, I was always talking only about POST, CSRF GET is OK. Some guys answer "Browser should not handle requests, there is no difference between GET and POST or whatever for him". 

There is difference, they just work in the different ways and are supposed to do the different things. Dear browser, please care about that. 
This time (I hope last time because I'm tired to get back to the subject over and over) I quote wikipedia.
Per RFC 2616, the POST method should be used for any context in which a request is non-idempotent: that is, it causes a change in server state each time it is performed, such as submitting a comment to a blog post or voting in an online poll.
Site1 causes "a change in server state" on Site2. Read again, it's vanilla English: "such as submitting a comment to a blog post or voting in an online poll". It's clearly not supposed that Site1 will vote for you (hi putin).

How to explain an obvious thing? I'm exhausted. Just deny cross POST, make it Access-Control-Allow-Origin based (as well as XHR2 works), in addition developers should replace it with cross GET when possible (all analytics work that way). And it will be over. The worst web vulnerability (among "fixable" vulns, XSS and SQL inject are not fixable that easy) would be fixed instantly.

Frames and Clickjacking. In 2012?
Do you want to find pictures of you on the first page of some stupid magazine w/o your approval? I don't. Nobody does.

In the Internet it happens: Site1 includes Site2 or Site3 or them all in frames and this is an absolutely silly allowance in terms of security. Neither Site2 nor site3 want to be shown on Site1. They really don't want it BY DEFAULT obviously.

I know only one "good" usage of cross frames - google images. It loads page with original page in the background layer. Silly solution: the site thinks you are visiting it + it will not work with framekillers or X-Frame-Options + GET CSRF attack is possible not by purpose etc + you don't interact with the website anyhow = much better to use Screenshots instead of the 'trick'. 

Actually google already has screenshots of all pages - please, use them, OK? 

Clickjacking and cross framing (which is simply senseless 'feature') are getting worse:

sandbox attribute
This attribute turns JS in the frame off. Framekillers (only whitelist-based helps) just don't work. But without JS clickjacking is not working.
Wait! Most of Web2.0 websites use unobtrusive JS - even w/o JS they work well. So just provide sandbox='allow-forms' to make <form> submissions work and enjoy clickjacking!

This attribute aims to remove all borders - to make frame look as native as possible. It does a great favor for phishing websites. I have seen it in action (smth like used my profile picture) and this is wonderful - any square on any website can be embedded in your site. 
"seamless - making UI redressing clickjacking good looking since HTML5". WTF?

Below is seamless frame for with turned off JS. Frame looks pretty native and trustful.

Content Type sniffing Problem.
Don't you remember 'breaking news' a few years ago: "JSON Arrays leak!". I hope you do, read the post from John Resig if you don't. Now I wonder: Why they patched it by changing Javascript interpreter instead of fixing the real problem - browsers sniff content-type?

Web development is not for idiots. But why browsers assume that developer is lame idiot? Why browsers are trying to interpret text/html, text/plain, application/json, images and whatever

We set proper Content-Type to clearly tell you what kind of content is inside. And if this is application/json I think it is obviously not JS (application/javascript), isn't it?

Yet another security header has been introduced to "fix" this issue in IE - X-Content-Type-Options:nosniff which actually is useless and doesn't work in chrome. text/html is executed assuming it's JS. 

Proof of concept - some server responds with plain data (not in JSON/XML) thus it likely will not raise Syntax error. Google Wallet response is text/html 'OK' which is also valid JS. Login detection:
window.__defineGetter__('OK',function(){alert('you are logged in google wallet');})
document.write('<script src=""></script>')
Anti-XSS Protection or Yet Another Nice Tool for Defacing & Exploiting
Some info about X-XSS-Protection header.

X-XSS-Protection is intended to be a header to control XSS Auditor in Chrome and IE - it just checks does the response contain some param from request and if attack is detected all URLs are replaced with 'about:blank' and XSS <script></script> tags are removed.

Let's reverse it - you can easily get rid of ANY script/inline event(onclick,onmouseover)/link with 'javascript:' just passing a few lines of that code in request params. Browser thinks that XSS is happening and removes those "XSSed" parts, which are just native parts of the website.

We can easily run some page w/o jQuery library, without validators.js or onclick=prompt('are you sure?') simplifying clickjacking. It's up to you how to get profit from the 'feature'. 

Getting rid of Google Adsense:

I have fun sending this link —'hidden'%3B - to my friends and telling seems broken. May be you know why it turns into 'about:blank'? Here is why: google websites send X-XSS-Protection:1; mode=block which equals "Do not remove XSS, just show about:blank if attack is detected".

I also don't like framekillers. I got to switch JS off with 'sandbox'. But websites are often broken without JS... Solution!

Let's merely remove the annoying framekiller and leave JS alone! Showcase — mobile version of (russian facebook) —

<form method=post action="" target=ifr><textarea name="get_rid_of_framekiller"></textarea></form><iframe name=ifr></iframe>

Paste in textarea and submit. Enjoy clickjacking with working JS and blocked framekiller.
<script type="text/javascript">parent&&parent!==window&&(document.getElementsByTagName('body')[0].innerHTML='');

Bad user experience: Basic auth should be shown in a new window.
There was popular phishing through <img src=basicauth> a while ago. Now that's fixed in Chrome but it still works when you click any link.


  • Cross POST. Make it work as XHR2 POST works (Origin — based).
    Backwards incompatibility: Zero (there are no "good" websites relying on cross POST). But sadly I feel it will never be done.
  • Set default X-Frame-Options to SAMEORIGIN. Prevents ALL kinds of clickjacking/frame busters busting: UI redressing, transparent layer, drag and drop (direct and reversed), XSS exploit via frame src etc..
    Backwards incompatibility: Actions must be taken carefully - We should require all pages those want to be appeared to send X-Frame-Options: ALLOWALL and some day (probably in a year) deny cross frames if X-Frame-Options is not ALLOWALL. It must be addressed because of incredible prevalence of "vulnerable" sites. Very tiny percent of sites uses X-Frame-Options. The web will be saved and safer.
  • XSS Auditors are actually helpful — I have seen it 'in action' and was impressed! But it's also harmful for now. We need to make them better by making 2 simple things:
    1. default to '1; mode=block' instead of current 'mode=remove injected scripts'. I see no sense to show compromised page to user.
    2. we should warn users as we warn them about insecure SSL cert. Redirect to about:blank is bad user experience.
    Backwards incompatibility: Zero.
  • sandbox attribute. Why do we need it at all? It is useless but harmful. Site1 switches off JS for site2. Try to be in site2's shoes, it's like being naked :)
    Backwards incompatibility: approx. Zero. It's HTML5 attribute, not implemented everywhere thus not used.
  • browsers should be more strict with Content-Type. HTML and JSON Hashes raise syntax error when included in <script>. But who knows what doesn't raise and which data can leak in the future?
    Backwards incompatibility: Low
Finally — we see 'Security is optional' attitude too often. 

Don't forget to set X-Frame-Options='SAMEORIGIN', X-Content-Type-Options='nosniff' and also X-XSS-Protection='1;mode=block' which actually must be default for 99% of sites. 
Don't forget to prevent cross POST verifying tokens, make sure all your links point to target=_blank. 
Remove framekillers — they are broken and useless now. 

It seems browsers don't want to do this for us. Let's ask them?

Any feedback is welcome (grammar related either), we must leave SaferWeb for our kids and for this kitten's sake.


  1. I told that he must write:


    but he answered "Im too busy, bro. Needto feed my bear with vodka"

  2. @anon
    I feed beer with vodka. Cocktail beer+vodka=ERSH

  3. Миру станет лучше, если это же самое появится на хорошей security-конференции в еще более обобщенной форме.

  4. X-Frame-Options='SAMEORIGIN' ? Its better to use DENY than SAMEORIGIN, unless otherwise explicitly needed.

  5. @i Sciurus hmm I hardly can visit some conf right away

    @Nafeez: yes, to SAMEORIGIN. DENY will definitely BREAK lots of frame-based websites. But SAMEORIGIN is perfect option

  6. @Egor: What do you think about this?

  7. @Nafeez I don't think it's an issue. never seen it in real life