Skip to main content

Insecure or unset HTTP headers - Content-Security-Policy

Need

Implementation of secure and properly configured Content-Security-Policy headers

Context

  • Usage of Dart 2.0 for building high-performance, cross-platform applications
  • Usage of Shelf for managing data storage and retrieval
  • Usage of shelf_io for managing and interacting with data storage in Node.js

Description

Non compliant code

import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;

void main() {
var handler = const shelf.Pipeline().addMiddleware(shelf.logRequests())
.addHandler(_echoRequest);

io.serve(handler, 'localhost', 8080);
}

shelf.Response _echoRequest(shelf.Request request) {
return shelf.Response.ok('Request for "${request.url}"');
}

In this code, the server responds to each request with a simple message. However, it does not set any HTTP headers, including the Content-Security-Policy header.

The Content-Security-Policy HTTP header is a powerful tool that helps protect against various types of attacks, including Cross Site Scripting (XSS) and data injection attacks. It allows you to specify the domains that the browser should consider to be valid sources of executable scripts.

Without this header, or with it set incorrectly, your application could be vulnerable to these types of attacks.

In the above code, there is no middleware or handler that sets this header. This means that every response from this server will not include the Content-Security-Policy header, leaving the application vulnerable.

Steps

  • First, you need to create a middleware function that will add the Content-Security-Policy header to every response.
  • In this middleware function, set the Content-Security-Policy header with a value that defines the allowed sources of content for your application. Be sure to restrict the sources to only trusted ones to prevent Cross-Site Scripting (XSS) attacks.
  • Add this middleware to your application pipeline using the addMiddleware method. This will ensure that the Content-Security-Policy header is added to every response that your server sends.
  • Finally, test your application to ensure that the Content-Security-Policy header is properly set and that it doesn't break any functionality of your application.

Compliant code

import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;

void main() {
var handler = const shelf.Pipeline()
.addMiddleware(shelf.logRequests())
.addMiddleware(_addContentSecurityPolicyHeader)
.addHandler(_echoRequest);

io.serve(handler, 'localhost', 8080);
}

shelf.Response _echoRequest(shelf.Request request) {
return shelf.Response.ok('Request for "${request.url}"');
}

shelf.Middleware _addContentSecurityPolicyHeader() {
return (shelf.Handler handler) {
return (shelf.Request request) {
return Future.sync(() => handler(request)).then((shelf.Response response) {
return response.change(headers: {
'Content-Security-Policy': "default-src 'self';"
});
});
};
};
}

The updated code includes a middleware function _addContentSecurityPolicyHeader that adds the Content-Security-Policy header to every response. This header is set with a value of "default-src 'self';", which means that all content must come from the same origin as the document itself. This is a common policy that helps prevent Cross-Site Scripting (XSS) attacks by restricting where content can be loaded from.

The middleware function is added to the application pipeline using the addMiddleware method. This ensures that the Content-Security-Policy header is added to every response that the server sends.

The middleware function works by wrapping the handler function. When a request is received, it first passes the request to the handler function. Once the handler function has processed the request and generated a response, the middleware function modifies this response to add the Content-Security-Policy header before it is sent back to the client.

This solution ensures that the Content-Security-Policy header is always set, regardless of the specific route that is handling the request. This is important because it ensures that the security policy is consistently applied across all parts of the application.

References