Code Monkey home page Code Monkey logo

jwt-csrf's Introduction

jwt-csrf

CSRF protection using the power of JWTs. Provides a number of stateless methods of csrf protection, if you don't want to keep a session.

Defaults to the double submit method of csrf protection, but supports a number of different strategies.

Middleware

Example

var express = require('express');
var app = express();

var jwtCSRF = require('jwt-csrf');
var jwtMiddleware = jwtCSRF.middleware(options); // This can be used like any other Express middleware

app.use(jwtMiddleware); // Executed on all requests

The middleware must be included before others to be effective.

Handling errors

On errors, jwt-csrf will call next(err) with a jwtCSRF.CSRFError. If you want to handle this specifically, you can do so in a middleware:

function(err, req, res, next) {
    if (err instanceof jwtCSRF.CSRFError) {
        explode();
    }
}

Options

options is an Object with the following format:

  • secret : String (Required) - Your application's secret, must be cryptographically complex.
  • csrfDriver : String (Optional) - CSRF driver/strategy to use. Defaults to DOUBLE_SUBMIT.
  • expiresInMinutes : Number (Optional) - A token's expiration time. Defaults to 60.
  • headerName : String (Optional) - The name of the response header that will contain the csrf token. Defaults to x-csrf-jwt.
  • excludeUrls : Array (Optional) - An array of elements that can be comprised of any of the following
  • A regular expression object. The request url will be compared using RegExp.test() using the regular expression supplied here
  • A two element array with the first being a string based regular expression and the second being the regular expression options such as "i" or "g". A regular expression will be created and tested against the request url. This is the ideal way to create a regular expression if the excludUrls are defined in a JSON file.
  • A string. This string will be tested as a regular expression with no regexp options. If this doesn't match the request.originalUrl, then it will be tested against the url as a direct string match.
  • getUserToken : Function (Optional) - Get a user specific token for the AUTHED_TOKEN and AUTHED_DOUBLE_SUBMIT strategies. Must accept req and return a user-specific token (like a user id) for a known user.
  • getCookieDomain : Function (Optional) - Must accept req and return a domain that the cookie will be scoped for (Ex: ".mysite.com"). Otherwise, defaults to the domain inside of the request.

CSRF Drivers

DOUBLE_SUBMIT

Persist two linked tokens on the client side, one via an http header, another via a cookie. On incoming requests, match the tokens.

AUTHED_TOKEN

Persist a token via an http header linked to the currently authenticated user. Validate against the user for incoming requests.

Requires getUserToken to be set in options

AUTHED_DOUBLE_SUBMIT

A combination of DOUBLE_SUBMIT and AUTHED_TOKEN, either strategy passing will allow the request to go through.

Client side

Note that jwt-csrf only works for ajax calls, not full-page posts, since it relies on being able to set and read http headers.

Persisting the csrf token

Firstly, you will need to pass the token down in your initial page render. You can get the value as follows on the server-side, to insert into your initial html:

var jwtCsrf = require('jwt-csrf');
var token = jwtCsrf.getHeaderToken(req, res, { secret: mySecret });

You have two options for persisting the csrf token on the client side:

1. Manually

  • On every ajax response, persist the x-csrf-jwt header
  • On every ajax request, send the persisted x-csrf-jwt header

For example:

var csrfJwt;

jQuery.ajax({
    type: 'POST',
    url: '/api/some/action',
    headers: {
        'x-csrf-jwt': csrfJwt
    },
    success: function(data, textStatus, request){
        csrfJwt = request.getResponseHeader('x-csrf-jwt');
    }
});

2. Automatically, by patching XMLHttpRequest

var jwtCsrf = require('jwt-csrf/client');
jwtCsrf.setToken(initialToken);
jwtCsrf.patchXhr();

This will hook into each request and response and automatically persist the token on the client side for you.

jwt-csrf's People

Contributors

bluelnkd avatar bluepnume avatar gabrielcsapo avatar jhwohlgemuth avatar mstuart avatar s-richards avatar sinhanurag avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jwt-csrf's Issues

