Skip to content
This repository has been archived by the owner on Sep 14, 2022. It is now read-only.

Commit

Permalink
Merge 8ec6681 into d47bc84
Browse files Browse the repository at this point in the history
  • Loading branch information
x24git committed Sep 6, 2018
2 parents d47bc84 + 8ec6681 commit 4a61106
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 14 deletions.
15 changes: 8 additions & 7 deletions README.md
Expand Up @@ -26,15 +26,15 @@ This is a [Node.js](https://nodejs.org/en/) module available through the
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):

```sh
$ npm install csurf
$ npm install csurf-expire
```

## API

<!-- eslint-disable no-unused-vars -->

```js
var csurf = require('csurf')
var csurf = require('csurf-expire')
```

### csurf([options])
Expand Down Expand Up @@ -68,6 +68,7 @@ following keys:
- `key` - the name of the cookie to use to store the token secret
(defaults to `'_csrf'`).
- `path` - the path of the cookie (defaults to `'/'`).
- `maxAge` - the maximum age the cookie can be before it expires in seconds. Setting this parameter will cause a 403 response if any cookie and csfr token is sent beyond the maxAge window
- any other [res.cookie](http://expressjs.com/4x/api.html#res.cookie)
option can be set.

Expand Down Expand Up @@ -111,12 +112,12 @@ that requires a CSRF token to post back.

```js
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var csrf = require('csurf-expire')
var bodyParser = require('body-parser')
var express = require('express')

// setup route middlewares
var csrfProtection = csrf({ cookie: true })
var csrfProtection = csrf({ cookie:{maxAge:60*60*8 \\8 hours})
var parseForm = bodyParser.urlencoded({ extended: false })

// create express app
Expand Down Expand Up @@ -204,7 +205,7 @@ do not check for a valid CSRF token.
```js
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var csrf = require('csurf-expire')
var bodyParser = require('body-parser')
var express = require('express')

Expand All @@ -220,7 +221,7 @@ app.use('/api', api)
// now add csrf and other middlewares, after the "/api" was mounted
app.use(bodyParser.urlencoded({ extended: false }))
app.use(cookieParser())
app.use(csrf({ cookie: true }))
app.use(csrf({ cookie:{maxAge:60*60*8 \\8 hours}}))

app.get('/form', function (req, res) {
// pass the csrfToken to the view
Expand Down Expand Up @@ -251,7 +252,7 @@ error messages.
```js
var bodyParser = require('body-parser')
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var csrf = require('csurf-expire')
var express = require('express')

var app = express()
Expand Down
40 changes: 38 additions & 2 deletions index.js
Expand Up @@ -89,6 +89,7 @@ function csurf (options) {
// generate & set new secret
if (sec === undefined) {
sec = tokens.secretSync()
sec = setExpirey(sec, cookie)
setSecret(req, res, sessionKey, sec, cookie)
}

Expand All @@ -104,11 +105,12 @@ function csurf (options) {
// generate & set secret
if (!secret) {
secret = tokens.secretSync()
secret = setExpirey(secret, cookie)
setSecret(req, res, sessionKey, secret, cookie)
}

// verify the incoming token
if (!ignoreMethod[req.method] && !tokens.verify(secret, value(req))) {
if (!ignoreMethod[req.method] && (!tokens.verify(secret, value(req)) || !verifyExpiry(secret, cookie))) {
return next(createError(403, 'invalid csrf token', {
code: 'EBADCSRFTOKEN'
}))
Expand Down Expand Up @@ -232,6 +234,25 @@ function getSecretBag (req, sessionKey, cookie) {
}
}

/**
* Set an expirey time on the cookie.
*
* @param {string} val
* @param {Object} [options]
* @api private
*/

function setExpirey (val, options) {
var secret = val
if (options) {
if (options.maxAge) {
var time = ((new Date().getTime() + (options.maxAge * 1000)).toString(21))
secret += ('-' + time)
}
}
return secret
}

/**
* Set a cookie on the HTTP response.
*
Expand All @@ -244,7 +265,6 @@ function getSecretBag (req, sessionKey, cookie) {

function setCookie (res, name, val, options) {
var data = Cookie.serialize(name, val, options)

var prev = res.getHeader('set-cookie') || []
var header = Array.isArray(prev) ? prev.concat(data)
: Array.isArray(data) ? [prev].concat(data)
Expand Down Expand Up @@ -289,6 +309,22 @@ function setSecret (req, res, sessionKey, val, cookie) {
throw new Error('misconfigured csrf')
}
}
/**
* Verify the cookie/token has not expired.
* @private
*/
function verifyExpiry (secret, cookie) {
if (cookie) {
if (cookie.maxAge) {
var index = secret.lastIndexOf('-')
if (index === -1) { return false }
var time = secret.substr(index + 1, secret.length - index)
time = parseInt(time, 21)
return (new Date().getTime()) < time
}
}
return true
}

/**
* Verify the configuration against the request.
Expand Down
39 changes: 34 additions & 5 deletions test/test.js
@@ -1,4 +1,3 @@

process.env.NODE_ENV = 'test'

var assert = require('assert')
Expand Down Expand Up @@ -262,11 +261,11 @@ describe('csurf', function () {

describe('with "ignoreMethods" option', function () {
it('should reject invalid value', function () {
assert.throws(createServer.bind(null, {ignoreMethods: 'tj'}), /option ignoreMethods/)
assert.throws(createServer.bind(null, { ignoreMethods: 'tj' }), /option ignoreMethods/)
})

it('should not check token on given methods', function (done) {
var server = createServer({ignoreMethods: ['GET', 'POST']})
var server = createServer({ ignoreMethods: ['GET', 'POST'] })

request(server)
.get('/')
Expand Down Expand Up @@ -346,7 +345,7 @@ describe('csurf', function () {
})
app.use('/new', function (req, res, next) {
// regenerate session
req.session = {hit: 1}
req.session = { hit: 1 }
next()
})
app.use(function (req, res) {
Expand Down Expand Up @@ -388,6 +387,36 @@ describe('csurf', function () {
.expect(500, /misconfigured csrf/, done)
})
})
describe('when using "maxAge" cookie option', function () {
var server = createServer({ cookie: { maxAge: 3600 } })
it('should work in with valid token', function (done) {
request(server)
.get('/')
.expect(200, function (err, res) {
if (err) return done(err)
var token = res.text
request(server)
.post('/')
.set('Cookie', cookies(res))
.set('csrf-token', token)
.expect(200, done)
})
})
it('should reject expired tokens', function (done) {
var server = createServer({ cookie: { maxAge: -3600 } })
request(server)
.get('/')
.expect(200, function (err, res) {
if (err) return done(err)
var token = res.text
request(server)
.post('/')
.set('Cookie', cookies(res))
.set('csrf-token', token)
.expect(403, done)
})
})
})
})

function cookie (res, name) {
Expand Down Expand Up @@ -415,7 +444,7 @@ function createServer (opts) {
req.query = url.parse(req.url, true).query
next()
})
app.use(bodyParser.urlencoded({extended: false}))
app.use(bodyParser.urlencoded({ extended: false }))
app.use(csurf(opts))

app.use(function (req, res) {
Expand Down

0 comments on commit 4a61106

Please sign in to comment.