Skip to content
This repository has been archived by the owner on Jan 17, 2023. It is now read-only.

Commit

Permalink
added csrf protection
Browse files Browse the repository at this point in the history
  • Loading branch information
dannycoates committed Apr 13, 2017
1 parent e68643d commit f86c9ce
Show file tree
Hide file tree
Showing 8 changed files with 24 additions and 11 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"convict": "3.0.0",
"cookies": "0.7.0",
"core-js": "2.4.1",
"csurf": "1.9.0",
"envc": "2.5.0",
"escape-html": "1.0.3",
"eslint-plugin-promise": "3.5.0",
Expand Down
6 changes: 4 additions & 2 deletions server/src/pages/leave-screenshots/server.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
const express = require("express");
const csrf = require('csurf');
const reactrender = require("../../reactrender");
const { Shot } = require("../../servershot");

const csrfProtection = csrf({cookie: true});
let app = express();

exports.app = app;

app.get("/", function (req, res) {
app.get("/", csrfProtection, function (req, res) {
if (! req.deviceId) {
res.status(403).send("You must have the addon installed to delete your account");
return;
Expand All @@ -15,7 +17,7 @@ app.get("/", function (req, res) {
reactrender.render(req, res, page);
});

app.post("/leave", function (req, res) {
app.post("/leave", csrfProtection, function (req, res) {
if (! req.deviceId) {
res.status(403).send("You must have the addon installed to leave");
}
Expand Down
1 change: 1 addition & 0 deletions server/src/pages/leave-screenshots/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class Body extends React.Component {
This will permanently erase all of your Firefox Screenshots data.
</div>
<form action="/leave-screenshots/leave" method="POST" className="responsive-wrapper row-center">
<input type="hidden" name="_csrf" value={this.props.csrfToken} />
<button type="submit" onClick={ this.onClickDelete.bind(this) } className="button warning">
Proceed
</button>
Expand Down
6 changes: 3 additions & 3 deletions server/src/pages/shot/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ exports.changeShotExpiration = function (shot, expiration) {
location.reload();
};
}
req.send(`id=${encodeURIComponent(shot.id)}&expiration=${encodeURIComponent(expiration)}`);
req.send(`id=${encodeURIComponent(shot.id)}&expiration=${encodeURIComponent(expiration)}&_csrf=${encodeURIComponent(model.csrfToken)}`);
};

exports.deleteShot = function (shot) {
Expand All @@ -113,7 +113,7 @@ exports.deleteShot = function (shot) {
location.href = model.backend + "/shots";
}
};
req.send(`id=${encodeURIComponent(shot.id)}`);
req.send(`id=${encodeURIComponent(shot.id)}&_csrf=${encodeURIComponent(model.csrfToken)}`);
};

function refreshHash() {
Expand Down Expand Up @@ -187,7 +187,7 @@ exports.setTitle = function (title) {
};
req.open("POST", url);
req.setRequestHeader("content-type", "application/json");
req.send(JSON.stringify({ title }));
req.send(JSON.stringify({ title, _csrf: model.csrfToken }));
};

function render() {
Expand Down
3 changes: 2 additions & 1 deletion server/src/pages/shot/server.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const express = require("express");
const csrf = require("csurf");
const { Shot } = require("../../servershot");
const { notFound } = require("../../pages/not-found/server");
const reactrender = require("../../reactrender");
Expand All @@ -7,7 +8,7 @@ let app = express();

exports.app = app;

app.get("/:id/:domain", function (req, res) {
app.get("/:id/:domain", csrf({cookie: true}), function (req, res) {
let shotId = `${req.params.id}/${req.params.domain}`;
Shot.get(req.backend, shotId).then((shot) => {
let noSuchShot = false;
Expand Down
2 changes: 1 addition & 1 deletion server/src/pages/shotindex/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ exports.deleteShot = function (shot) {
refreshModel();
}
};
req.send(`id=${encodeURIComponent(shot.id)}`);
req.send(`id=${encodeURIComponent(shot.id)}&_csrf=${encodeURIComponent(model.csrfToken)}`);
};

window.addEventListener("popstate", () => {
Expand Down
3 changes: 3 additions & 0 deletions server/src/reactrender.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@ exports.render = function (req, res, page) {
model.backend = req.backend;
let jsonModel = model.jsonModel || model;
let serverModel = model.serverModel || model;
let csrfToken = req.csrfToken && req.csrfToken();
jsonModel = Object.assign({
authenticated: !!req.deviceId,
sentryPublicDSN: req.config.sentryPublicDSN,
backend: req.backend,
gitRevision: getGitRevision(),
csrfToken,
abTests: req.abTests
}, jsonModel);
serverModel = Object.assign({
authenticated: !!req.deviceId,
sentryPublicDSN: req.config.sentryPublicDSN,
staticLink: req.staticLink,
staticLinkWithHost: req.staticLinkWithHost,
csrfToken,
abTests: req.abTests
}, serverModel);
if (req.query.data == "json") {
Expand Down
13 changes: 9 additions & 4 deletions server/src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const {
const dbschema = require("./dbschema");
const express = require("express");
const bodyParser = require('body-parser');
const csrf = require("csurf");
const morgan = require("morgan");
const linker = require("./linker");
const { randomBytes } = require("./helpers");
Expand Down Expand Up @@ -154,6 +155,8 @@ function initDatabase() {

initDatabase();

const csrfProtection = csrf({cookie: true});

const app = express();

app.set('trust proxy', true);
Expand Down Expand Up @@ -237,10 +240,10 @@ app.use(morgan("combined"));
app.use(function (req, res, next) {
let authHeader = req.headers['x-screenshots-auth'];
let authInfo = {};
let cookies = new Cookies(req, res, {keys: dbschema.getKeygrip()});
if (authHeader) {
authInfo = decodeAuthHeader(authHeader);
} else {
let cookies = new Cookies(req, res, {keys: dbschema.getKeygrip()});
authInfo.deviceId = cookies.get("user", {signed: true});
let abTests = cookies.get("abtests", {signed: true});
if (abTests) {
Expand All @@ -255,6 +258,8 @@ app.use(function (req, res, next) {
req.userAnalytics = req.userAnalytics.debug();
}
}
req.cookies = cookies;
req.cookies._csrf = cookies.get("_csrf"); // csurf expects a property
req.abTests = authInfo.abTests || {};
req.backend = `${req.protocol}://${req.headers.host}`;
req.config = config;
Expand Down Expand Up @@ -684,7 +689,7 @@ app.get("/data/:id/:domain", function (req, res) {
});
});

app.post("/api/delete-shot", function (req, res) {
app.post("/api/delete-shot", csrfProtection, function (req, res) {
if (! req.deviceId) {
sendRavenMessage(req, "Attempt to delete shot without login");
simpleResponse(res, "Not logged in", 401);
Expand All @@ -702,7 +707,7 @@ app.post("/api/delete-shot", function (req, res) {
});
});

app.post("/api/set-title/:id/:domain", function (req, res) {
app.post("/api/set-title/:id/:domain", csrfProtection, function (req, res) {
let shotId = `${req.params.id}/${req.params.domain}`;
let userTitle = req.body.title;
if (userTitle === undefined) {
Expand All @@ -728,7 +733,7 @@ app.post("/api/set-title/:id/:domain", function (req, res) {
});
});

app.post("/api/set-expiration", function (req, res) {
app.post("/api/set-expiration", csrfProtection, function (req, res) {
if (! req.deviceId) {
sendRavenMessage(req, "Attempt to set expiration without login");
simpleResponse(res, "Not logged in", 401);
Expand Down

0 comments on commit f86c9ce

Please # to comment.