WIP
This commit is contained in:
parent
ea9c1a453d
commit
7a0820bf89
@ -15,7 +15,7 @@ import io.jsonwebtoken.Jwts;
|
|||||||
* @since 4/23/17.
|
* @since 4/23/17.
|
||||||
*/
|
*/
|
||||||
@AssignmentPath("/JWT/secret")
|
@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 {
|
public class JWTSecretKeyEndpoint extends AssignmentEndpoint {
|
||||||
|
|
||||||
private static final String JWT_SECRET = "victory";
|
private static final String JWT_SECRET = "victory";
|
||||||
|
@ -101,4 +101,72 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="lesson-page-wrapper">
|
||||||
|
<div class="adoc-content" th:replace="doc:JWT_refresh.adoc"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="lesson-page-wrapper">
|
||||||
|
<div class="adoc-content" th:replace="doc:JWT_refresh_assignment"></div>
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/jwt.css}"/>
|
||||||
|
<script th:src="@{/lesson_js/bootstrap.min.js}" language="JavaScript"></script>
|
||||||
|
<script th:src="@{/lesson_js/jwt-signing.js}" language="JavaScript"></script>
|
||||||
|
<div class="attack-container">
|
||||||
|
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||||
|
<form class="attack-form" accept-charset="UNKNOWN"
|
||||||
|
method="POST"
|
||||||
|
successCallback="jwtSigningCallback"
|
||||||
|
action="/WebGoat/JWT/refresh/reset"
|
||||||
|
enctype="application/json;charset=UTF-8">
|
||||||
|
<div class="container-fluid">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="well">
|
||||||
|
<div class="pull-right">
|
||||||
|
<div class="dropdown">
|
||||||
|
<button type="button" data-toggle="dropdown" class="btn btn-default dropdown-toggle"
|
||||||
|
title="Change user">
|
||||||
|
<i class="fa fa-user"></i> <span class="caret"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-left">
|
||||||
|
<li role="presentation"><a role="menuitem" tabindex="-1"
|
||||||
|
onclick="javascript:login('Guest')"
|
||||||
|
th:text="Guest">current</a></li>
|
||||||
|
<li role="presentation"><a role="menuitem" tabindex="-1"
|
||||||
|
onclick="javascript:login('Tom')"
|
||||||
|
th:text="Tom">current</a></li>
|
||||||
|
<li role="presentation"><a role="menuitem" tabindex="-1"
|
||||||
|
onclick="javascript:login('Jerry')"
|
||||||
|
th:text="Jerry">current</a></li>
|
||||||
|
<li role="presentation"><a role="menuitem" tabindex="-1"
|
||||||
|
onclick="javascript:login('Sylvester')"
|
||||||
|
th:text="Sylvester">current</a></li>
|
||||||
|
</ul>
|
||||||
|
<button type="button" class="btn btn-default fa fa-refresh" title="Refresh votes"
|
||||||
|
onclick="javascript:getVotings()"/>
|
||||||
|
<button type="submit" class="btn btn-default fa fa-trash-o" title="Reset votes"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-right">Welcome back, <b><span id="name"></span></b></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3>Vote for your favorite</h3>
|
||||||
|
</div>
|
||||||
|
<div id="votesList" class="list-group">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<div class="attack-feedback"></div>
|
||||||
|
<div class="attack-output"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -9,3 +9,7 @@ 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-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-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
|
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
|
||||||
|
@ -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
|
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 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
|
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.
|
below can find a couple of points to keep in mind while choosing which tokens to use.
|
||||||
|
|
||||||
So a normal flow can look like:
|
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)
|
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
|
With storing you can match the refresh token to the specific user the refresh token was granted to.
|
||||||
granted to. So in this case whenever the access token is still valid we can speak of a "stateless" session, there is
|
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.
|
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
|
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.
|
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
|
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.
|
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
|
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.
|
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
|
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.
|
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
|
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
|
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).
|
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
|
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
|
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)
|
(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
|
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.
|
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
|
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.
|
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
|
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
|
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.
|
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
|
||||||
|
|
||||||
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).
|
use a hash function to store them in your database).
|
||||||
Another check is to make use there is only one access token
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
|
@ -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
|
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]
|
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]
|
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
|
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.
|
for signing the token.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user