Top 3 security best practices for handling JWTs
December 18, 2023
0 mins readIn modern web development, JSON Web Tokens (JWTs) have become a popular method of securely transmitting information between parties. JWTs are used for authentication and authorization and are often used to store user information. However, with the increasing use of JWTs come potential security risks that developers need to be aware of.
As a developer, you are responsible for ensuring that your application is secure and user data is protected. In this blog post, we will discuss the top three security best practices for handling JWTs. We will also provide practical examples using Python and show how Snyk can help you identify and remediate security vulnerabilities in your application.
By the end of this blog post, you will have a better understanding of how to handle JWTs securely in your applications and the importance of using tools like Snyk to ensure your code is secure. Let's get started!
Best practice #1: Keep JWTs secret
JWTs are widely used in modern web applications for authentication and authorization purposes. However, if not handled properly, JWTs can pose a significant security risk to your application. In this section, we'll discuss the importance of keeping JWTs secret and how to achieve that.
Why keeping JWTs secret is important
JWTs are essentially signed JSON objects that contain information about a user. This information can include sensitive data such as user IDs, roles, and permissions. If an attacker gets hold of a JWT, they can use it to impersonate the user and gain unauthorized access to your application.
Therefore, it's crucial to keep JWTs secret and ensure that only authorized parties can access them. When thinking about the secrecy of JWTs, think about session cookies in a traditional web application: if an attacker can steal your cookies, they can easily imitate you and wreak havoc!
How to keep JWTs secret
The first step in keeping JWTs secret is to ensure that they are transmitted securely over the network. This can be achieved by using HTTPS for all communication between the client and server.
The second step is to store JWTs securely on the client side. One way to achieve this is by using HttpOnly
and Secure
flags when sending cookies to the client. The HttpOnly
flag prevents client-side scripts from accessing the cookie, while the Secure
flag ensures that the cookie is only transmitted over HTTPS.
Another way to store JWTs securely is by using browser storage mechanisms such as sessionStorage
or localStorage
. These mechanisms provide a way to store data in the browser that is inaccessible to other domains. Although… tread carefully. If your JWTs are stored in either sessionStorage
or localStorage
, this means they’ll be accessible to JavaScript code, which means you need to carefully evaluate your website to ensure you aren’t susceptible to cross-site scripting (XSS) attacks, which would potentially allow attackers to compromise your JWTs.
Finally, it's essential to ensure that JWTs are properly validated on the server side. This includes checking the signature and verifying the contents of the token.
Practical example of how Snyk can find security issues related to keeping JWTs secret
Snyk is a developer security tool that can help you identify security issues related to JWTs. For example, Snyk can detect whether your application is using weak encryption algorithms or not using HttpOnly
or Secure
flags when sending cookies to the client.
Let's take a look at an example code snippet in Python:
1from flask import Flask, jsonify, request
2from flask_jwt_extended import JWTManager, jwt_required, create_access_token
3
4app = Flask(__name__)
5
6app.config['JWT_SECRET_KEY'] = 'super-secret' # Keep your secret key safe and make sure it’s unique!
7jwt = JWTManager(app)
8
9@app.route('/login', methods=['POST'])
10def login():
11 username = request.json.get('username')
12 password = request.json.get('password')
13
14 # Check if the username and password are valid
15 # ...
16
17 # If the user is authenticated, create a JWT
18 access_token = create_access_token(identity=username)
19
20 return jsonify({'access_token': access_token}), 200
21
22@app.route('/protected', methods=['GET'])
23@jwt_required
24def protected():
25 return jsonify({'message': 'You are authorized!'}), 200
26
27if __name__ == '__main__':
28 app.run()
In this example, we're using the Flask-JWT-Extended
library to create and verify JWTs. However, Snyk can detect if we're using insecure encryption algorithms or not properly validating the JWTs on the server side.
By using a tool like Snyk, you can ensure that your application is secure and that your JWTs are kept secret.
Best practice #2: Validate JWTs
As mentioned in the previous section, JWTs are used for authentication and authorization, and their compromise can lead to security breaches. Therefore, it is essential to validate the JWTs before trusting them.
Importance of validating JWTs
Validating JWTs ensures that the incoming request is from an authenticated and authorized user. It confirms that the token has not expired or been tampered with, and was signed by the party who issued it. If the JWT is not validated correctly, it can lead to security vulnerabilities, such as unauthorized access and data breaches.
How to validate JWTs
To validate JWTs, the following steps need to be performed:
Parse the JWT to extract the header, payload, and signature.
Verify the signature using the secret key or public key.
Check the expiration time (
exp
) and the not-before time (nbf
) claims to ensure the JWT is valid.Verify the issuer (
iss
) claim to ensure the JWT was issued by a trusted party.Verify the audience (
aud
) claim to ensure the JWT is intended for the correct recipient.
Python provides several libraries to validate JWTs — such as PyJWT, a Python implementation of the JWT standard. Below is an example of how to validate a JWT using PyJWT:
1import jwt
2
3token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyMzkwMjJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
4
5try:
6 decoded_token = jwt.decode(token, 'secret', algorithms=['HS256'], options={"verify_exp": True, "verify_iss": True, "verify_aud": True})
7 print(decoded_token)
8except jwt.ExpiredSignatureError:
9 print("Token has expired")
10except jwt.InvalidIssuerError:
11 print("Invalid issuer")
12except jwt.InvalidAudienceError:
13 print("Invalid audience")
14except jwt.InvalidTokenError:
15 print("Invalid token")
In the above example, the jwt.decode()
method is used to decode and validate the token. The algorithms
parameter specifies which algorithms should be used to verify the signature. The options
parameter specifies the additional checks to be performed, such as verifying the expiration time, issuer, and audience.
Practical example of how Snyk can find security issues related to validating JWTs
Snyk provides a comprehensive security scanning tool that can detect security issues related to validating JWTs. For example, Snyk can scan the codebase for insecure JWT validation practices, such as using an insecure algorithm or not verifying the issuer or audience claims. Snyk can also detect vulnerabilities in the third-party libraries used for JWT validation.
By using Snyk, developers can ensure that their codebase is free from security vulnerabilities related to JWT validation. To get started with Snyk, developers can sign up for a free account and integrate it into their development workflow.
Best practice #3: Set expiration time on JWTs
JWTs are widely used in modern web applications as a way to securely transmit information between parties. However, if not properly secured, JWTs can lead to security vulnerabilities that can compromise the security of the entire application. One of the best practices to prevent such vulnerabilities is to set expiration times on JWTs.
Importance of setting expiration time on JWTs
Setting expiration times on JWTs is important because it limits the amount of time that the JWT can be used. Once the expiration time has passed, the JWT is no longer valid, and the user is required to obtain a new JWT to access the application. This prevents attackers from using an old JWT to gain access to the application, even after the user has logged out.
How to set expiration time on JWTs
Setting an expiration time on a JWT is done by adding an expiration claim to the JWT payload. The expiration claim (exp
) value is a Unix timestamp that represents the time the JWT will expire. When verifying the JWT, the server can check the exp claim to ensure that the JWT is still valid.
Here's an example of setting an expiration time of 30 minutes on a JWT in Python:
1import jwt
2import datetime
3
4# Set the expiration time to 30 minutes from now
5exp_time = datetime.datetime.utcnow() + datetime.timedelta(minutes=30)
6
7# Encode the JWT with the expiration claim
8jwt.encode({'some_payload': 'some_value', 'exp': exp_time}, 'secret_key', algorithm='HS256')
Practical example of how Snyk can find security issues
Snyk is a developer security tool that can help detect security issues related to setting expiration times on JWTs. For example, Snyk Open Source can scan your application's dependencies for known vulnerabilities, including vulnerabilities related to JWTs.
Snyk Open Source can also identify if an application is using an outdated or insecure version of a JWT library. By keeping your JWT libraries up to date, you can ensure that any security vulnerabilities related to JWTs are patched.
Recommended open source packages
There are several open source packages available that can help with setting expiration times on JWTs in Python. One such package is PyJWT, which provides a simple interface for encoding and decoding JWTs, including setting the expiration time.
To install PyJWT, you can use pip:
pip install PyJWT
Once installed, you can use PyJWT to set the expiration time on a JWT:
1import jwt
2import datetime
3
4# Set the expiration time to 30 minutes from now
5exp_time = datetime.datetime.utcnow() + datetime.timedelta(minutes=30)
6
7# Encode the JWT with the expiration claim using PyJWT
8jwt.encode({'some_payload': 'some_value', 'exp': exp_time}, 'secret_key', algorithm='HS256')
In conclusion, setting expiration times on JWTs is a crucial security best practice that can help prevent security vulnerabilities in your application. By using tools like Snyk and open source packages like PyJWT, you can ensure that your application is secure and up to date with the latest security best practices.
The criticality of JWT security best practices
In summary, adhering to JWT security best practices is vital for ensuring the safety and integrity of your web applications. As we've explored, improper handling of JWTs can lead to severe vulnerabilities and breaches, resulting in unauthorized access, data leaks, and reputational damage. By following the top 3 security best practices for handling JWTs, developers can significantly reduce the likelihood of encountering these risks.
Secure JWT storage: Avoid storing JWTs in local storage or cookies, and opt for more secure alternatives like HTTP-only cookies or server-side session management.
Validate and verify JWTs: Always validate JWTs upon receipt and verify the signature to ensure they haven't been tampered with. Implement proper error handling to handle invalid tokens securely.
Use strong encryption and algorithms: Choose robust encryption algorithms like RS256 and manage your private keys securely to prevent unauthorized token creation and modification.
Strengthen your application security with Snyk
To further bolster the security of your web applications, consider signing up for Snyk. Snyk is a powerful developer security tool that scans your source code, open source packages, container images, and cloud configurations for vulnerabilities. With Snyk Open Source, you can quickly identify and fix security issues in your Python projects and their dependencies.
For instance, Snyk can help you detect if your Python project is using an outdated or vulnerable version of a JWT library, and provide actionable recommendations for upgrading to a secure version.
# Requirements.txt file in your Python project
pyjwt==1.7.1
Snyk might notify you that pyjwt
version 1.7.1
is vulnerable and suggest upgrading to a more secure version, such as 2.1.0
.
# Updated Requirements.txt file
pyjwt==2.1.0
By integrating Snyk into your development workflow, you can proactively discover and address security issues before they become critical, ensuring that your applications remain secure and compliant.
Take action today
Don't leave the security of your web applications to chance. Ensure you follow the best practices for handling JWTs, and sign up for Snyk to gain a comprehensive security solution that helps you protect your applications from vulnerabilities and risks. With Snyk, you can develop with confidence, knowing that your applications are secure and compliant with industry standards. Start your free account today to secure your web applications!