Insecure or unset HTTP headers - Accept
Need
Enforcement of secure and restricted HTTP headers
Context
- Usage of Java 8 for developing applications with enhanced features and performance improvements
- Usage of javax.servlet-api for building Java web applications with Servlets
Description
Non compliant code
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public void doGet(HttpServletRequest request, HttpServletResponse response) {
String acceptHeader = request.getHeader("Accept");
if (acceptHeader == null || acceptHeader.equals("*/*")) {
// process the request
}
}
In the above Java servlet code, the Accept HTTP header is retrieved from the request and checked if it is null or if it equals "/". If either of these conditions is true, the application proceeds to process the request.
The Accept HTTP header is used by HTTP clients to tell the server what content types they'll accept. The server will then send back a response, which will include a Content-Type header to tell the client what the content type of the returned content actually is.
In the provided code, if the Accept header is not set (null) or if it is set to accept any MIME type ("/"), the server will process the request. This is a vulnerability because it allows for potential attacks where the client can send a request with a malicious MIME type. The server would then process this request and potentially cause unexpected behaviors or vulnerabilities.
For example, an attacker could send a request with a MIME type that causes the server to interpret the content in a way that leads to code execution, information disclosure, or any number of other potential vulnerabilities.
The server should be validating the Accept header to ensure it only processes requests with expected and safe MIME types.
Steps
- Validate and restrict the allowed MIME types in the Accept header.
- Set a default Accept header if it is not provided by the client.
- Implement proper error handling for unsupported or unexpected MIME types.
- Consider implementing content negotiation to ensure the server and client agree on the acceptable content types.
Compliant code
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public void doGet(HttpServletRequest request, HttpServletResponse response) {
String acceptHeader = request.getHeader("Accept");
String defaultAcceptHeader = "application/json"; // Default MIME type
List<String> allowedMimeTypes = Arrays.asList("application/json", "text/html"); // Allowed MIME types
if (acceptHeader == null) {
response.setHeader("Accept", defaultAcceptHeader);
acceptHeader = defaultAcceptHeader;
}
if (!allowedMimeTypes.contains(acceptHeader)) {
throw new IllegalArgumentException("Unsupported MIME type: " + acceptHeader);
}
if (acceptHeader.equals("*/*")) {
response.setHeader("Accept", defaultAcceptHeader);
acceptHeader = defaultAcceptHeader;
}
// process the request
}
The fixed code first sets a default MIME type (application/json
) and a list of allowed MIME types (application/json
and text/html
).
If the Accept
header is not provided by the client, the server sets it to the default MIME type.
Then, the server checks if the provided Accept
header is in the list of allowed MIME types. If it is not, an IllegalArgumentException
is thrown, indicating that the provided MIME type is not supported. This is an example of proper error handling for unsupported or unexpected MIME types.
If the Accept
header is set to */*
(which means any MIME type is acceptable), the server sets it to the default MIME type. This is a way of restricting the allowed MIME types in the Accept
header.
This way, the server ensures that it only processes requests with acceptable content types, thereby preventing unexpected behaviors when interpreting incorrect content types. This is an example of implementing content negotiation.