@@ -92,6 +92,18 @@ const generateSecret = () => {
92
92
) ;
93
93
} ;
94
94
95
+ // Creates a cookie like 'next-auth.csrf-token' with the value 'token|hash',
96
+ // where 'token' is the CSRF token and 'hash' is a hash made of the token and
97
+ // the secret, and the two values are joined by a pipe '|'. By storing the
98
+ // value and the hash of the value (with the secret used as a salt) we can
99
+ // verify the cookie was set by the server and not by a malicous attacker.
100
+ const generateNewCookieToken = ( csrfToken ) => {
101
+ return `${ csrfToken } |${ createHash ( "sha256" )
102
+ . update ( `${ csrfToken } ${ generateSecret ( ) } ` )
103
+ . digest ( "hex" ) } `;
104
+ } ;
105
+
106
+ // Parses token and hash generated by generateNewCookieToken.
95
107
const parseTokenFromPostRequestCookies = ( req ) => {
96
108
let value , hash ;
97
109
if ( req . cookies [ cookie . metadata ( ) . csrfToken . name ] ) {
@@ -102,35 +114,28 @@ const parseTokenFromPostRequestCookies = (req) => {
102
114
103
115
/**
104
116
* validateCsrfToken
105
- * Function to verify a csrf token based on code from `next-auth`
106
- * and modified for our purposes:
117
+ * Function to verify a csrf token once upon a time based on code from
118
+ * `next-auth` and modified for our purposes, now heavily refacotred :
107
119
* https://github.com/nextauthjs/next-auth/blob/main/src/server/index.js
108
- * Most comments are kept in place but some were added for clarity.
120
+ *
121
+ * For more details, see the following OWASP links:
122
+ * https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie
123
+ * https://owasp.org/www-chapter-london/assets/slides/David_Johansson-Double_Defeat_of_Double-Submit_Cookie.pdf
109
124
*/
110
125
const validateCsrfToken = ( req ) => {
111
- const tokenValueFromPostRequestBody = req . body ?. csrfToken ;
126
+ const tokenFromRequestBody = req . body ?. csrfToken ;
112
127
const tokenFromRequestCookie = parseTokenFromPostRequestCookies ( req ) ;
113
- // Ensure CSRF Token cookie is set for any subsequent requests.
114
- // Used as part of the strategy for mitigation for CSRF tokens.
115
- //
116
- // Creates a cookie like 'next-auth.csrf-token' with the value 'token|hash',
117
- // where 'token' is the CSRF token and 'hash' is a hash made of the token and
118
- // the secret, and the two values are joined by a pipe '|'. By storing the
119
- // value and the hash of the value (with the secret used as a salt) we can
120
- // verify the cookie was set by the server and not by a malicous attacker.
121
- //
122
- // For more details, see the following OWASP links:
123
- // https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie
124
- // https://owasp.org/www-chapter-london/assets/slides/David_Johansson-Double_Defeat_of_Double-Submit_Cookie.pdf
125
128
126
129
if ( postRequestHashMatchesServerHash ( tokenFromRequestCookie ) ) {
127
130
return (
128
131
req . method === "POST" &&
129
- tokenFromRequestCookie . value === tokenValueFromPostRequestBody
132
+ tokenFromRequestCookie . value === tokenFromRequestBody
130
133
) ;
131
134
} else return false ;
132
135
} ;
133
136
137
+ // Validate that the token value from the request cookies generates what the
138
+ // server knows to be a valid hash
134
139
const postRequestHashMatchesServerHash = ( tokenFromRequestCookie ) => {
135
140
return (
136
141
tokenFromRequestCookie . hash ===
@@ -140,6 +145,8 @@ const postRequestHashMatchesServerHash = (tokenFromRequestCookie) => {
140
145
) ;
141
146
} ;
142
147
148
+ // Ensure CSRF Token cookie is set for any subsequent requests.
149
+ // Used as part of the strategy for mitigation for CSRF tokens.
143
150
const setCsrfTokenCookie = ( res , csrfToken ) => {
144
151
const newCsrfTokenCookie = generateNewCookieToken ( csrfToken ) ;
145
152
cookie . set (
@@ -154,15 +161,6 @@ const generateNewToken = () => {
154
161
return randomBytes ( 32 ) . toString ( "hex" ) ;
155
162
} ;
156
163
157
- const generateNewCookieToken = ( csrfToken ) => {
158
- // If there is no csrfToken because it's not been set yet or because
159
- // the hash doesn't match (e.g. because it's been modified or because the
160
- // secret has changed), then create a new token and create a cookie.
161
- return `${ csrfToken } |${ createHash ( "sha256" )
162
- . update ( `${ csrfToken } ${ generateSecret ( ) } ` )
163
- . digest ( "hex" ) } `;
164
- } ;
165
-
166
164
export {
167
165
redirectIfUserHasRegistered ,
168
166
homePageRedirect ,
0 commit comments