koajs / csrf Goto Github PK
View Code? Open in Web Editor NEWCSRF tokens for koa
License: MIT License
CSRF tokens for koa
License: MIT License
fresh clone/fork and:
~/dev/src/github.com/stephenmathieson/koa-csrf on master ∴ npm install
npm WARN deprecated [email protected]: Please use istanbul@>=0.4.0 instead
npm WARN deprecated [email protected]: Jade has been renamed to pug, please install the latest version of pug instead of jade
[email protected] node_modules/should
├── [email protected]
├── [email protected]
└── [email protected]
[email protected] node_modules/koa-session
├── [email protected]
└── [email protected] ([email protected])
[email protected] node_modules/csrf
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected] ([email protected])
[email protected] node_modules/co-body
├── [email protected]
├── [email protected]
├── [email protected] ([email protected], [email protected], [email protected])
└── [email protected] ([email protected], [email protected])
[email protected] node_modules/koa
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected] ([email protected])
├── [email protected] ([email protected])
├── [email protected] ([email protected], [email protected])
├── [email protected] ([email protected])
├── [email protected] ([email protected])
├── [email protected] ([email protected], [email protected])
├── [email protected] ([email protected])
├── [email protected] ([email protected])
└── [email protected] ([email protected])
[email protected] node_modules/mocha
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected] ([email protected])
├── [email protected] ([email protected])
├── [email protected] ([email protected], [email protected])
└── [email protected] ([email protected], [email protected])
[email protected] node_modules/supertest
├── [email protected]
└── [email protected] ([email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected])
[email protected] node_modules/istanbul-harmony
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected] ([email protected])
├── [email protected]
├── [email protected] ([email protected])
├── [email protected]
├── [email protected] ([email protected], [email protected])
├── [email protected] ([email protected], [email protected], [email protected], [email protected], [email protected])
├── [email protected] ([email protected], [email protected])
└── [email protected] ([email protected], [email protected], [email protected])
~/dev/src/github.com/stephenmathieson/koa-csrf on master ∴ npm test
> [email protected] test /Users/stephenmathieson/dev/src/github.com/stephenmathieson/koa-csrf
> NODE_ENV=test mocha --harmony --reporter spec --require should
CSRF Token
should create
✓ a token
✓ a single token per request
✓ a new token per request
should assert
✓ when no token is supplied
✓ when no secret is supplied
✓ when invalid csrf token
should not assert when the token is supplied via
✓ json body
✓ querystring
✓ x-csrf-token
✓ x-xsrf-token
.assertCSRF()
✓ should support a string value
CSRF Token Middleware
should create
✓ a token
✓ a single token per request
1) a new token per request
✓ a null token when session is invalid
should assert
✓ when no token is supplied
should not assert when the token is supplied via
✓ json body
✓ querystring
✓ querystring with body
✓ x-csrf-token
✓ x-xsrf-token
20 passing (111ms)
1 failing
1) CSRF Token Middleware should create a new token per request:
Error: expected body 'fjn6oL6A--KQnQ2JliJVRlVMRL8atRinZV0M' to match /^\w+-[\w+\/]+/
at error (node_modules/supertest/lib/test.js:265:13)
at Test._assertBody (node_modules/supertest/lib/test.js:188:18)
at Test._assertFunction (node_modules/supertest/lib/test.js:247:11)
at Test.assert (node_modules/supertest/lib/test.js:148:18)
at assert (node_modules/supertest/lib/test.js:127:12)
at node_modules/supertest/lib/test.js:124:5
at Test.Request.callback (node_modules/supertest/node_modules/superagent/lib/node/index.js:691:12)
at IncomingMessage.<anonymous> (node_modules/supertest/node_modules/superagent/lib/node/index.js:922:12)
at endReadableNT (_stream_readable.js:905:12)
npm ERR! Test failed. See above for more details.
maybe we shouldnt use a regex?
just had our security audit, and it was recommended we don't use query strings for passing the token around:
[...] but in your case I think it's suboptimal. If a user is on a page with a CSRF token in the URL and gets redirected to an external site, the CSRF token will be passed in the referrer header. Because those tokens do not expire after a single use, it means that the site which is recieving the redirect could use it to CSRF that user. Additionally, those tokens might appear in server logs or elsewhere, so it's better to keep them in the body of the request [...]
this said, it'd be nice to just disable the functionality here (rather than having to worry about it upstream). would you be opposed to a pr adding an option to disable query-string support?
i can't seem to get it working, but app.use(require('koa-csrf')())
works fine. since csrf.middleware
is the suggested way of using this thing, i'm surprised there are no tests for it
base koa2.0
const csrf = require('koa-csrf')
but
csrf(app)
is errors
I followed the example, and every time I make a POST request sending the csrf token like in the example, I always get this message: 'Invalid CSRF Token'
This is my code:
// app.js
app
.use(session())
.use(new CSRF({
invalidSessionSecretMessage: 'Invalid session secret',
invalidSessionSecretStatusCode: INVALIDSTATUSCODE,
invalidTokenMessage: 'Invalid CSRF token',
invalidTokenStatusCode: INVALIDSTATUSCODE,
excludedMethods: [ 'GET', 'HEAD', 'OPTIONS' ],
disableQuery: false
}))
// ... all other configurations...
// routes.js
route.get('/login', ctx => {
console.log(ctx.csrf)
ctx.state = { title : 'Login', login : true, csrf: ctx.csrf }
ctx.render('login')
})
// login.pug
form(submit='/auth/login' method='post')
label Username
input(name='username' type='text' placeholder='JohnDoe2' required)
label Password
input(name='password' type='password' placeholder='********' required)
if login
a(href='/auth/signup') Or register here
input(name='_csrf' value=csrf hidden)
input(type='submit' value='Send')
Am I missing something important?
I'm not sure how koa-csrf
intercepts HTTP requests - does it matter if I set my koa-router
middleware before or after setting koa-csrf
?
This is what I'm using now:
server.use(new CSRF({
invalidSessionSecretMessage: 'Invalid session secret',
invalidSessionSecretStatusCode: 403,
invalidTokenMessage: 'Invalid CSRF token',
invalidTokenStatusCode: 403,
excludedMethods: ['GET', 'HEAD', 'OPTIONS'],
disableQuery: false
}));
server.use(router.routes());
it can't work in multipart/form-data form
unlike express, we create the secret only when we need to to avoid setting cookies and updating sessions unnecessarily. however, this means with a getter, we do so synchronously.
how about changing the api to:
var csrf = yield this.csrf()
and optionally get it synchronously:
var csrf = this.csrfToken
// or without a getter
var csrf = this.csrfSync()
another breaking change, but i think it's for the better. unless we make the dev set the secret themselves, which would be kind of annoying.
Currently i am mounting csrf middleware per route like the example below,
routes.js
const csrf = new CSRF({
invalidSessionSecretMessage: 'Invalid session secret',
invalidTokenMessage: 'Invalid CSRF token',
invalidTokenStatusCode: 403,
});
const router = new Router();
route.get('/', csrf, Controller.getPage);
Is this the correct way of doing it or is there a better way? I can't find any example to validate it as the README.md only shows example of applying csrf to all routes.
I appreciate that you've made the tokenizer and validator extensible. However, secret keys really shouldn't be used with a straight hash algorithm.
var mac = crytpo.createHmac('sha256', secret).update(salt).digest('base64')
SHA1 is also pretty insecure at this point in time. Is there a reason for not using SHA-256?
For HMAC, It's important that the secret length matches the hash function. For SHA1 it's 20 bytes (160 bits), SHA256 is 32 bytes (256 bits), etc. The HMAC RFC (https://tools.ietf.org/html/rfc2104) provides guidance on key lengths.
If possible, addressing these would be a responsible thing to do to make the default more secure.
Hi, I was just wondering if there was any plan to upgrade to Koa2.0
Thanks.
~/dev/src/github.com/koajs/csrf on master ∴ node example
/Users/stephenmathieson/dev/src/github.com/koajs/csrf/node_modules/koa-session/index.js:45
throw new TypeError('app instance required: `session(opts, app)`');
^
TypeError: app instance required: `session(opts, app)`
at module.exports (/Users/stephenmathieson/dev/src/github.com/koajs/csrf/node_modules/koa-session/index.js:45:11)
at Object.<anonymous> (/Users/stephenmathieson/dev/src/github.com/koajs/csrf/example.js:7:9)
at Module._compile (module.js:435:26)
at Object.Module._extensions..js (module.js:442:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:313:12)
at Function.Module.runMain (module.js:467:10)
at startup (node.js:136:18)
at node.js:963:3
[email protected] deprecate: If you are using Koa v3.x, please make sure you are on at least 3.0.3 due to CSRF session reset issue (prevents XHR from working properly for example)
is this a mistake?
Looking at these lines: https://github.com/koajs/csrf/blob/master/src/index.js#L59-L60 when I'm debugging, ctx.request.body
is always undefined. I don't know why. Can anyone help?
Something else: at the same breakpoint as above, ctx.csrf
IS defined. Should I just be using ctx.csrf
as the token? I'm confused as to why ctx.csrf
isn't already treated as the token.
If opts is omitted, this.tokens = csrf(opts)
is created without the default values .. all the default values went into this.opts .. So either that is a bug or the code could probably be clearer commenting why this is the case and perhaps moving this.tokens = csrf(opts);
closer to the top.
I think the fix is to change:
this.tokens = csrf(opts);
to
this.tokens = csrf(this.opts);
constructor(opts) {
this.opts = opts || {};
if (!this.opts.invalidSessionSecretMessage)
this.opts.invalidSessionSecretMessage = 'Invalid session secret';
if (!this.opts.invalidSessionSecretStatusCode)
this.opts.invalidSessionSecretStatusCode = 403;
if (!this.opts.invalidTokenMessage)
this.opts.invalidTokenMessage = 'Invalid CSRF token';
if (!this.opts.invalidTokenStatusCode)
this.opts.invalidTokenStatusCode = 403;
if (!this.opts.excludedMethods)
this.opts.excludedMethods = [ 'GET', 'HEAD', 'OPTIONS' ];
if (typeof this.opts.disableQuery !== 'boolean')
this.opts.disableQuery = false;
this.tokens = csrf(opts);
return this.middleware;
}
Currently, assertCsrf
method has the body argument.
But I thought it look like that assertCsrf
method presuppose request.body
.
I seem that some developer have to understand those implements.
So, the body
argument of assertCsrf
method should have like default value which is this.request.body
.
What do you think?
that's right, i haven't even tried this.
Think of two situations:
GET/HEAD
methods are used to do write operations in backend, then risks rise.GET/HEAD
are used to query data, attackers can easily get data which may be sensitive via csrf
.To be able to import CSRF
in node 6.x we have to write like this:
const CSRF = require('koa-csrf').default;
Is this the right way? Also, the README.md example doesn't import CSRF at all(although it is using es6 modules).
this.response.csrf
this.request.assertCSRF(body)
A post route handler is called by Azure AD as a result of authentication POST response.
Is it possible to exclude CSRF check for such route?
not sure where or how.
Why is a semicolon used for the csrf token here:
https://github.com/koajs/csrf/blob/master/index.js#L70
https://github.com/koajs/csrf/blob/master/index.js#L119
Here you found the spec:
http://curl.haxx.se/rfc/cookie_spec.html
"This string is a sequence of characters excluding semi-colon, comma and white space."
When one would set this csrf-token as a cookie, then it would not work, right?
I am using an Angular JS on the client side, which sends a form data to the server. The form is trivial: username and password. AngularJS has a default action: looks for a cookie 'XSRF-TOKEN' with a token value set by server, modifies the request headers by adding 'X-XSRF-TOKEN' to the request headers and sends it to server using it's $http module.
The problem arises, when an "empty" request is made - when a user clicks login button without entering any data to fields. In that case this.request.body is null.
I now do a form validation on a client side to disable the sending of an empty body, as well as an early validation on a server side to check the presence of this.request.body after parsing the request. But it feels kind of patchy and might break future requests, where body is actually not required.
May I know the advantages of keep changing tokens?
As far as I know, only one csrf secret is created with each session, therefore, all tokens will be valid within same session (elder one wont be expired as the result of creating new one).
Can I simply create one token while creating the session and always return the same token for all incoming requests?
ctx.session.csrf = ctx.csrf;
// then always return ctx.session.csrf
I am debugging my project and have a breakpoint set at this line: https://github.com/koajs/csrf/blob/master/src/index.js#L56
Now when I evaluate (ctx.csrf), I get a value back. However I am not sending a CSRF token anywhere in my application..all I've done is set Koa to use the CSRF middleare..I haven't embedded _csrf
in a hidden form field anywhere, nor have I appended a csrf token to any of my requests. So my question is, how is ctx.csrf
already set?
Hi, I would like to ask, what if I use koa-session instead of koa-generic-session. Will it compatible with koa-csrf? since koa-generic-session seems to be deprecated.
Thanks in advance.
Bayu.
i actually looked at the middleware now, and this entire catch block is unnecessary:
try {
// bodyparser middlewares maybe store body in request.body
// or you can just set csrf token header
this.assertCSRF(this.request.body)
} catch (err) {
if (err.status === 403) {
this.status = 403
this.body = 'invalid csrf token'
} else {
this.throw(err)
}
return
}
an upstream error handler should handle the rendering of the error
I cloned this repo: https://github.com/mapmeld/koa-passport-example and getting this crucial error:
/usr/src/app/server.js:36
app.use(new CSRF({
^
TypeError: CSRF is not a constructor
at Object.<anonymous> (/usr/src/app/server.js:36:9)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.runMain (module.js:605:10)
at run (bootstrap_node.js:427:7)
at startup (bootstrap_node.js:151:9)
at bootstrap_node.js:542:3
[nodemon] app crashed - waiting for file changes before starting...
I am running inside docker containers using docker-compose and the mac client.
I am not sure how to solve.
Hi
How about limit the csrf verification to application/x-www-form-urlencoded, multipart/form-data, and text/plain type requests only ? As the plain html form can only send these 3 types of requests (without XMLHttpRequest / fetch, which has same origin policy), there will be no CSRF risks in most cases if I implement a 'application/json' type rest style API
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.