Saturday, February 23, 2013

Pagebox — sandboxing XSS attacks.

View FAQ and proof of concept (Sinatra app) on Github  Here I explain the idea and problems I stumbled upon.

Demo online

XHR
Pagebox is a technique for building bullet-proof web apps, which can dramatically improve XSS protection for complex and multi-layer websites with huge attack surface.
Web is not super robust (Cookies, Clickjacking, Frame navigation, CSRF etc) but XSS is an Achilles' heel, it is a shellcode for the entire domain.

If we prove /some_path to be vulnerable to XSS, we can interact with the whole website. This might lead to bad things happening — for example, malicious XSS on /some_path may attempt to, damn it, /withdraw our money. Pagebox presents the solution to this problem.

Sandboxed pages

The idea I want to implement is to make every page independent and secure from other vulnerable pages located on the same domain.

Developers can limit interactions of this particular page with others—by either blacklisting things that clearly shouldn't be done, or by taking a more restrictive approach and whitelisting only allowed things.

frames
Pagebox splits the entire website into many sandboxed pages with unique origins. Every page is not accessible from other pages unless developer allowed it explicitly - you simply cannot window.open/<iframe> other pages on the same domain and extract document.body.innerHTML because of the CSP header: Sandbox.
frames
Every page contains a signed serialized object in <meta> tag, and sends it along with every XMLHttpRequest and <form> submission. Meta tag contains signed information about what was permitted for this URL.
Boxed pages are assigned their pagebox scope, which either limits or allows only particular kinds of request (suppose you're viewing the messages page, you only have the :messages scope, which indicates only message query/creation is allowed; attempt to access any other part would be denied.) Backend checks if the permissions were tampered, if they're good and the action is allowed, it processes the request. To some extent, it's Cross Page Request Forgery protection.

Pagebox can look like: ["follow", "write_message", "read_messages", "edit_account", "delete_account"]. Or it can be more high-level: ["default", "basic", "edit", "show_secret"]
permitted URLs

Problems

Now page can only submit forms, but XHR CORS doesn't work properly - nobody knew we will try it in such way. I'm stuck with XHR-with-credentials and I need your help and ideas.
1) Every page is sandboxed and we cannot put 'allow-same-origin' to avoid DOM interactions
2) When we sandbox a page it gets a unique origin 'null', when we make requests from 'null' we cannot attach credentials (Cookies), because wildcard ('*') is not allowed in Access-Control-Allow-Origin: * for with-credentials requests.
when responding to a credentialed request,  server must specify a domain, and cannot use wild carding.
3) Neither * nor null are allowed for Access-Control-Allow-Origin. So XHR is not possible with Cookies from sandboxed pages.
4) I was trying to use not sandboxed /pageboxproxy iframe, which would do the trick from not sandboxed page and return result back with postMessage, but when we frame not sandboxed page under sandboxed it doesn't work either.
I don't know how to fix it but I really want to make pagebox technique work. It fixes the Internet.

Feel free to troll ask me questions in comments or at homakov@gmail.com - I'm happy to help! Please share your ideas how to make it real.

12 comments:

  1. You are just talking about app isolation. :)
    But playing with a single sinatra app/domain etc.

    ReplyDelete
    Replies
    1. not app isolation, page isolation. I have one domain and many pages

      Delete
  2. It seems to be a fine idea, but practically it's difficult to do. Programmer is prone to do a lot more errors. Legitimate requests might get denied because of misconfiguration on programmer's carelessness. It will be quite annoying to develop. It's not page by page development in today world, some folks is happy enough with single page application architecture. I am not sure this will fit.

    I step up we all can do is to banish Cookie. XSS as what you said is still the Achilles' heel and hell you got to handle it nicely. Sanitize all your string outputs that has user inputs component. There is no other way.

    XSS is still the second most malicious threat. It still requires a lot of efforts from attacker to understand your application architecture. The scariest of all, which getting more and more common is man in the middle attack. With that, attacker could steal your session, cookie, credential etc. Even when you use SSL, some still tried try the work around using SSL stripping. Heard of china try to block github by circumventing with fake ssl certificate? or Nokia browser that acts as proxy for your secure page, and so on and on.

    Bottom line, be your own gatekeeper. With cookie, you surrender all your rights to the browser in handling your users' credentials. In most case browser heck care about to who should the cookie get passed on, in fact it's all entrance pass scenario.



    ReplyDelete
    Replies
    1. Of course you should care about escaping and input params.
      BUt if you really really care about some particular parts of websites - you can pagebox them.
      When we polish this technique it will not be headache for programmers as well.
      demo
      http://pagebox.herokuapp.com/

      Delete
  3. You might want to have a look at https://github.com/aenario/cozy-security-model.

    basically you'll need two domains (let's say www.website.com and pages.website.com).

    www.website.com is where your login and cookies happens.
    www.website.com also serves wrapper pages which include the actual pages (served by pages.website.com) in an iframe (sandbox="allow scripts allow same origin") and give each page its appropriate token.

    Server-side you need to check for each request if the page that makes the call is allowed to access whatever is it trying to access.

    ReplyDelete
    Replies
    1. good but still not what i need.
      i don't need domains, in eed normal full featured website.
      with permission check for pages.
      subdomains are ugly

      Delete
    2. Yes, the point with this solution is that you need only two domains. One is visible to the user (www.yoursite.com), the other is only shown in iframes (anything-the-user-wont-see-anyway.yoursite.com)

      Delete
    3. ah, i missed 'iframe' part a bit sorry.
      so, only www. domain will be shown in URL.
      and i guess we need more than 2 subdomains. e.g. payments., manageaccount., and other scopes.

      how do you insert iframes to make them "seamless" is there demo?

      Delete
    4. No demo yet, still working on it.

      All pages except for the auth system can be served under the same domain (let's say pages.website.com). They received their token from the parent window (served from www.website.com). Theses tokens depends on the scope, but can virtually be one for every page. Pages access user informations through a postmessage API with their parent window.

      It's the backend responsability to validate the token against the query.

      iframe are virtually seamless if they have the same styles than parent window and border: 0.

      Delete
    5. I think frame-token is very hard way.
      1) links must have target=_top
      2) SEO
      etc
      i wanted to make demo for rails where user is simply redirected to subdomain as sson as opens new scope

      Delete
  4. You can include a signed token with your CORS requests, echo-ing the Origin back from the server but performing validation based on the token only.

    ReplyDelete
    Replies
    1. do you mean rely on signed token, not cookie? not acceptable - I can't make it httpOnly.
      so i need cookies to be used. But i cant send cookies from null origin.

      Delete