Crypto on the Web

Billions of people use cryptography on a daily basis without realising it. The 2010s saw the widespread adoption of encryption on the web, accelerated by the Snowden disclosures: in 2015, 30% of pages loaded on Android were protected by Transport Layer Security (TLS), but by 2020, it was 90%. Alongside TLS, major websites employ hash functions for password storage, signed tokens for authorisation, and complex protocols for handling payment-card data.

However, as we've seen from other categories, cryptography is full of subtleties, and teams building web apps often get it wrong. This highly practical category explores common ways that cryptography is used in web apps, together with devastating implementation errors that are seen in the real world.

JSON Web Tokens

  • Token Appreciation
    5 pts · 1601 Solves

    JavaScript Object Signing and Encryption (JOSE) is a framework specifying ways to securely transmit information on the internet. It's most well-known for JSON Web Tokens (JWTs), which are used to authorise yourself on a website or application. JWTs typically do this by storing your "login session" in your browser after you have authenticated yourself by entering your username and password. In other words, the website gives you a JWT that contains your user ID, and can be presented to the site to prove who you are without logging in again. JWTs look like this:


    You can recognise it because it's base64-encoded data split into three parts (separated by a .): the header, the payload, and the signature. In fact, it's a variant of base64 encoding, where the + and / have been replaced by different special characters since they can cause issues in URLs.

    Some developers believe that the JWT encoding is like encryption, so they put sensitive data inside the tokens. To prove them wrong, decode the JWT above to find the flag. There are online tools to do this quickly, but working with Python's PyJWT library will prepare you best for future challenges.

    You must be logged in to submit your flag.

  • JWT Sessions
    10 pts · 1303 Solves

    The traditional way to store sessions is with session ID cookies. After you login to a website, a session object is created for you on the backend (the server), and your browser (the client) is given a cookie which identifies that object. As you make requests to the site, your browser automatically sends the session ID cookie to the backend server, which uses that ID to find your session in its own memory and thus authorise you to perform actions.

    JWTs work differently. After you login, the server sends your web browser the whole session object in a JWT, containing a payload of key-value pairs describing your username, privileges, and other info. Also included is a signature created using the server's secret key, designed to prevent you from tampering with the payload. Your web browser saves the token into local storage.

    diagram showing JWT usage

    On subsequent requests, your browser sends the token to the backend server. The server verifies the signature first, and then reads the token payload to authorise you.

    To summarise, with session ID cookies, sessions live on the server, but with JWTs, sessions live on the client.

    The main advantage of JWTs over session ID cookies is that they are easy to scale. Organisations need a way to share sessions across multiple backend servers. When a client switches from using one server or resource to another, that client's session should still work. Furthermore, for large orgs there could be millions of sessions. Since JWTs live on the client, they solve these problems: any backend server can authorise a user just by checking the signature on the token and reading the data inside.

    Unfortunately there are some downsides to JWTs, as they are often configured in an insecure way, and clients are free to modify them and see if the server will still verify them. We'll look at these exploits in the next challenges. For now, the flag is the name of the HTTP header used by the browser to send JWTs to the server.

    You must be logged in to submit your flag.

  • No Way JOSE
    20 pts · 1041 Solves · 4 Solutions

    Let's look at JWT algorithms. The first part of a JWT is the JOSE header, and when you decode it, looks like this:


    This tells the server it's a JWT and which algorithm to use to verify it. Can you see the issue here? The server has to process this untrusted input before it is actually able to verify the integrity of the token! In ideal cryptographic protocols, you verify messages you receive before performing any further operations on them, otherwise in Moxie Marlinspike's words, "it will somehow inevitably lead to doom".

    The "none" algorithm in JWTs is a case in point. The link below takes you to a page where you can interact with a broken session API, which emulates a vulnerability that existed in a lot of JWT libraries. Use it to bypass authorisation and get the flag.

    Play at

    You must be logged in to submit your flag.

  • JWT Secrets
    25 pts · 954 Solves · 3 Solutions

    The most common signing algorithms used in JWTs are HS256 and RS256. The first is a symmetric signing scheme using a HMAC with the SHA256 hash function. The second is an asymmetric signing scheme based on RSA.

    A lot of guides on the internet recommend using HS256 as it's more straightforward. The secret key used to sign a token is the same as the key used to verify it.

    However, if the signing secret key is compromised, an attacker can sign arbitrary tokens and forge sessions of other users, potentially causing total compromise of a webapp. HS256 makes the secret key harder to secure than an asymmetric keypair, as the key must be available on all servers that verify HS256 tokens (unless better infrastructure with a separate token verifying service is in place, which usually isn't the case). In contrast, with the asymmetric scheme of RS256, the signing key can be better protected while the verifying key is distributed freely.

    Even worse, developers sometimes use a default or weak HS256 secret key.

    Here is a snippet of source code with one function to create a session and another function to authorise a session and check for admin permissions. But there's a strange comment about the secret key. What are you going to do?

    Play at

    You must be logged in to submit your flag.

  • RSA or HMAC?
    35 pts · 714 Solves · 6 Solutions

    There's another issue caused by allowing attackers to specify their own algorithms but not carefully validating them. Attackers can mix and match the algorithms that are used to sign and verify data. When one of these is a symmetric algorithm and one is an asymmetric algorithm, this creates a beautiful vulnerability.

    We're using PyJWT version 1.5.0 for this challenge to allow the exploit, since later versions of the library have fixed it. To create the signature, you may need to patch or downgrade your PyJWT library too.

    Play at

    You must be logged in to submit your flag.

  • JSON in JSON
    40 pts · 623 Solves · 6 Solutions

    We've explored how flawed verification can break the security of JWTs, but it can sometimes be possible to exploit the code to sign unexpected data in the first place.

    Play at

    Challenge contributed by sublevel_1157

    You must be logged in to submit your flag.

  • RSA or HMAC? Part 2
    100 pts · 154 Solves · 4 Solutions

    It is possible to abuse JWT public keys without the public key being public? This challenge takes RSA or HMAC one step further, and now both a deeper knowledge of RSA maths and data formatting is involved. It's more realistic than the first part as web apps usually won't have a route disclosing their public key.

    If you are attempting to implement the solution yourself (which is recommended over using a public script!), but the signature is not validating, take care that your formatting is 100% correct. We've added to the source the commands used to generate the private and public keys.

    We're using PyJWT version 1.5.0 for this challenge to allow the exploit, since later versions of the library have fixed it. To create the signature, you may need to patch or downgrade your PyJWT library too.

    Play at

    You must be logged in to submit your flag.

Level Up

level up icon

You are now level Current level