Skip to content

Commit

Permalink
backport: hmac key (#132)
Browse files Browse the repository at this point in the history
  • Loading branch information
marco-ippolito authored Apr 20, 2023
1 parent 7534c83 commit 4d95248
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ You can also pass the [cookie serialization](https://github.com/fastify/fastify-
The option `userInfo` is required if `getUserInfo` has been specified in the module option.
The provided `userInfo` is hashed inside the csrf token and it is not directly exposed.
This option is needed to protect against cookie tossing.
The option `csrfOpts.hmacKey` is required if `getUserInfo` has been specified in the module option in combination with using [@fastify/cookie](https://github.com/fastify/fastify-cookie) as sessionPlugin

### `fastify.csrfProtection(request, reply, next)`

Expand Down
5 changes: 5 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ export interface FastifyCsrfOptions {
sessionKey?: string;
getToken?: GetTokenFn;
sessionPlugin?: '@fastify/cookie' | '@fastify/session' | '@fastify/secure-session';
csrfOpts: CSRFOptions;
}

export interface CSRFOptions {
hmacKey: string;
}

declare const fastifyCsrf: FastifyPlugin<FastifyCsrfOptions>;
Expand Down
5 changes: 5 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ async function csrfPlugin (fastify, opts) {
if (opts.getUserInfo) {
csrfOpts.userInfo = true
}

if (sessionPlugin === '@fastify/cookie' && csrfOpts.userInfo) {
assert(csrfOpts.hmacKey, 'csrfOpts.hmacKey is required')
}

const tokens = new CSRF(csrfOpts)

const isCookieSigned = cookieOpts && cookieOpts.signed
Expand Down
1 change: 1 addition & 0 deletions test/index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ async function run () {
const fastify = Fastify()
await fastify.register(FastifyCookie)
await fastify.register(FastifyCsrf)
fastify.register(FastifyCsrf, { csrfOpts: { hmacKey: 'hmac' } })

fastify.route({
method: 'GET',
Expand Down
88 changes: 88 additions & 0 deletions test/user-info.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ test('Cookies with User-Info', async t => {
await fastify.register(fastifyCsrf, {
getUserInfo (req) {
return userInfoDB[req.body.username]
},
csrfOpts: {
hmacKey: 'foo'
}
})

Expand Down Expand Up @@ -73,6 +76,9 @@ test('Session with User-Info', async t => {
sessionPlugin: '@fastify/session',
getUserInfo (req) {
return req.session.username
},
csrfOpts: {
hmacKey: 'foo'
}
})

Expand Down Expand Up @@ -122,6 +128,9 @@ test('SecureSession with User-Info', async t => {
sessionPlugin: '@fastify/secure-session',
getUserInfo (req) {
return req.session.get('username')
},
csrfOpts: {
hmacKey: 'foo'
}
})

Expand Down Expand Up @@ -163,3 +172,82 @@ test('SecureSession with User-Info', async t => {

t.equal(response2.statusCode, 200)
})

test('Validate presence of hmac key with User-Info /1', async (t) => {
const fastify = Fastify()
await fastify.register(fastifyCookie)

await t.rejects(fastify.register(fastifyCsrf, {
getUserInfo (req) {
return req.session.get('username')
}
}), Error('csrfOpts.hmacKey is required'))
})

test('Validate presence of hmac key with User-Info /2', async (t) => {
const fastify = Fastify()
await fastify.register(fastifyCookie)

await t.rejects(fastify.register(fastifyCsrf, {
getUserInfo (req) {
return req.session.get('username')
},
sessionPlugin: '@fastify/cookie'
}), Error('csrfOpts.hmacKey is required'))
})

test('Validate presence of hmac key with User-Info /3', async (t) => {
const fastify = Fastify()
await fastify.register(fastifyCookie)

await t.rejects(fastify.register(fastifyCsrf, {
getUserInfo (req) {
return req.session.get('username')
},
csrfOpts: {
hmacKey: undefined
}
}), Error('csrfOpts.hmacKey is required'))
})

test('Validate presence of hmac key with User-Info /4', async (t) => {
const fastify = Fastify()
await fastify.register(fastifyCookie)

await t.rejects(fastify.register(fastifyCsrf, {
getUserInfo (req) {
return req.session.get('username')
},
sessionPlugin: '@fastify/cookie',
csrfOpts: {
hmacKey: undefined
}
}), Error('csrfOpts.hmacKey is required'))
})

test('Validate presence of hmac key with User-Info /5', async (t) => {
const fastify = Fastify()
await fastify.register(fastifySecureSession, { key, cookie: { path: '/', secure: false } })

await t.resolves(fastify.register(fastifyCsrf, {
getUserInfo (req) {
return req.session.get('username')
},
sessionPlugin: '@fastify/secure-session'
}))
})

test('Validate presence of hmac key with User-Info /6', async (t) => {
const fastify = Fastify()
await fastify.register(fastifySecureSession, { key, cookie: { path: '/', secure: false } })

await t.resolves(fastify.register(fastifyCsrf, {
getUserInfo (req) {
return req.session.get('username')
},
sessionPlugin: '@fastify/secure-session',
csrfOpts: {
hmacKey: 'foo'
}
}))
})

0 comments on commit 4d95248

Please sign in to comment.