English 中文(简体)
How to implement CSRF protection in Ajax calls using express.js (looking for complete example)?
原标题:

I am trying to implement CSRF protection in an app built using node.js using the express.js framework. The app makes abundant use of Ajax post calls to the server. I understand that the connect framework provides CSRF middleware, but I am not sure how to implement it in the scope of client-side Ajax post requests.

There are bits and pieces about this in other Questions posted here in stackoverflow, but I have yet to find a reasonably complete example of how to implement it from both the client and server sides.

Does anyone have a working example they care to share on how to implement this? Most of the examples I have seen, assume you are rendering the form on the server-side and then sending it (along with the embedded csrf_token form field) to the client-side. In my app, all content is rendered on the client-side (including templates) via Backbone.js. All the server does is provide values in JSON format, which are utilized by various Models in Backbone.js on the client-side. By my understanding I would need to retrieve the csrf_token via ajax first before it can be used. However, I am concerned this may be problematic from a security standpoint. Is this a valid concern?

问题回答

It can be done by adding meta tag for CSRF token and then pass CSRF token with every Ajax request

Server

Add CSRF middleware

app.use(express.csrf());
app.use(function (req, res, next) {
  res.locals.token = req.session._csrf;
  next();
});

You can pass a CSRF token to the client side via, say, a meta tag. For ex, in Jade

meta(name="csrf-token", content="#{token}")

Client

jQuery has a feature called ajaxPrefilter, which lets you provide a callback to be invoked every Ajax request. Then set a header using ajaxPrefilter.

var CSRF_HEADER =  X-CSRF-Token ;

var setCSRFToken = function (securityToken) {
  jQuery.ajaxPrefilter(function (options, _, xhr) {
    if (!xhr.crossDomain) {
      xhr.setRequestHeader(CSRF_HEADER, securityToken);
    }
  });
};

setCSRFToken($( meta[name="csrf-token"] ).attr( content ));

server.js

...
// All Cookies/Sessions/BodyParser go first
app.use(express.csrf());
...
// Get the request
app.post( /ajax , function(req, res){
    res.render( somelayout , {csrf_token: req.session._csrf});
});

In somelayout.jade

input(type= hidden , name= _csrf , value=csrf_token)

The CSRF middleware only generates the csrf token once per session, so it will probably not change for the duration of a user s visit.

Also, it doesn t check for the token on GET and HEAD requests. As long as the token is in the request (header, body, or query), you re good. That s pretty much all there is to it.

Since you are using Backbone.js for your application, I am assuming that it is a SPA and you initially load an index.html file, then make any other requests are made via ajax calls. If so, you can add a small snippet of JS code to your index.html file to hold the crsf token for any future ajax calls.

For example:

index.html (using Handlebars for templating...)

<!DOCTYPE html>
<html>
    <head>
        ...
        <script type="text/javascript">
            $( function() {
                window.Backbone.csrf = "{{csrfToken}}";
            });
        </script>
    </head>
    <body>
        ...
    </body>
</html>

When you render the index.html file, give it the csrf token that the express framework generated here: req.session._csrf

When you use Backbone.js, it sets a global variable called Backbone. All that the previous function is doing is seting a property called csrf to the global Backbone object. And when you make an ajax call to POST data, simply add the Backbone.csrf variable to the data as _csrf that is being sent via the ajax call.

In Server:

app.use(function (req, res) {
  res.locals._csrf = req.csrfToken();
  res.locals.csrf_form_html =  <input type="hidden" name="_csrf" value="  + req.csrfToken() +  " > ;
  req.next();
});

In Client: (swig template)

var csrf = {{ _csrf|json|safe }};

$.ajaxSetup({
  headers: {
     X-CSRF-Token : csrf
  }
});

$.post("/create", data, function(result) {
  console.log(result);
}).fail(function(){
  console.log(arguments);
});

1. Add csrf protection middleware:

app.use(csrf({cookie: true}));

// csrf middleware
app.use(function (req, res, next) {
   res.cookie( X-CSRF-Token , req.csrfToken());
   // this line below is for using csrfToken value in normal forms (as a hidden input)
   res.locals.csrfToken = req.csrfToken(); 
   next();
});

// routing setup goes here

2. Add a beforeSend callback using $.ajaxSetup: (add this somewhere before all your ajax calls)

$.ajaxSetup({
beforeSend: function (xhr, settings) {
    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie !=   ) {
            var cookies = document.cookie.split( ; );
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name +  = )) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }

    if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
        // Only send the token to relative URLs i.e. locally.
        xhr.setRequestHeader("X-CSRF-Token", getCookie( X-CSRF-Token ));
    }
}
});

3. That s it! now you can send ajax requests and you don t need to add anything in headers or as a request parameter to pass through csrf.





相关问题
ajax login using httpRequest?

I am trying to develop my login script to give feedback to the user if the login is valid or not. Basically if it isn t correct a div box will show saying its wrong, if its correct it will show its ...

Virtual Tour using sketch up, ajax, flash technologies

I want to know if there are existing technology that make your 3d models in sketch into virtual tours, using either Ajax or Flash for web presentation. If there s none, which will be a good approach ...

How can i update div continuously

I have asp.net application where i have a div which showing the value from other site. The value of that site is changing continuously. I want that my div will automatically update in some interval ...

热门标签