mirror of https://github.com/calzoneman/sync.git
web/account: add referrer check
This commit is contained in:
parent
b876c8907a
commit
875337d9a6
13
NEWS.md
13
NEWS.md
|
@ -1,3 +1,16 @@
|
||||||
|
2017-11-05
|
||||||
|
==========
|
||||||
|
|
||||||
|
The latest commit introduces a referrer check in the account page handlers.
|
||||||
|
This is added as a short-term mitigation for a recent report that account
|
||||||
|
management functions (such as deleting channels) can be executed without the
|
||||||
|
user's consent if placed in channel JS.
|
||||||
|
|
||||||
|
Longer term options are being considered, such as moving account management to a
|
||||||
|
separate subdomain to take advantage of cross-origin checks in browsers, and
|
||||||
|
requiring the user to re-enter their password to demonstrate intent. As always,
|
||||||
|
I recommend admins take extreme caution when accepting channel JS.
|
||||||
|
|
||||||
2017-09-26
|
2017-09-26
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"author": "Calvin Montgomery",
|
"author": "Calvin Montgomery",
|
||||||
"name": "CyTube",
|
"name": "CyTube",
|
||||||
"description": "Online media synchronizer and chat",
|
"description": "Online media synchronizer and chat",
|
||||||
"version": "3.51.2",
|
"version": "3.51.3",
|
||||||
"repository": {
|
"repository": {
|
||||||
"url": "http://github.com/calzoneman/sync"
|
"url": "http://github.com/calzoneman/sync"
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,7 +15,7 @@ var session = require("../session");
|
||||||
var csrf = require("./csrf");
|
var csrf = require("./csrf");
|
||||||
const url = require("url");
|
const url = require("url");
|
||||||
|
|
||||||
const LOGGER = require('@calzoneman/jsli')('database/accounts');
|
const LOGGER = require('@calzoneman/jsli')('web/accounts');
|
||||||
|
|
||||||
let globalMessageBus;
|
let globalMessageBus;
|
||||||
let emailConfig;
|
let emailConfig;
|
||||||
|
@ -28,12 +28,42 @@ function handleAccountEditPage(req, res) {
|
||||||
sendPug(res, "account-edit", {});
|
sendPug(res, "account-edit", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function verifyReferrer(req, expected) {
|
||||||
|
const referrer = req.header('referer');
|
||||||
|
|
||||||
|
if (!referrer) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsed = url.parse(referrer);
|
||||||
|
|
||||||
|
if (parsed.pathname !== expected) {
|
||||||
|
LOGGER.warn(
|
||||||
|
'Possible attempted forgery: %s POSTed to %s',
|
||||||
|
referrer,
|
||||||
|
expected
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles a POST request to edit a user"s account
|
* Handles a POST request to edit a user"s account
|
||||||
*/
|
*/
|
||||||
function handleAccountEdit(req, res) {
|
function handleAccountEdit(req, res) {
|
||||||
csrf.verify(req);
|
csrf.verify(req);
|
||||||
|
|
||||||
|
if (!verifyReferrer(req, '/account/edit')) {
|
||||||
|
res.status(403).send('Mismatched referrer');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var action = req.body.action;
|
var action = req.body.action;
|
||||||
switch(action) {
|
switch(action) {
|
||||||
case "change_password":
|
case "change_password":
|
||||||
|
@ -43,7 +73,7 @@ function handleAccountEdit(req, res) {
|
||||||
handleChangeEmail(req, res);
|
handleChangeEmail(req, res);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
res.send(400);
|
res.sendStatus(400);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,6 +227,11 @@ async function handleAccountChannelPage(req, res) {
|
||||||
function handleAccountChannel(req, res) {
|
function handleAccountChannel(req, res) {
|
||||||
csrf.verify(req);
|
csrf.verify(req);
|
||||||
|
|
||||||
|
if (!verifyReferrer(req, '/account/channels')) {
|
||||||
|
res.status(403).send('Mismatched referrer');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var action = req.body.action;
|
var action = req.body.action;
|
||||||
switch(action) {
|
switch(action) {
|
||||||
case "new_channel":
|
case "new_channel":
|
||||||
|
@ -395,6 +430,11 @@ function validateProfileImage(image, callback) {
|
||||||
async function handleAccountProfile(req, res) {
|
async function handleAccountProfile(req, res) {
|
||||||
csrf.verify(req);
|
csrf.verify(req);
|
||||||
|
|
||||||
|
if (!verifyReferrer(req, '/account/profile')) {
|
||||||
|
res.status(403).send('Mismatched referrer');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const user = await webserver.authorize(req);
|
const user = await webserver.authorize(req);
|
||||||
// TODO: error message
|
// TODO: error message
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
@ -465,6 +505,11 @@ function handlePasswordResetPage(req, res) {
|
||||||
function handlePasswordReset(req, res) {
|
function handlePasswordReset(req, res) {
|
||||||
csrf.verify(req);
|
csrf.verify(req);
|
||||||
|
|
||||||
|
if (!verifyReferrer(req, '/account/passwordreset')) {
|
||||||
|
res.status(403).send('Mismatched referrer');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var name = req.body.name,
|
var name = req.body.name,
|
||||||
email = req.body.email;
|
email = req.body.email;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue