Skip to main content

Lack of data validation - Token

Need

Implementation of robust data validation for JWT access tokens

Context

  • Usage of Dart for building cross-platform mobile, web, and desktop applications
  • Usage of Shelf for managing and organizing data in a Node.js application
  • Usage of jaguar_jwt for JSON Web Token (JWT) authentication and authorization

Description

Non compliant code

import 'package:shelf/shelf.dart' as shelf;
import 'package:jaguar_jwt/jaguar_jwt.dart';

shelf.Response handleRequest(shelf.Request request) {
final String authHeader = request.headers['Authorization'];
if (authHeader != null && authHeader.startsWith('Bearer ')) {
final String token = authHeader.substring(7);
final decClaimSet = verifyJwtHS256Signature(token, 'yourSecret');
if (decClaimSet != null) {
return shelf.Response.ok('Authorized');
}
}
return shelf.Response.forbidden('Unauthorized');
}

This Dart code is a simple server-side implementation using the Shelf framework. The handleRequest function is a request handler that checks if the incoming request has an 'Authorization' header that contains a JWT token.

The verifyJwtHS256Signature function from the jaguar_jwt package is used to decode the JWT token. The verifyJwtHS256Signature function decodes the token but does not validate the signature of the token. This is a security vulnerability because an attacker can modify the token or remove the signature, and the server will still accept the request as valid.

The handleRequest function checks if the decoded token is not null and if it is not, the server responds with a 200 OK status, indicating that the request is authorized. If the token is null or does not exist, the server responds with a 403 Forbidden status, indicating that the request is unauthorized.

However, because the verifyJwtHS256Signature function does not validate the signature of the token, an attacker can send a request with a modified or unsigned token, and the server will respond with a 200 OK status, indicating that the request is authorized. This is a security vulnerability because it allows an attacker to bypass authentication and authorization checks.

Steps

  • First, ensure that the JWT token is not null or empty before proceeding with any operations.
  • Next, validate the JWT token's signature. This can be done by using a secret key that only the server knows. The 'verifyJwtHS256Signature' function should throw an exception if the signature is invalid.
  • Handle the exception thrown by 'verifyJwtHS256Signature' function. If an exception is thrown, it means that the token is invalid. In this case, return a 'Unauthorized' response.
  • If no exception is thrown, it means that the token is valid. Proceed with the request processing.

Compliant code

import 'package:shelf/shelf.dart' as shelf;
import 'package:jaguar_jwt/jaguar_jwt.dart';

shelf.Response handleRequest(shelf.Request request) {
final String authHeader = request.headers['Authorization'];
if (authHeader != null && authHeader.startsWith('Bearer ')) {
final String token = authHeader.substring(7);
if (token != null && token.isNotEmpty) {
try {
final decClaimSet = verifyJwtHS256Signature(token, 'yourSecret');
if (decClaimSet != null) {
return shelf.Response.ok('Authorized');
}
} on JwtException catch (e) {
return shelf.Response.forbidden('Unauthorized');
}
}
}
return shelf.Response.forbidden('Unauthorized');
}

The updated code now includes a check to ensure that the JWT token is not null or empty before proceeding with any operations. This is done by adding an if condition if (token != null && token.isNotEmpty).

Next, the code validates the JWT token's signature by using the verifyJwtHS256Signature function. This function uses a secret key that only the server knows to verify the signature of the token. If the signature is invalid, the function will throw a JwtException.

The code now handles the JwtException thrown by the verifyJwtHS256Signature function. If an exception is thrown, it means that the token is invalid. In this case, the function returns a 'Unauthorized' response by using return shelf.Response.forbidden('Unauthorized');.

If no exception is thrown, it means that the token is valid. The function then proceeds with the request processing and returns a 'Authorized' response.

References