csrfimmunity
Version:
Protection against Cross Site Request Forgery attacks. This module provides multiple variation of protection.
188 lines (149 loc) • 7.03 kB
JavaScript
var colors = require('colors/safe');
var randomstring = require("randomstring"),
encryptDecrypt = require("./lib/encrypt-decrypt"),
separator = "###",
defaultTimeDiff = 250000;
function isJsonString(str) {
try {
var js = JSON.parse(str);
if (Object.keys(js).length < 2) {
console.warn(colors.red("CSRFImmunity Module (csrfImmunity.js) : Options parameter is not enough. Application might be risky to CSRF attacks"));
}
} catch (e) {
console.log(e);
console.log(colors.red("CSRFImmunity Module (csrfImmunity.js) : Not a valid JSON string, " + str));
// throw new Error(e);
return false;
}
return true;
}
module.exports = {
setKeyForEncryption: function(key) {
if (key !== "" && key !== null) {
encryptDecrypt.setKeyForEncryption(key);
return this;
} else {
console.log(colors.red("Key not found. Please provide the encryption key"));
return null;
}
},
generateTimeBasedToken: function(options, callback) {
//options needed to generate the csrf token Ex : {"formname":"loginform", formaction="http://www.weekendsecurity.org/submit"}
options = options || '{"null": "null"}';
//Check for valid JSON string
if(isJsonString(options)){
//Time calculated to check the CSRF token validity
var milliseconds = new Date().getTime();
//A random String to pass in the CSRF token and cookie value
var randomString = randomstring.generate(15);
//Converting the options JSON to hexadecimal value
var optionsBuffer = new Buffer(options);
var encodedOptions = optionsBuffer.toString('hex');
//Collecting all the token parameters for token generations
var tokenHidden = encodedOptions + separator + randomString + separator + milliseconds;
// Encrypting the CSRF token
var token = encryptDecrypt.encrypt(tokenHidden);
callback(token);
}else{
throw new Error('Options is not a JSON String');
}
},
generateToken: function(options, callback) {
options = options || '{"null": "null"}';
//Check for valid JSON string
if(isJsonString(options)){
//Time calculated to check the CSRF token validity
var milliseconds = new Date().getTime();
//A random String to pass in the CSRF token and cookie value
var randomString = randomstring.generate(15);
//Converting the options JSON to hexadecimal value
var optionsBuffer = new Buffer(options);
var encodedOptions = optionsBuffer.toString('hex');
//Collecting all the token parameters for token generations
var tokenHidden = encodedOptions + separator + randomString;
// Encrypting the CSRF token
var token = encryptDecrypt.encrypt(tokenHidden);
callback(token);
}else{
throw new Error('Options is not a JSON String');
}
},
verifyTimeBasedToken: function(csrfToken, options) {
//The options which is used to generate the CSRF token
options = options || '{"null":"null"}';
//Check for valid JSON string
if(isJsonString(options)){
//Need the CSRF token to be passed here for verification
csrfToken = csrfToken || "";
//Return false if the csrfToken and cookieValue are sent null
if (csrfToken === "") {
return false;
}
//Decrypting the csrf token
try {
var decTokenHidden = encryptDecrypt.decrypt(csrfToken);
//Split the tokens using the separators and store it in an array
var decTokenHiddenArray = decTokenHidden.split(separator);
//Converting the options in the hidden token to ascii and then into Javascript object
var optionsBuffer = new Buffer(decTokenHiddenArray[0], 'hex');
var optionsjsFromToken = JSON.parse(optionsBuffer.toString('ascii'));
var optionsjsFromParam = JSON.parse(options);
//Fetching the time limit of token validity from options parameter.
var timeDef = optionsjsFromParam.milliseconds || defaultTimeDiff;
var currentMilliseconds = new Date().getTime();
//Verifying if the CSRF token with time, and options parameter
if (currentMilliseconds < Number(decTokenHiddenArray[2]) + timeDef) {
for (var key in optionsjsFromToken) {
if (optionsjsFromToken[key] !== optionsjsFromParam[key]) {
return false;
}
}
return true;
} else {
return false;
}
} catch (e) {
console.log(colors.red(e));
console.log(colors.red("CSRFImmunity (index.js) : CSRF decryption failed.", e));
throw new Error(e);
}
}else{
throw new Error('Options is not a JSON String');
}
},
verifyToken: function(csrfToken, options) {
//The options which is used to generate the CSRF token
options = options || '{"null":"null"}';
if(isJsonString(options)){
//Need the CSRF token to be passed here for verification
csrfToken = csrfToken || "";
//Return false if the csrfToken and cookieValue are sent null
if (csrfToken === "") {
return false;
}
//Decrypting the csrf token
try {
var decTokenHidden = encryptDecrypt.decrypt(csrfToken);
//Split the tokens using the separators and store it in an array
var decTokenHiddenArray = decTokenHidden.split(separator);
//Converting the options in the hidden token to ascii and then into Javascript object
var optionsBuffer = new Buffer(decTokenHiddenArray[0], 'hex');
var optionsjsFromToken = JSON.parse(optionsBuffer.toString('ascii'));
var optionsjsFromParam = JSON.parse(options);
//Verifying if the CSRF token with time, and options parameter
for (var key in optionsjsFromToken) {
if (optionsjsFromToken[key] !== optionsjsFromParam[key]) {
return false;
}
}
return true;
} catch (e) {
console.log(e);
console.log(colors.red("CSRFImmunity (csrfImmunity.js) : CSRF decryption failed."));
throw new Error(e);
}
}else{
throw new Error('Options is not a JSON String');
}
}
};