This blog is a security centred articles that is intended to help django developers secure their deployments. In this piece I will talk about the security setup required for the secure use of JSON Web Token, an authorization mechanism used while transferring information in REST Frameworks such as Django REST-APIs
With business needs demanding more from web-applications, product teams have moved towards light-weight application development for scalability and efficiency. This usually includes building applications that use RESTful web-services, which use Application Programming Interface (API) to interact with other applications and web-services. One such popular web-framework that supports such an architecture is Django Web-Framework.
Django is a stateless application. Its completely decoupled; its front-end and back-end are completely different. Hence, it enables developers to build lightweight applications. Its popularity can also be attributed to its security features by design. It protects(see “Security in Django”) against multiple vulnerabilities such as SQL injection, CSRF, CSS, Clickjacking, and Session Hijacking. However, this doesn’t mean it’s completely secure. In fact certain vulnerabilities like JSON Web Token (JWT) attacks, XML External Entity or Insecure Direct Object Reference (IDOR) can only be protected against by proactive security measures that the developer needs to take when building an application.
A quick 101 for those who don't know what JSON Web Tokens (JWT) are: In a REST framework, information transferred between applications are pure information and do not include any format data. But, the applications need to format it to be able to present it to users. Hence, the most commonly used format is the JavaScript Object Notation (JSON) format.
In a REST-Framework, you need some sort of token-based authorization mechanism that is compact, easier to scale, and reusable. That's where JSON Web Token (JWT) comes in; it meets all the requirements. It is compact, supports a wide range of algorithms, and its parsing is common in most programming languages.
Okay, now that you know what JWTs are and their role in Django REST-framework, let's look at its security aspect.
JSON Web Tokens are not insecure by design. Any attacks you might come across involving JWT is largely down to poor implementation. A good example of such a vulnerability is the one Auth0(Auth0 is one of the biggest identity-as-a-service platform) faced which enabled any malicious user to bypass login through cross-site request forgery (CSRF). All that any malicious user would need is the victim’s user ID.
JWTs are used for authorization, as mentioned earlier, and hence has sensitive data embedded in it. JWTs have two JSON objects that store information; The header and the Payload. The header consists of information about what algorithm was used to sign or encrypt the payload in that token. Header by itself is not encrypted. The token is base64 encoded, which can be easily decoded. And, with the available algo info, you can decrypt the payload. Hence, it is very crucial to use strong secrets to encrypt the payload before using in a JWT.
All libraries allow the “none” option for a signature algorithm. This means, when a user submits the token for authorization, there is no signature verification done in the backend.
In the image above, on the right, the base64 encoded data before the first dot includes the algorithm info. Shown on the right side of the image is the decoded data, and as we can see that the “alg” field is using HS256. This can be replaced with “none”, and some implementations will accept it as a legit token,
So, a malicious user can change the algorithm to “none”, remove the signature, and use the modified token to access a server.
The algorithm HS256 uses a secret key to sign and verify each message. And, the algorithm RS256 uses a private key to sign messages, and a public key to verify them. If we change the algorithm from RS256 to HS256, the signature is now verified using the HS256 algorithm using the public key as secret key. Since the public key is not secret at all, we can correctly sign such messages. Here is how one can exploit them:
Now that you know what the attack surface for Django web-services look like, the following approach to securing them will become obvious to you.
Django is a very easy to use framework that already comes with robust security measures. However, developers should proactively take measures to protect their application from attacks such as JWT manipulation. To further your understanding of how to secure your Django Framework, I recommend watching Tilak’s talk( see “Unique ways to Hack into a Python Web Service” at DjangoCon US 2018.