expressjs / csurf Goto Github PK
View Code? Open in Web Editor NEWCSRF token middleware
License: MIT License
CSRF token middleware
License: MIT License
Here's the example from official docs, except one difference: xsrfToken is sent in response to POST request, not GET:
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var bodyParser = require('body-parser')
var express = require('express')
var csrfProtection = csrf({ cookie: true })
var parseForm = bodyParser.urlencoded({ extended: false })
var app = express()
app.use(cookieParser())
app.post('/authenticate', /*csrfProtection,*/ function (req, res) {
// check credentials from request.body
// and then
res.send({ csrfToken: req.csrfToken() }) //EXCEPTION: csrfToken is not a function
})
app.post('/process', parseForm, csrfProtection, function (req, res) {
res.send('data is being processed')
})
I'm facing the egg-hen problem: if I enable csrfProtection, I cannot access the endpoint without the token, but if I disable it, req.csrfToken becomes undefined.
I need the /authenticate endpoint to be POST, because I don't want to expose password as url parameter.
When using kue.app.listen
(and the kue module) I noticed the following issue and reported to @dougwilson in #express who told me to open the issue here.
When csurf() is hit, it reads the stored secret in the session, and after that, you can't get it to use another secret, so destroying the session will invalidate whatever csurfToken()
gives, even when it is after the req.session.destroy()
call.
This only seems to be happening when I use kue
, so I thought it was an issue with kue and reported it here: Automattic/kue#368
Currently I'm trying to test my expressjs POST routes using Mocha/Chai. Without manual intervention all post requests fail with such a trace:
POST /users/new ForbiddenError: invalid csrf token at csrf (/vagrant/node_modules/csurf/index.js:112:19) at Layer.handle [as handle_request] (/vagrant/node_modules/express/lib/router/layer.js:95:5)
So I searched around and found this this answer from which I wrote this in my tests:
let should = chai.should()
// preserve token and agent
let csrfToken, agent
before((done) => {
agent = chai.request(server)
agent.get("/_csrf")
.end((err, res) => {
csrfToken = res.body.csrf
done()
})
})
// the test
it("should create a user when valid user data is posted", (done) => {
agent.post("/users/new")
.send({ username: "validUserName", password1: "123456", password2: "123456", _csrf: csrfToken })
.end((err, res) => {
...
So I'm passing the token (which I checked to be a real value) but the test is still failing. Can somebody tell me why this is not working?
Me having used django, I never had to deal with the problem because CSRF checks are disabled by default during tests. Is this something that can (should) be achieved with csurf? Like disable CSRF if NODE_ENV == "test"?
Dear All,
I just switched to connect 3 and i have an issue, hoped you can help me out.
var connect = require('connect'),
cookieParser = require('cookie-parser'),
cookieSession = require('cookie-session'),
csrf = require('csurf')
...
var app = connect()
.use( cookieParser( process.env.SEC_SESSION_PASS || global.config.server.session.hashSecret ) )
.use( cookieSession( {
name: text'.sid',
secret: 'secret',
cookie: { httpOnly: true }
} ) )
.use( csrf( { cookie: { key: 'XSRF-TOKEN', httpOnly: true } } ) )
...
And to all request I send I received this:
/.../node_modules/csurf/index.js:65
res.cookie(cookieKey, secret, cookie);
^
TypeError: undefined is not a function
at /.../node_modules/csurf/index.js:65:13
at Object.ondone (/.../node_modules/csurf/node_modules/csrf-tokens/node_modules/uid-safe/index.js:13:7)
All packages are the latest ones available in NPMJS.
Tanks in advance!
I can't reopen #40, but I can reproduce the problem easily:
var app = require('express')()
app.use(require('cookie-parser')())
app.use(require('csurf')({cookie: true}))
// error handler
app.use(function (err, req, res, next) {
if (err.code !== 'EBADCSRFTOKEN') return next(err)
// handle CSRF token errors here
res.status(403)
res.send('session has expired or form tampered with')
})
require('http').createServer(app).listen(3000);
I run that as node app.js
and then test it with curl:
$ curl -v 'http://localhost:3000'
< set-cookie: _csrf=DkSxyeny6EX0rBL205t26k00
$ curl -v -H 'Cookie: _csrf=DkSxyeny6EX0rBL205t26k00' -H 'X-XSRF-TOKEN: DkSxyeny6EX0rBL205t26k00' --data-binary '{}' 'http://localhost:3000'
> Cookie: _csrf=DkSxyeny6EX0rBL205t26k00
> X-XSRF-TOKEN: DkSxyeny6EX0rBL205t26k00
< HTTP/1.1 403 Forbidden
When using the first example in the Readme, (using Ejs template language), the token validation works fine. When I try using the 'Ignoring Routes' example, on the 'GET /form' to 'POST /process' execution(just as I did in the first example), I get 'invalid token' on the 'POST'. The token is being passed to the form on the GET. Any ideas?
I know some (including me) have had confusion about the difference between the csrf cookie placed in the client and the token submitted in the requests.
I understand it to work the following way:
If this is the case, is there anyway to test a CSRF protected POST route via something like Postman? and if so, does anyone have suggestions for this?
I've looked at some answers such as this here:
https://stackoverflow.com/questions/27182701/how-do-i-send-spring-csrf-token-from-postman-rest-client/35925413
But they don't seem to work as described.
The document says:
_csrf parameter in req.body generated by the body-parser middleware.
From the client, I have done a POST and the request payload is:
{"email":"[email protected]","password":"asdfas","_csrf":"Cn72pjW6-8PQ43dGXIAjslG488tFfAAgzX0s"}
But I always get a 403
error "session has expired or tampered with".
This is the expressjs app:
var express = require('express');
var app = express();
var http = require('http').Server(app);
var cookie = require("cookie-session");
var session = require("express-session");
app.use(cookie('keyboard cat'));
app.use(session({
secret: 'keyboard cat'
}));
var csrf = require('csurf');
var bodyParser = require('body-parser');
app.use(csrf());
app.use(function(err, req, res, next) {
if (err.code !== 'EBADCSRFTOKEN') return next(err);
res.status(403).json({"error": "session has expired or tampered with"});
});
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.post("/register", function(req, res) {
var email = req.body.email;
var password = req.body.password;
console.log('login done');
console.log(req.body);
res.json({"done":"done"});
});
app.get("/register", function(req, res) {
res.json({"csrf": req.csrfToken()});
});
http.listen(3000, function() {
console.log('Express app started');
});
The csrf token is retrieved when the client does a GET /register
, which sets the csrf token on the form. When the form is submitted, the request payload is sent but denied by csurf. I'm still not clear on what is needed after reading the doc. Am I missing something?
Would be nice to catch the error in a middleware error handler without having to parse the message. Something like:
/**
* Verify the token.
*
* @param {IncomingMessage} req
* @param {Object} tokens
* @param {string} secret
* @param {string} val
* @api private
*/
var InvalidCsrfToken = function(message) {
this.name = "InvalidCsrfToken";
this.message = message || "Invalid CSRF token.";
};
InvalidCsrfToken.prototype = new Error();
InvalidCsrfToken.prototype.constructor = InvalidCsrfToken;
function verifytoken(req, tokens, secret, val) {
// valid token
if (tokens.verify(secret, val)) {
return;
}
var err = new InvalidCsrfToken();
throw err;
}
I don't think that the verifytoken
function should throw a 403 (as it currently does) as this should be handled by the error handler, although if it's best left here that's understandable. It can always be changed by the error handler.
Just to demonstrate, my error handler could then...
app.use(function(err, req, res, next) {
// Log all errors.
console.error(err);
// Pull the default error message from the error, updating it where helpful.
var message = err.toString();
// Send the proper response code.
switch (err.name) {
case 'ValidationError':
case 'BadRequest':
res.status(400);
break;
case 'InvalidCsrfToken':
res.status(403);
message = "The form you submitted has become outdated or has been tampered with. Foo bar baz.";
break;
case 'NotFound':
res.status(404);
break;
default:
res.status(500);
message = "An internal error occured.";
break;
}
// Send the error.
if (req.xhr || req.get('content-type') == 'application/json') {
res.json({error: message});
} else {
res.render('pages/error', {error: message});
}
});
And everyone wins.
For now, the docs give two examples. Both of them are based on server-side render.
The key point is: how to send csrf
token to front-end domain.
back-end server will not render a <form>
or index.html
page so you can attach csrf-token
to hidden form field or <meta>
tag.
We also can't provide a api
to grab the csrf-token
.
back-end: http://localhost:3000
front-end: http://localhost:4200
I search a lot, but still do not find a solution for this case.
In index.js
var hash = escape(crypto
.createHash('sha1')
.update(salt)
.update('-')
.update(secret)
.digest('base64'))
return salt + '-' + hash
it looks like .update("-")
causes a TypeError: Bad input string
error.
It seems to work find when i remove that line. I'm wondering if it's an issue with an older version of crypto? since it seems to work find when i pull up a node console.
Any thoughts?
I'm having some trouble getting both these frameworks to use and verify csrf. Main problem is that angular's csrf is always undefined
and csurf doesn't seem to verify any tokens at all (the app.post('/login')
is always run successfully as though csurf was never integrated).
Here is my attempt at getting a register form to use csrf:
https://github.com/maplesap/csrf_test
You can run it with node app.js
and then visit /register
to see the problem. Can anyone help?
Is there any harm with doing this so I can avoid having to put the csrfToken: req.csrfToken()
in each res.render(...)
in my Express app.
app.use(function(req, res, next) {
res.locals.csrfToken = req.csrfToken();
next();
});
Thanks
When doing a POST or PUT request with the new-ish fetch()
API:
fetch('/URL', {
method: 'PUT',
body: 'whatever',
headers: { 'csrf-token': csrf }
}).then(res => res.json()).then(res => {
console.log(res);
});
I receive a typical error of:
ERROR { ForbiddenError: invalid csrf token
...
code: 'EBADCSRFTOKEN' }
After many hours searching the web and debugging it (since it is a hard-to-debug issue if you don't know why), I found out that this is because fetch()
does not send the current session. This can be solved adding the credentials: 'include'
key-value pair to the fetch() request:
fetch(`/todo/${e.target.id}`, {
method: 'PUT',
body: done,
credentials: 'include',
headers: { 'csrf-token': csrf }
}).then(res => res.json()).then(res => {
console.log(res);
});
However Google returns really bad results for this as there are many similar errors. I think more people might be having this issue and it'll be more and more common as fetch()
becomes more popular, and it's not something that will be easy to debug for people new to csurf.
So I propose to add a warning to the documentation, since fetch
is an standard and it doesn't work without adding this (it creates a new session).
Can you guys put a working example somewhere please? I can't get this to work with obvious parameters.
https://github.com/expressjs/csurf/blob/master/index.js#L44 cookieKey
should be _csrfSecret
or something not _csrf
. i think that confuses people.
also, i think we should move this lib to cookies
because implicitly depending on another middleware is silly. this way we could optionally pass in other options like .httpOnly
and maxAge
, etc.
This is a deviation from recommended patterns for connect-based middleware. When a middleware encounters an unrecoverable error, it should call next(err)
.
This is not the case below (index.js). Also the error message is misleading in this case because the configuration is valid:
throw new Error('misconfigured csrf')
Also this does not filter page and xhr requests versus resources. The end result is that resources like styles and images cannot be served to build a friendly nice looking error page.
Currently we implement the CSURF in our project to add security feature.
Here how we implement it :
under routes
/** Implement CSRF Token */
var csrfProtection = csrf();
/** Home page */
app.get('/user', isAuthenticated, csrfProtection, home.show);
app.post('/new/user', isAuthAPI, csrfProtection, user.update);
Add the token in meta data
<meta name="csrf-token" content="{{_csrftoken}}">
Then override AJAX to add the token
/** SET CSRF */
var CSRF_HEADER = 'X-CSRF-Token';
var setCSRFToken = function (securityToken) {
jQuery.ajaxPrefilter(function (options, _, xhr) {
if (!xhr.crossDomain && options.type != 'get') {
xhr.setRequestHeader(CSRF_HEADER, securityToken);
}
});
};
setCSRFToken($('meta[name="csrf-token"]').attr('content'));
/** END SET CSRF */
Then i try the a single token in all the page and it was working. It should be valid only in one page or one request ?
Hi.
I'm trying to use the example if (err.code !== 'EBADCSRFTOKEN') return next(err)
- I stop the app, then the restart it and try to send the form which contains a csrf
hidden field,
but my app (Express 4.x) returns such an err
:
{ [Error: invalid csrf token] status: 403 }
which is really strange, and I cannot even get the error string.
Any ideas?
Hi all!
I'm currently building an authentication library, which ships with pre-built registration and login forms. Because of this, my library uses this csurf module to protect the form inputs.
My library initializes it's own session management stuff (to maintain user state), using the node-client-sessions library from Mozilla (https://github.com/mozilla/node-client-sessions), which allows me to specify a custom request session key.
So for instance, I can use that library to initialize ONE session as req.stormpathSession
, and another as req.session
.
I like doing this because this way -- my library does its own session stuff under req.stormpathSession
, while the user USING my library can create / do their own session stuff as req.session
, which is sort of the convention.
Anyhow: back to my original point. What I'd like is for this ilbrary to support custom session keys. This way, I could tell the csurf middleware to write data to req.stormpathSession
instead of the default req.session
. This would make it possible for my sort of use case to work.
If this is cool with ya'll, and you'll merge it in, I'd be happy to submit a clean patch supporting this behavior along with full tests / etc.
Let me know if this sounds OK!
I don't see any issues regarding lack of support for prevention against BREACH attack. Is it supported?
An implementation that supposedly is a work around that.
Am I understanding correctly that the cookie option stores the secret that is used to create the csrf token as a cookie?
If so, the attacker could change the cookie and thereby always send a valid token.
I think this only works if CORS is disabled or there's an XSS vector (in which case it doesn't really matter), but it could be mitigated by using an extra fixed secret in the server that combines with the cookie secret?
I think that adding the 'Encrypted Token Pattern' for stateless CSRF protection would be a good feature to add as an alternative to 'double submit.' #
Wondering your thoughts on this. recently, my redis provider went down for a sec, and sent my app into a downward spiral of death. i've since added in better error handling for when the session isn't available, and also a check to see if first the req.csrfToken()
function exists, so the app won't crash. is that pretty much the extent of it?
if (req.csrfToken) {
state.csrf = req.csrfToken();
} else {
next(new Error('no csrftoken function'));
}
and for sessions:
app.use(function (req, res, next) {
if (!req.session) {
return next(new Error('session not defined'));
}
next();
});
When reading values from headers, csurf looks at x-xsrf-token
and x-csrf-token
. RFC 6648 recommends against using X-
prefix for non-standard HTTP headers. Would be nice if csurf added support for headers xsrf-token
and csrf-token
, recommended their use in the documentation and linked to RFC 6648.
Hello,
I had arranged a middleware to allow a certain route to pass without csrf examine like the below. Now, I've been trying to get rid of this error message: [TypeError: Object #<incomingMessage> has no method 'csrfToken']
. Because of this error my response status is set as 500 (internal server error).
I was wondering how can I obstruct being called csrfToken() ?
var csrf = csurf()
app.use(function (req, res, next) {
if (req.path == '/test') return next()
csrf(req, res, next)
})
My node application routes the requests in two main categories /app
, /api
. The application uses csurf
as described in the examples.
How can I disable it for the /api
routes since I'm using token authentication (RFC 6750) and I don't want CSRF protection.
I am unable to use csurf in this basic test application, no matter what I do I always get "ForbiddenError: invalid csrf token" after sending a form.
What am I doing wrong? I am trying to follow the example given in the documentation for csurf (although I am using TLS as well - could that affect the results?).
'use strict'
var https = require('https');
var express = require('express');
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var bodyParser = require('body-parser')
var fs = require('fs');
var oauth = require('./oauth.js');
var argv = require('minimist')(process.argv.slice(2), {
alias: {p: 'port'},
default: {port: 80},
});
// setup route middlewares
var csrfProtection = csrf({ cookie: true })
var parseForm = bodyParser.urlencoded({ extended: false })
var app = express();
app.use(cookieParser());
// Init SSL
var sslPath = '/etc/letsencrypt/live/censored/';
var options = {
key: fs.readFileSync(sslPath + 'privkey.pem'),
cert: fs.readFileSync(sslPath + 'fullchain.pem')
};
app.get('/some-form', csrfProtection, function(req, res){
res.send('<form action="/process" method="POST">' +
'<input type="hidden" name="_csrf" value="' + req.csrfToken() + '">' +
'Favorite color: <input type="text" name="favoriteColor">' +
'<button type="submit">Submit</button>' +
'</form>');
});
app.post('/process', csrfProtection, function(req, res){
res.send('<p>Your favorite color is "' + req.body.favoriteColor + '".');
});
app.get("/", function(req, res) {
res.send('Hello World!');
});
app.listen(argv.port, function() {
console.log('listening on port ' + argv.port);
});
https.createServer(options, app).listen(443);
Or rather, I don't know how to use it :)
Basically, I want the following:
So I set the following code into my server:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cookieParser());
app.use(csrf({ cookie: true }));
app.use(function (req, res, next) {
res.cookie('XSRF-TOKEN', req.csrfToken());
next();
});
// unauthenticated routes
var authCtrl = require('./routes/auth');
app.use('/auth/login', authCtrl.login);
app.use('/auth/register', authCtrl.register);
// verify JWT token for authorization
app.use(require('./middleware/access_token').checkJwt);
// authenticated routes
var usersCtrl = require('./routes/user');
app.get('/users', node_acl.customMiddleware, usersCtrl.getAll);
// ... more routes ...
// global error handler
app.use(function (err, req, res, next) {
console.error(err);
if (err.code == 'EBADCSRFTOKEN') {
err.status = 403;
err.message = 'Invalid Anti-CSRF token.';
}
res.status(err.status || 500).send(err.message || 'Internal server error.');
});
The problem is the following: the line that goes app.use(csrf({ cookie: true }));
already tries to validate the token. But I cannot remove it, because then this code req.csrfToken()
would fail because csrfToken()
is undefined.
Am I missing something here? How do I attach csrfToken()
to req
without actually trying to validate it?
Trying to use this with Ajax and it is not working.
Many others are having same problem.
This is a common use case and would be worthy of putting in the documentation..
Scenario:
All my site forms protected by csrf
- it is ok.
But url /special
must receive POST
request from other site (example, self-signed notification of payment) and there is no csrf
available for this request.
Example:
app.use(csurf({ignoreUrls: new RegExp('^/(special|nocsrf)')}));
And in library:
// verify the incoming token
if (!ignoreMethod[req.method] && !req.url.match(ignoreUrls)) {
verifytoken(req, tokens, secret, value(req))
}
This is a placeholder for the idea to alter this module to check for the CSRF token when the request has a body, regardless of the method. Any request containing a body should fall under CSRF checking (since it is likely modifying state).
@jonathanong @Fishrock123 @defunctzombie thoughts?
In the document, the example given:
// pass the csrfToken to the view
app.get('/form', function(req, res) {
res.render('send', { csrfToken: req.csrfToken() })
})
Shows that it will provide the form with a new csrf token whenever /form
is requested.
If I refresh the form to get a new csrf token, but POST with the old csrf token, it won't throw a 403
error and will succeed.
Would it be good practice to expire old tokens as soon as they are used? How can that be done with csurf?
Hello,
Yesterday, our site started giving all users an http500 error, which we tracked back to csurf failing with the error message 'misconfigured csrf at getSecret'. The site had been up and running for weeks, and this error started getting reported out of the nowhere. Restarting the server brought the site back to normal.
Our site runs csurf 1.7.0, just wanted to file this issue and check if other users have been experiencing the same situation.
Unfortunately, I am not able to repro the issue.
Currently the readme basically says nothing.
I'll have a go at it, but I don't know much about csurf and I have had some trouble implementing it in the past.
Currently csrf secret creation and token checking are done "together." The problem is that I may want to put the csrf secret creation early on in the middleware stack, but then check the token some time later in the stack.
My use case is that I only parse incoming form submissions in routes where I expect them instead of parsing them near the top of the stack for every request. The form is where I'd usually have my csrf token for verification.
I found that this module only checks whether the submitted CSRF token is valid against the secret inside session/cookie secret at this line https://github.com/expressjs/csurf/blob/master/index.js#L111.
However, when a correct token is submitted, and it is verified, the code does nothing to the secret. So, I can reuse the same token over-and-over again because the secret does not change.
What it should do is when a valid token is verified, it should regenerate a new secret.
I am using express 4.3.1 and csurf and everything works on chrome no problem.
However in Safari every form post generates a 403 "invalid csrf token" error.
Items of note:
app.enable('trust proxy');
in place app.use(session({
secret: config.session.secret,
key: 'sessionId', // Use something generic so you don't leak information about your server
cookie: {
httpOnly: true, // Reduce XSS attack vector
secure: true, // Cookies via SSL
maxAge: config.session.maxAge
},
store: new MongoStore({
mongoose_connection: db,
auto_reconnect: true
})
}));
Safari works in development without SSL and without secure cookies just fine.
I'm stumped. Anyone have any ideas?
I believe it's not very clear what's the way of using it.
Adding an example with a form will help for it. In the current documentation only the server side is shown.
I found this example in stackoverflow which shows how to use it in the views as well:
app.use(require('body-parser')());
app.use(require('cookie-parser')('YOUR SECRET GOES HERE'));
app.use(require('express-session')());
app.use(require('csurf')());
app.get('/some-form', function(req, res){
res.send('<form action="/process" method="POST">' +
'<input type="hidden" name="_csrf" value="' + req.csrfToken() + '">' +
'Favorite color: <input type="text" name="favoriteColor">' +
'<button type="submit">Submit</button>' +
'</form>');
});
app.post('/process', function(req, res){
res.send('<p>Your favorite color is "' + req.body.favoriteColor + '".');
});
The use of csrfToken()
is not explained in the docs.
I have this odd issue with the _csrf cookie in safari (not sure if this is csurf library or not).
I can replicate this in my app by loading up "https://crm-node:3443/tickets" with no cookie and it decides to set 2.
I use this setup code:
app.use require('express-session')
cookie:
httpOnly: true
secure: true
maxAge: 3600000 * 8 # hour in ms * 8 = 8 hours
secret: security.cookieSecret
store: sessionstore
saveUninitialized: true
resave: true
csrf = require "csurf"
app.use csrf cookie: true
app.use (req, res, next) ->
res.cookie 'XSRF-TOKEN', req.csrfToken()
next()
# error handler
app.use (err, req, res, next) ->
if err.code isnt 'EBADCSRFTOKEN' then return next err
# handle CSRF token errors here
res.status 403
res.send 'session has expired or form tampered with'
And looking on safari for some reason I get the following, causing errors for some bizarre reason:
Note the duplicate _csrf cookie, one for '/' and one for '/tickets'.
Is this a bug or some kind of user error?
Please note in the docs, that if using the cookie-session module, it must be required before requiring csurf.
My code looked like this:
....
var cookieParser = require('cookie-parser');
var csrf = require('csurf');
var bodyParser = require('body-parser');
var express = require('express');
var cookieSession = require('cookie-session'); // <- should be required before csurf!
...
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(cookieSession({
secret: conf.session.secret,
expires: new Date(Date.now() + sessionMaxAge),
key: 'sessionId'
}));
app.use(csrf({ cookie: true}));
...
I passed the csrf token to the view:
res.render('index', { csrf: req.csrfToken() });
In the view I use the csrf token in a hidden input element (Jade code):
input(type='hidden', name='_csrf', value='#{csrf}')
Now if I waited until the session had expired and tried to submit the form I got the error EBADCSRFTOKEN
no matter what.
Requiring cookie-session before csurf solved the problem for me.
hey there.
I'm currently making use of the csurf module and having an issue, which I think is interesting for others too and can be fixed very easy:
I do want to use and valide csurf for every method, also for get, head, options, etc. - but I want to specifiy some specific routes, which should not be validated.
My quickfix was to fork your module on my private npm and include the following:
var ignoreRoutes = options.ignoreRoutes === undefined
? []
: options.ignoreRoutes;
if (!ignoreMethod[req.method] &&
ignoreRoutes.indexOf(req.path.replace(new RegExp("/", "g"), "")) === -1) {
verifytoken(req, tokens, secret, value(req));
}
Now I could use the middleware that way:
var csrfExcludedRoutes = ["someRoute"];
this.app.use(csrf({cookie: true, httpOnly: false, ignoreMethods: [], ignoreRoutes: csrfExcludedRoutes}));
I want to get the csrf-token created, but not validated. Is there another way to do that?
Currently the following code:
const csrf = csurf({
cookie: {
key: '_csrf',
httpOnly: true,
secure: true,
sameSite: 'none',
},
});
Throws the following error:
express_error { error:
TypeError: option sameSite is invalid
at Object.serialize (/home/me/myapp/node_modules/cookie/index.js:174:15)
at setCookie (/home/me/myapp/node_modules/csurf/index.js:246:21)
at setSecret (/home/me/myapp/node_modules/csurf/index.js:275:5)
at csrf (/home/me/myapp/node_modules/csurf/index.js:107:7)
at /home/me/myapp/mytest.js:117:9
I believe this is because [email protected]
does not support none
as a valid value for the sameSite
option. [email protected]
has added this support [1].
Other projects that depend on cookie
have upgraded to [email protected]
. For example, express-session
[2].
SameSite=None
is a valid cookie attribute [3] and with the change in Chrome 80 in how SameSite
is defaulted [4], setting SameSite=None
is a needed feature in csurf
.
[1] https://github.com/jshttp/cookie/releases/tag/v0.4.0
[2] https://github.com/expressjs/session/releases/tag/v1.17.0
[3] https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
[4] https://www.chromium.org/updates/same-site
cookie
set to a truthy value to enable cookie-based instead of session-based csrf secret storage.
cookie
is an object, these options can be configured, otherwise defaults are used:
key
the name of the cookie to use (defaults to _csrf
) to store the csrf secretif (options.cookie && !options.cookie.key) {
options.cookie.key = '_csrf'
}
so, if i do the following:
app.use(express.csrf({ cookie: true }));
options.cookie.key
is undefined
because .key
is assigned to a bool.
what am I missing?
Can I set the Token Lifetime ? and whats is the default lifetime ?
It can be useful csrf tokens as a state parameter to oauth callbacks. Those are a bit of a snowflake: the state is expected to be part of the query of an otherwise normal GET request.
It would be great if something along the lines of this would work:
app.get('/oauth/callback', function(req, res, next) {
req.csrfToken.verify(req.query.state, function(err) {
if (err) return next(err);
// ... react to token that is passed into the callback ...
res.redirect('/actually-do-stuff');
});
});
From the code, we can see that signedCookies are supported for _csrf
with a secret located at req.secret
https://github.com/expressjs/csurf/blob/master/index.js#L272-L281
Would be nice if this feature can be documented (and even encouraged) in README. Thanks.
For every request it will generate new token but the old token is still valid if I make the request with old token there is no CSRF error is showing.
app.use(function(req, res, next) {
console.log("Token",req.csrfToken());
res.setHeader('X-CSRFTOKEN',req.csrfToken())
next();
});
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.