Saturday, May 4, 2013

Do not use RJS-like techniques

RJS (Ruby JavaScript) — a straightforward technique when server side (e.g. Rails app) responds with Javascript code and client-side eval-s it (Writing JS in Ruby is unrelated, I only consider response-evaling concept!)

Here are my usability and security concerns about this interaction.

Possibly other developers use their own RJS-like techniques — they can find my post helpful too.
(c) from http://slash7.com/assets/2006/10/8/RJS-Demistified_Amy-Hoy-slash7_1.pdf
  1. Broken concept & architecture. This feels as weird as the client-side sending code that is going to be evaled on the server-side... wait... Rails programmers had similar thing for a while :/
    Any RCEJS technique can be painlessly split into client's listeners and server's data.
  2. Escaping user content and putting it into Javascript can be more painful and having more pitfalls then normal HTML escaping. Even :javascript section used to be vulnerable in HAML (</script> breaks .to_json in Rails < 4). There can be more special characters and XSS you should care about.
  3. JSONP-like data leaking. If app accepts GET request and responds with Javascript containing private data in it attacker can use fake JS functions to leak data from the response. For example response is:

    Page.updateData("data")

    and attacker crafts such page:

    <script>var Page={updateData:function(leak){ ... }}</script>
    <script src="http://TARGET/get_data.js?params"></script>

    Voila, joys of RJS
  4. UPD as pointed out on HN evaling response will mess with your global namespace and there is no way to jump into closure you created request in..
Original RJS (Ruby-generates-JS) was removed by Yahuda Katz 6 years ago, he gave me this link with more details.

But I still see in the wild apps responding with private data in javascript. This is a very fragile technique, refactoring will both improve code quality and secureness of your app.

P.S. Cool, GH uses cutting edge HTML 5 security and added CSP headers. My thoughts:

  • Rails 4 has built-in default_headers (guess who added it?), which has better performance than before filter
  • current CSP is easily bypassed with JSONP trick, just write in console on github.com:
    document.write('<script src="https://github.com/rails.json?callback=alert(0)//"></script>')
    i will fix it when get spare time, btw: https://github.com/rails/rails/pull/9075
  • CSP is very far from ultimate XSS prevention. Really very far, especially for Rails's agileness and jquery_ujs. Github should consider privileged subdomains https://github.com/populr/subdomainbox 

5 comments:

  1. I think RJS is great for prototyping but I wouldn't use it for production.

    ReplyDelete
  2. Hi.

    First of all thanks for sharing your findings!

    I don't get how your pull-request for Rails fixes the problem. I understand that is checks that the callback is present but the attacking side can provide a valid callback and still attack.

    For example if the affected site sends javascript statements that update the page, such as creates a form, then all you have to do is provide your Element.update or whatever JS framework the site uses.

    Please, correct me, if I am missing something.

    ReplyDelete
    Replies
    1. which pull request? don't know what you're talking about

      Delete
    2. I thought this one: https://github.com/rails/rails/pull/9075
      But I probably misunderstood what you wrote.

      Delete
    3. this PR is completely unrelevant, it's to filter JSONP more strictly.

      Delete