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

Add support for cookie.secure === 'auto' #242

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ following keys:
- `path` - the path of the cookie (defaults to `'/'`).
- `signed` - indicates if the cookie should be signed (defaults to `false`).
- `secure` - marks the cookie to be used with HTTPS only (defaults to
`false`).
`false`). If set to ``'auto'`, HTTPS will be detected via the `x-forwarded-proto`
header, similar to [express-session](https://expressjs.com/en/resources/middleware/session.html#cookiesecure).
- `maxAge` - the number of seconds after which the cookie will expire
(defaults to session length).
- `httpOnly` - flags the cookie to be accessible only by the web server
Expand Down
12 changes: 10 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,14 +235,22 @@ function getSecretBag (req, sessionKey, cookie) {
/**
* Set a cookie on the HTTP response.
*
* @param {IncomingMessage} req
* @param {OutgoingMessage} res
* @param {string} name
* @param {string} val
* @param {Object} [options]
* @api private
*/

function setCookie (res, name, val, options) {
function setCookie (req, res, name, val, options) {
// Set by most proxies, allows us to auto-detect if we should set 'secure'
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto
if (options.secure === 'auto') {
var isSecure = Boolean(req.headers &&
req.headers['x-forwarded-proto'] === 'https');
options = Object.assign({}, options, {secure: isSecure})
}
var data = Cookie.serialize(name, val, options)

var prev = res.getHeader('set-cookie') || []
Expand Down Expand Up @@ -272,7 +280,7 @@ function setSecret (req, res, sessionKey, val, cookie) {
value = 's:' + sign(val, req.secret)
}

setCookie(res, cookie.key, value, cookie)
setCookie(req, res, cookie.key, value, cookie)
} else {
// set secret on session
req[sessionKey].csrfSecret = val
Expand Down
109 changes: 109 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,115 @@ describe('csurf', function () {
.expect(500, /misconfigured csrf/, done)
})
})

describe('when "secure": true', function () {
it('should add Secure', function (done) {
var server = createServer({ cookie: { secure: true } })

request(server)
.get('/')
.expect(200, function (err, res) {
if (err) return done(err)
var data = cookie(res, '_csrf')
var token = res.text

assert.ok(Boolean(data))
assert.ok(/^_csrf=[\w-_]+/i.test(data))
assert.ok(/Secure/.test(data))

request(server)
.post('/')
.set('Cookie', cookies(res))
.set('X-CSRF-Token', token)
.expect(200, done)
})
})
})

describe('when "secure": "auto"', function () {
it('should add Secure when x-forwarded-proto: "https"', function (done) {
var server = createServer({ cookie: { secure: 'auto' } })

request(server)
.get('/')
.set('x-forwarded-proto', 'https')
.expect(200, function (err, res) {
if (err) return done(err)
var data = cookie(res, '_csrf')

assert.ok(Boolean(data))
assert.ok(/^_csrf=[\w-_]+/i.test(data))
assert.ok(/Secure/.test(data))

done()
})
})

it('should not add Secure for http', function (done) {
var server = createServer({ cookie: { secure: 'auto' } })

request(server)
.get('/')
.set('x-forwarded-proto', 'http')
.expect(200, function (err, res) {
if (err) return done(err)
var data = cookie(res, '_csrf')

assert.ok(Boolean(data))
assert.ok(/^_csrf=[\w-_]+/i.test(data))
assert.equal(/Secure/.test(data), false)

done()
})
})

it('should not add Secure otherwise', function (done) {
var server = createServer({ cookie: { secure: 'auto' } })

request(server)
.get('/')
.expect(200, function (err, res) {
if (err) return done(err)
var data = cookie(res, '_csrf')

assert.ok(Boolean(data))
assert.ok(/^_csrf=[\w-_]+/i.test(data))
assert.equal(/Secure/.test(data), false)

done()
})
})

it('setting is not sticky and can change between requests', function (done) {
var server = createServer({ cookie: { secure: 'auto' } })

request(server)
.get('/')
.set('x-forwarded-proto', 'https')
.expect(200, function (err, res) {
if (err) return done(err)
var data = cookie(res, '_csrf')

assert.ok(Boolean(data))
assert.ok(/^_csrf=[\w-_]+/i.test(data))
assert.ok(/Secure/.test(data))

// Note header not present
request(server)
.get('/')
.expect(200, function (err, res) {
if (err) return done(err)
var data = cookie(res, '_csrf')

assert.ok(Boolean(data))
assert.ok(/^_csrf=[\w-_]+/i.test(data))
assert.equal(/Secure/.test(data), false)

done()
})
})
})
})
})
})

Expand Down