Add csrf prevention

This commit is contained in:
calzoneman 2015-02-22 18:15:22 -06:00
parent 420e77963b
commit afc0ea0a58
14 changed files with 110 additions and 5 deletions

View file

@ -12,6 +12,7 @@ var $util = require("../utilities");
var Config = require("../config");
var Server = require("../server");
var session = require("../session");
var csrf = require("./csrf");
/**
* Handles a GET request for /account/edit
@ -28,6 +29,8 @@ function handleAccountEditPage(req, res) {
* Handles a POST request to edit a user"s account
*/
function handleAccountEdit(req, res) {
csrf.verify(req);
var action = req.body.action;
switch(action) {
case "change_password":
@ -204,6 +207,8 @@ function handleAccountChannelPage(req, res) {
* Handles a POST request to modify a user"s channels
*/
function handleAccountChannel(req, res) {
csrf.verify(req);
var action = req.body.action;
switch(action) {
case "new_channel":
@ -394,6 +399,8 @@ function handleAccountProfilePage(req, res) {
* Handles a POST request to edit a profile
*/
function handleAccountProfile(req, res) {
csrf.verify(req);
if (!req.user) {
return sendJade(res, "account-profile", {
profileImage: "",
@ -442,6 +449,8 @@ function handlePasswordResetPage(req, res) {
* Handles a POST request to reset a user's password
*/
function handlePasswordReset(req, res) {
csrf.verify(req);
var name = req.body.name,
email = req.body.email;

View file

@ -15,11 +15,14 @@ var db = require("../database");
var Config = require("../config");
var url = require("url");
var session = require("../session");
var csrf = require("./csrf");
/**
* Processes a login request. Sets a cookie upon successful authentication
*/
function handleLogin(req, res) {
csrf.verify(req);
var name = req.body.name;
var password = req.body.password;
var rememberMe = req.body.remember;
@ -119,7 +122,10 @@ function handleLoginPage(req, res) {
* Handles a request for /logout. Clears auth cookie
*/
function handleLogout(req, res) {
csrf.verify(req);
res.clearCookie("auth");
req.user = res.user = null;
// Try to find an appropriate redirect
var dest = req.query.dest || req.header("referer");
dest = dest && dest.match(/login|logout|account/) ? null : dest;
@ -159,6 +165,8 @@ function handleRegisterPage(req, res) {
* Processes a registration request.
*/
function handleRegister(req, res) {
csrf.verify(req);
var name = req.body.name;
var password = req.body.password;
var email = req.body.email;

40
lib/web/csrf.js Normal file
View file

@ -0,0 +1,40 @@
/*
* Adapted from https://github.com/expressjs/csurf
*/
var csrf = require("csrf");
var createError = require("http-errors");
var tokens = csrf();
exports.init = function csrfInit(req, res, next) {
var secret = req.signedCookies._csrf;
if (!secret) {
secret = tokens.secretSync();
res.cookie("_csrf", secret, { signed: true, httpOnly: true });
}
var token;
req.csrfToken = function csrfToken() {
if (token) {
return token;
}
token = tokens.create(secret);
return token;
};
next();
};
exports.verify = function csrfVerify(req) {
var secret = req.signedCookies._csrf;
var token = req.body._csrf || req.query._csrf;
if (!tokens.verify(secret, token)) {
throw createError(403, 'invalid csrf token', {
code: 'EBADCSRFTOKEN'
});
}
};

View file

@ -14,7 +14,8 @@ function merge(locals, res) {
siteDescription: Config.get("html-template.description"),
siteAuthor: "Calvin 'calzoneman' 'cyzon' Montgomery",
loginDomain: Config.get("https.enabled") ? Config.get("https.full-address")
: Config.get("http.full-address")
: Config.get("http.full-address"),
csrfToken: res.req.csrfToken()
};
if (typeof locals !== "object") {
return _locals;

View file

@ -14,6 +14,7 @@ var cookieParser = require("cookie-parser");
var static = require("serve-static");
var morgan = require("morgan");
var session = require("../session");
var csrf = require("./csrf");
const LOG_FORMAT = ':real-address - :remote-user [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"';
morgan.token('real-address', function (req) { return req._ip; });
@ -190,6 +191,7 @@ module.exports = {
Logger.errlog.log("YOU SHOULD CHANGE THE VALUE OF cookie-secret IN config.yaml");
}
app.use(cookieParser(Config.get("http.cookie-secret")));
app.use(csrf.init);
app.use(morgan(LOG_FORMAT, {
stream: require("fs").createWriteStream(path.join(__dirname, "..", "..",
"http.log"), {
@ -253,6 +255,10 @@ module.exports = {
return res.status(413).end();
} else if (err.message && err.message.match(/bad request/i)) {
return res.status(400).end("Bad Request");
} else if (err.message && err.message.match(/invalid csrf token/i)) {
res.status(403);
sendJade(res, 'csrferror', { path: req.path });
return;
}
Logger.errlog.log(err.stack);
res.status(500).end();