krakenjs / lusca

Application security for express apps.
Other
1.79k stars 123 forks source link

Support XSRF-TOKEN for AngularJS #27

Open aozora opened 10 years ago

aozora commented 10 years ago

See Angular docs at the paragraph "Cross Site Request Forgery (XSRF) Protection" https://docs.angularjs.org/api/ng/service/$http

ubald commented 10 years ago

I'd suggest at least to give us an option to provide our own method for fetching the token from the request instead of the body-only way it is done.

token = req.body[key];

By letting us use a custom function there (like it is done with impl.validate()) we could get the key from a cookie or header or whatever.

jeffharrell commented 10 years ago

It could be documented better, but why won't the custom token implementation method work for this? https://github.com/krakenjs/lusca/blob/master/test/csrf.js#L93

Edit: You have direct access to the request from that function https://github.com/krakenjs/lusca/blob/master/test/mocks/token.js#L12

pdapel commented 10 years ago

Hi folks. I'm trying to getting Angular and Lusca to play nicely with CSRF, but Lusca (csrf.js) is seeing undefined values for the key and the token when it receives the POST, and I see nothing related to csrf or xsrf in the req.body or req.headers. Would you mind pointing out what I'm doing wrong, so that I correctly set and get the header and cookie? Here's what I've got currently configured:

in my angular app:

    $httpProvider.defaults.xsrfHeaderName = '_csrf';
    $httpProvider.defaults.xsrfCookieName = 'x-xsrf-token';

and in my node:

   app.use(lusca({
        csrf: {key: "x-xsrf-token", header: "_csrf"},
        xframe: "SAMEORIGIN",
        csp: false,
        p3p: false,
        hsts: false,
        xssProtection: true
    }));

Much appreciated!

aredridel commented 10 years ago

@pdapel It looks like you've swapped key and header in the config there.

totherik commented 10 years ago

From the angular docs:

"To take advantage of this, your server needs to set a token in a JavaScript readable session cookie called XSRF-TOKEN on the first HTTP GET request."

This functionality isn't provided by lusca at this time.

mzarella commented 9 years ago

@totherik Is there a way to use lusca and support Angular, and if so how?

totherik commented 9 years ago

Hey @mzarella. AFAIK, nothing has changed in lusca to support sending the token as a cookie. (However, there's nothing preventing you from doing this in your app.) HTTP header support was added and we're always open to PRs if you have a proposal. Also, @jasisk may already have something in mind, so I'll let him comment.

jasisk commented 9 years ago

@eriktoth is correct. The best way is to either configure lusca to use the X-XSRF-TOKEN header, or Angular to use the x-csrf-token header and write a tiny middleware (with a later priority than lusca which is 110 by default) to set the generated token as a cookie value (with something like: res.cookie('XSRF-TOKEN', res.locals._csrf);).

mzarella commented 9 years ago

Thanks @totherik and @jasisk

anjali-chadha commented 9 years ago

@pdapel Did you get it working or can you suggest some module that works with angular?

aredridel commented 9 years ago

@gracehopper17 Did you try adding res.cookie('XSRF-TOKEN', res.locals._csrf); as a middleware after lusca?

anjali-chadha commented 9 years ago

@aredridel Hi Aria, res.locals._csrf is coming as undefined for me. Can you please take a minute to explain how to set this value.

aredridel commented 9 years ago

Sure. Will reply in #54

jadeye commented 8 years ago

I am using lusca with express-session, I have on server side:

var opts = { csrf: { angular: true } };
server.use(lusca({
  csrf: {key: "_csrf", header: "x-xsrf-token"},
  xframe: "SAMEORIGIN",
  csp: false,
  p3p: false,
  hsts: false,
  xssProtection: true,
  nosniff: true
}));

On angular side

  .config(['$httpProvider', function($httpProvider) {
            $httpProvider.defaults.xsrfCookieName = "_csrf";
            $httpProvider.defaults.xsrfHeaderName = 'X-CSRF-TOKEN';

Read here on issues and alot on the web, still can't wrap my head around how to get token to jade views...

on server side I also have req.path filter so:

server.use((req, res, next) => {
  if ((req.path === '/api/upload') || (/^\/store/.test(req.originalUrl))) {
    next();
  } else {
    lusca.csrf()(req, res, next);
  }
});

store pages are the ones I need to persist token!

And on jade template I have the following tag: input(type='hidden', name='_csrf', value=_csrf)

Tokens are coming in but they keep on changing with every page load. Is that normal behavior for this scenario? If not, what am I doing wrong/ what should I change?? (I am aware that some parts don't belong...)

PhilippeCorreges commented 8 years ago

Hi, This can solved server side by : app.use(lusca({ csrf: { angular: true }, csp: { policy: { 'default-src': '\'self\'', 'img-src': '', 'style-src': '' }}, xframe: 'SAMEORIGIN', p3p: 'ABCDEF', hsts: {maxAge: 31536000, includeSubDomains: true, preload: true}, xssProtection: true, nosniff: true }));

Token are finely 'cookised'

Cheers

jadeye commented 8 years ago

@PhilippeCorreges , thanx...but isn't that the same as:

var opts = { csrf: { angular: true } };
server.use(lusca(opts));

I have both on my server.js but still can't access the token/cookie... Maybe I am accessing them wrongly?? Say you have the two lines of code above (if they do the job...), How would you access the token/cookie from angular? controller? app config?? Thanx again

PhilippeCorreges commented 8 years ago

Yes this is the same. On my side I simply suppressed those lines (setting csrf to false) as they are not relevant for jwt.