Add security headers to your web app with Envoy

Envoy gives you the option to run a LUA script against each route you define. So for example let's imagine you have created a route in envoy to your app.

# Web request to our app
- match: { prefix: "/app" }
route: { cluster: app }
# Add security headers
    name: app_headers.lua

We define our script within our filters, notice the function is called envoy_on_response it will catch all the responses from your route and add the headers.

- name: envoy.filters.http.lua

            inline_string: |
            function envoy_on_response(response_handle)
                csp = "default-src 'none'; script-src 'self'; img-src 'self'; style-src 'self'; connect-src 'self'";
                response_handle:headers():add("Content-Security-Policy", csp);
                response_handle:headers():add("X-Frame-Options", "deny");
                response_handle:headers():add("X-XSS-Protection", "1; mode=block");
                response_handle:headers():add("X-Content-Type-Options", "nosniff");
                response_handle:headers():add("Referrer-Policy", "no-referrer");
                response_handle:headers():add("X-Download-Options", "noopen");
                response_handle:headers():add("X-DNS-Prefetch-Control", "off");
                response_handle:headers():add("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
                                            "accelerometer=(), "..
                                            "camera=(), "..
                                            "geolocation=(), "..
                                            "gyroscope=(), "..
                                            "magnetometer=(), "..
                                            "microphone=(), "..
                                            "payment=(), "..

Check your sites security headers

This is enough to get an A+ on

Security Headers Test

But, we can do more

A very important part of the security headers is the Content-Security-Policy if we set the policy to the below we shut off JavaScript and therefore whole classes of attacks.

default-src 'none'; img-src 'self'; style-src 'self'

If you need to run JavaScript we can open up the policy like so.

default-src 'none'; script-src 'self'; img-src 'self'; style-src 'self'; connect-src 'self'

Now for any resources that break the policy you will get errors in the browser console. Things that will cause errors are inline JavaScript or CSS and perhaps any 3rd party services you are calling from the front end.

You can use to see how effective your CSP is.

So ideally we want to stay with the policies above, opening up the policies more than this introduces potential ways for attackers to abuse your application.