From dafc538920596083ac180c19700cd5acab4e49e9 Mon Sep 17 00:00:00 2001 From: Lars <32460418+advename@users.noreply.github.com> Date: Wed, 9 Oct 2024 11:33:11 +0200 Subject: [PATCH] Update Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md (#1513) --- .../Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md b/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md index 9b6a439006..cfa11ec36b 100644 --- a/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md +++ b/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md @@ -78,8 +78,8 @@ We strongly recommend that you use the Hash-based Message Authentication (HMAC) To generate HMAC CSRF tokens (with a session-dependent user value), the system must have: -- **A session-dependent value that changes with each login session**. This value should only be valid for the entirety of the users authenticated session. Avoid using static values like the user's email or ID, as they are not secure ([1](https://stackoverflow.com/a/8656417) | [2](https://stackoverflow.com/a/30539335) | [3](https://security.stackexchange.com/a/22936)). It's worth noting that updating the CSRF token too frequently, such as for each request, is a misconception that assumes it adds substantial security while actually harming the user experience ([1](https://security.stackexchange.com/a/22936)). For example, you could choose one of the following session-dependent values: - - The server-side session ID (e.g. [PHP](https://www.php.net/manual/en/function.session-start.php) or [ASP.NET]()). +- **A session-dependent value that changes with each login session**. This value should only be valid for the entirety of the users authenticated session. Avoid using static values like the user's email or ID, as they are not secure ([1](https://stackoverflow.com/a/8656417) | [2](https://stackoverflow.com/a/30539335) | [3](https://security.stackexchange.com/a/22936)). It's worth noting that updating the CSRF token too frequently, such as for each request, is a misconception that assumes it adds substantial security while actually harming the user experience ([1](https://security.stackexchange.com/a/22936)). For example, you could choose one, or a combination, of the following session-dependent values: + - The server-side session ID (e.g. [PHP](https://www.php.net/manual/en/function.session-start.php) or [ASP.NET]()). This value should never leave the server or be in plain text in the CSRF Token. - A random value (e.g. UUID) within a JWT that changes every time a JWT is created. - **A secret cryptographic key** Not to be confused with the random value from the naive implementation. This value is used to generate the HMAC hash. Ideally, store this key as discussed in the [Cryptographic Storage page](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#key-storage). - **A random value for anti-collision purposes**. Generate a random value (preferably cryptographically random) to ensure that consecutive calls within the same second do not produce the same hash ([1](https://github.com/data-govt-nz/ckanext-security/issues/23#issuecomment-479752531)). @@ -101,7 +101,7 @@ randomValue = cryptographic.randomValue() // Cryptographic random value // Create the CSRF Token message = sessionID + "!" + randomValue // HMAC message payload hmac = hmac("SHA256", secret, message) // Generate the HMAC hash -csrfToken = hmac + "." + message // Combine HMAC hash with message to generate the token. The plain message is required to later authenticate it against its HMAC hash +csrfToken = hmac + "." + randomValue // Add the `randomValue` to the HMAC hash to create the final CSRF token. Avoid using the `message` because it contains the sessionID in plain text, which the server already stores separately. // Store the CSRF Token in a cookie response.setCookie("csrf_token=" + csrfToken + "; Secure") // Set Cookie without HttpOnly flag