Deprecated Crypto Functions

With node v10.0.0 and above, crypto.cipher and crypto.decipher have been deprecated. I have created a PR that updates to new functions and allows passing algorithm options.

Allow excluding domains when patching the xhr

There should be a way to exclude certain domains when making post requests. Sometimes, the request could be posted to another domain. There is no need to send the token to a different server and even if it is sent, due to CORS restrictions there may be errors when reading the header.

Concurrent ajax problem

Hey guys, I am having the following problem:

  • browser renders the application
  • javascript makes 2-5 concurrent requests
  • library throw error, since cookie id doesnt match header id

This is because the COOKIE is not set at the same time as the csrf from the header. I am using the given interceptor of XmlHttpRequest. How do I handle this case? Do you guys have any good ideas?

(tested using latest Chrome)

Dependency and NPM issues

I was seeing some dependency issues when trying to pull down from NPM (see bottom) and forked the repo just to change the package.json. Looking into the code though, the missing dependency (cryptutils-paypal) isnt even in the public github version of the code. It seems it must have been an internal module? Then after looking at the npm repo i am seeing the URL for the repo is actually your internal github (github.paypal.com). Also looking at the npm page (https://www.npmjs.com/package/jwt-csrf) the whole documentation seems to be mismatched. I would help with a PR if i could but it seems like this is just an issue with the NPM setup. If you could make sure the public repo is linked to NPM and also update the jsonwebtoken version to the latest (or atleast later than 5 to fix the big security hole from last year) that would be awesome. Not sure if the internal code is more up to date but if you also have some new things in that repo merging that to upstream / public would be very helpful as well. Looking forward to using this, and thanks for building it!

Errors below:

npm WARN deprecated [email protected]: Critical vulnerability fix in v5.0.0. See https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/

npm ERR! 404 Registry returned 404 for GET on https://registry.npmjs.org/cryptutils-paypal
npm ERR! 404 
npm ERR! 404  'cryptutils-paypal' is not in the npm registry.
npm ERR! 404 You should bug the author to publish it (or use the name yourself!)
npm ERR! 404 It was specified as a dependency of 'jwt-csrf'

Keep uid unique across single request

Problem:

a) User calls to generate header token with UID X
b) Header token gets dropped on request end with UID Y
c) Cookie gets dropped with UID Y

The UID doesn't match between a) and c) so CSRF breaks. Need to persist the UID in req to make sure this doesn't happen.

incorrect cookie domain resolving

Function resolveDomain() has incorrect implementation:

function resolveDomain(req) {
    var host = req.get('host'); // Ex: "mysite.com:8000"
    var domain = host.substr(0, host.indexOf(':') || host.length); // Ex: "mysite.com"

    return '.' + domain;
}

If port is not specified in host, than function indexOf() returns -1, which is a truthy value. That's why the following condition:

host.indexOf(':') || host.length

in this case will always evaluate to -1. This results in that domain variable is an empty string so the resolved cookie domain value is ..

Here is my implementation:

function resolveDomain(req) {
    const host = req.get('host');
    const colonIndex = host.indexOf(':');

    if (colonIndex !== -1) {
        return host.substr(0, colonIndex);
    }

    return host;
}

lack of "cookie-parser" dependency info

In Readme.md file there is no information that this package relies on cookie-parser express middleware existence. Consider reading and writing cookies directly by your package.

There is also no information that JWT token is returned and cookie is being set on GET request automagically by middleware. It is important information in use case of your package with RESTfull API.

The last thing:
(node:2281) Warning: Use Cipheriv for counter mode of aes-256-ctr

Cipher algorithm should be updated, read here.

Thank you for your work :-)

Support Submit/Authed Submit driver for full page reload

I think the main idea to use JWT for stateless verification is great, however it would be nice to support apps with full page reloads.

i think that using only the cookie persistence (without header persistence), generating the token, adding it in my view (maybe in hidden field) and with a middleware that verify the jwt in the cookie against a field in the req object would make it work. Any toughts?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.