From 7a0820bf89304b6761445fe2af1333f97123136b Mon Sep 17 00:00:00 2001 From: Nanne Baars Date: Wed, 16 May 2018 12:39:23 +0200 Subject: [PATCH] WIP --- .../webgoat/plugin/JWTSecretKeyEndpoint.java | 2 +- .../jwt/src/main/resources/html/JWT.html | 68 +++++++++++++++++++ .../resources/i18n/WebGoatLabels.properties | 6 +- .../resources/lessonPlans/en/JWT_refresh.adoc | 16 ++--- .../en/JWT_refresh_assignment.adoc | 8 +++ .../resources/lessonPlans/en/JWT_signing.adoc | 1 - 6 files changed, 86 insertions(+), 15 deletions(-) create mode 100644 webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_refresh_assignment.adoc diff --git a/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTSecretKeyEndpoint.java b/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTSecretKeyEndpoint.java index ec99d43b5..1ce27e416 100644 --- a/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTSecretKeyEndpoint.java +++ b/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTSecretKeyEndpoint.java @@ -15,7 +15,7 @@ import io.jsonwebtoken.Jwts; * @since 4/23/17. */ @AssignmentPath("/JWT/secret") -@AssignmentHints({"jwt-secret-hint1", "jwt-secret-hint2", "jwt-secret-hint3", "jwt-secret-hint4", "jwt-secret-hint5"}) +@AssignmentHints({"jwt-secret-hint1", "jwt-secret-hint2", "jwt-secret-hint3"}) public class JWTSecretKeyEndpoint extends AssignmentEndpoint { private static final String JWT_SECRET = "victory"; diff --git a/webgoat-lessons/jwt/src/main/resources/html/JWT.html b/webgoat-lessons/jwt/src/main/resources/html/JWT.html index ff4c17f03..e50b9a405 100644 --- a/webgoat-lessons/jwt/src/main/resources/html/JWT.html +++ b/webgoat-lessons/jwt/src/main/resources/html/JWT.html @@ -101,4 +101,72 @@ +
+
+
+ +
+
+ + + + +
+
+
+
+ +
+ +
+
+ +
+

Welcome back,

+
+
+ +
+

Vote for your favorite

+
+
+ +
+
+
+
+
+ +
+
+
+
+
+ \ No newline at end of file diff --git a/webgoat-lessons/jwt/src/main/resources/i18n/WebGoatLabels.properties b/webgoat-lessons/jwt/src/main/resources/i18n/WebGoatLabels.properties index 214fa1c5d..3137cc27b 100644 --- a/webgoat-lessons/jwt/src/main/resources/i18n/WebGoatLabels.properties +++ b/webgoat-lessons/jwt/src/main/resources/i18n/WebGoatLabels.properties @@ -8,4 +8,8 @@ jwt-change-token-hint1=Select a different user and look at the token you receive jwt-change-token-hint2=Decode the token and look at the contents jwt-change-token-hint3=Change the contents of the token and replace the cookie before sending the request for getting the votes jwt-change-token-hint4=Change the admin field to true in the token -jwt-change-token-hint5=Submit the token by changing the algorithm to None and remove the signature \ No newline at end of file +jwt-change-token-hint5=Submit the token by changing the algorithm to None and remove the signature + +jwt-secret-hint1=Save the token and try to verify the token locally +jwt-secret-hint2=Download a word list dictionary (https://github.com/first20hours/google-10000-english) +jwt-secret-hint3=Write a small program or use HashCat for brute forcing the token according the word list diff --git a/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_refresh.adoc b/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_refresh.adoc index 5068626ec..8b11093dc 100644 --- a/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_refresh.adoc +++ b/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_refresh.adoc @@ -10,7 +10,7 @@ In general there are two type of tokens: access token and a refresh token. The a calls towards the server. Access tokens have a limited life span, that's where the refresh token comes in. Once the access token is no longer valid a request can me made towards the server to get a new access token by presenting the refresh token. The refresh token can expire but their life span is much longer. This solves the problem of a user -having to authenticate again with their credentials. Whether you should use a refresh token and access token depends +having to authenticate again with their credentials. Whether you should use a refresh token and access token depends, below can find a couple of points to keep in mind while choosing which tokens to use. So a normal flow can look like: @@ -31,18 +31,16 @@ The server returns: ``` As you can see the refresh token is a random string which the server can keep track of (in memory or store in a database) -With storing the information you can match the refresh token to the specific user to which the refresh token was -granted to. So in this case whenever the access token is still valid we can speak of a "stateless" session, there is +With storing you can match the refresh token to the specific user the refresh token was granted to. +So in this case whenever the access token is still valid we can speak of a "stateless" session, there is no burden on the server side to setup the user session, the token is self contained. When the access token is no longer valid the server needs to query for the stored refresh token to make sure the token is not blocked in any way. Whenever the attacker gets a hold on an access token it is only valid for a certain amount of time (say 10 minutes). The attacker then needs the refresh token to get a new access token. That is why the refresh token needs better protection. - It is also possible to make the refresh token stateless but this means it will become more difficult to see if the user revoked the tokens. - After the server made all the validations it must return a new refresh token and a new access token to the client. The client can use the new access token to make the API call. @@ -53,11 +51,9 @@ Regardless of the chosen solution you should store enough information on the ser is still trusted. You can think of many things, like store the ip address, keep track of how many times the refresh token is used (using the refresh token multiple times in the valid time window of the access token might indicate strange behavior, you can revoke all the tokens an let the user authenticate again). - It is also a good to keep track of which access token belonged to which refresh token. Otherwise an attacker might be able to get a new access token for a different user with the refresh token of the attacker (see https://emtunc.org/blog/11/2017/jwt-refresh-token-manipulation/ for a nice write up about how this attack works) - Also a good thing to check for is the ip address or geolocation of the user. If you need to give out a new token check whether the location is still the same if not revoke all the tokens and let the user authenticate again. @@ -72,14 +68,10 @@ server you can chose to only use the access token. As stated above using an access token and a separate refresh token gives some leverage for the server not to check the access token over and over. Only perform the check when the user needs a new access token. - It is certainly possible to only use an access token, at the server you store the exact same information you would store for a refresh token, see previous paragraph. This way you need to check the token each time but this might -be suitable depending on the application. - -In the case the refresh tokens are stored for validation it is important to protect these tokens as well (at least +be suitable depending on the application. In the case the refresh tokens are stored for validation it is important to protect these tokens as well (at least use a hash function to store them in your database). -Another check is to make use there is only one access token diff --git a/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_refresh_assignment.adoc b/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_refresh_assignment.adoc new file mode 100644 index 000000000..8690dd64d --- /dev/null +++ b/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_refresh_assignment.adoc @@ -0,0 +1,8 @@ +== Refreshing a token + +=== Assignment + +In this assignment Tom no longer has a valid token, try to find a way to create a new access token and use that token +to vote. + + diff --git a/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_signing.adoc b/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_signing.adoc index 16e48409e..12bdc93a9 100644 --- a/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_signing.adoc +++ b/webgoat-lessons/jwt/src/main/resources/lessonPlans/en/JWT_signing.adoc @@ -3,7 +3,6 @@ Each JWT token should at least be signed before sending it to a client, if a token is not signed the client application would be able to change the contents of the token. The signing specifications are defined https://tools.ietf.org/html/rfc7515[here] the specific algorithms you can use are described https://tools.ietf.org/html/rfc7518[here] - It basically comes down you use "HMAC with SHA-2 Functions" or "Digital Signature with RSASSA-PKCS1-v1_5/ECDSA/RSASSA-PSS" function for signing the token.