jscsrf v0.0.11
jscsrf
Node package to create and verify time based, request tokens. Prevents CSRF, Spam, & resource abuse by ensuring the traffic originates from the same domain (ie: cookie based, same origin policy) and requires the triggering of javascript events (click, submit, etc) on HTML elements.
Examples:
Basic example
const jscsrf = require('jscsrf');
// Token expires in 2 seconds.
jscsrf.setConfig({
'expires': 2,
'cookieName': 'jscsrf',
'alg': 'aes-256-ctr',
'salt': 'some random string'
});
console.log('salt:', jscsrf.conf('salt')); // salt: some random string
// Get a new token.
let token = jscsrf.getToken();
console.log('token:', token); // token: da0cb6d623bb948f2d32
// Wait 2.1 seconds.
setTimeout(function(){
let valid = jscsrf.isValidToken(token);
console.log('valid:', valid); // valid: FALSE
}, 2100);
Express Example
const express = require('express');
const cookieParser = require('cookie-parser');
const jscsrf = require('jscsrf');
// Token expires in 2 seconds.
jscsrf.setConfig({
'expires': 2
});
const app = express();
app.use(cookieParser());
/**
* Route middleware to validate a token.
* @date 2017-06-30
* @return mixed
*/
function validateCSRFToken(req, res, next) {
// Get the token from req.cookes (ie: cookie-parser).
let token = req.cookies[jscsrf.conf('cookieName')];
// Missing or empty
if (typeof token == 'undefined' || token == '') {
return next(new Error('Request token missing.'));
}
// Check whether token exists and has not expired.
if( ! jscsrf.isValidToken(token)) {
return next(new Error('Request token failed to match.'));
}
// Destroy the cookie.
res.clearCookie(jscsrf.conf('cookieName'));
// Continue.
next();
}
/**
* GET /delete_everything
* Route secured by jscsrf middleware.
* @date 2017-06-30
* @return mixed
*/
app.get('/delete_everything', validateCSRFToken, function (req, res) {
// Try reloading the page after initial success message (=401)
res.send('Passed!');
});
/**
* POST /setcsrftoken
* Ajax request route (ie: onclick, onsubmit) to set a token in a cookie.
* Jquery example:
* // <a class="delete_everything" href="/delete_everything">Delete everything</a>
* $('.delete_everything').on('click', function(){
* // Post request to example route below. Note: cache=false, async=false.
* $.ajax({type: "POST", url: '/setcsrftoken', cache: false, async: false});
* // Go to /delete_everything
* return true;
* });
* @date 2017-06-30
* @return string
*/
app.post('/setcsrftoken', function (req, res) {
// Get the current token. Possible to extend to use named tokens.
let token = jscsrf.getToken();
// See cookie-parser docs for options
res.cookie(jscsrf.conf('cookieName'), token, {maxAge : null});
// For debugging.
res.send({'token': token});
});
app.listen(8080);
Methods:
setConfig(options)
options
an object passed to over-write default options; expires (default: 3 seconds), alg (default: aes-256-ctr), salt
conf(option)
option
Optional. If specified, returns the config option value. If empty, returns all config options.
getToken()
- returns a new time sensitive token
isValidToken(token)
token
Optional. If unspecified, will use the most recently generated token.- returns true/false
Notes:
This very basic method of time based, request tokenization has been used in production sites for 5+ years to prevent common annoyances like bot registrations (transparently replacing craptchas), prevent resource abuse (ie: scraping data from ajax get urls, etc.), and provide CSRF protection on links, such as user log out and deleting sensitive data via get requests.
Common CSRF mechanisms add a token to a form input which can be scraped and passed along with input, and in some cases, defeat its intended purpose. Common methods are also ill-equipped to deal with get requests (links).