Security headers and TLS protocol version with Envoy/Istio
HTTP security headers are HTTP response headers designed to enhance the security of a site. They instruct browsers on how to behave and prevent them from executing vulnerabilities that would endanger your users.
Whilst there are number of HTTP security headers which can be implement to increase the security of a web site, below are few most important HTTP security headers that will strengthen your website’s security.
XSS Protection Header
The HTTP 'X-XSS-Protection' response header is a feature of modern browsers that allows websites to control their XSS auditors.The server is not configured to return a 'X-XSS-Protection' header which means that any pages on this website could be at risk of a Cross-Site Scripting (XSS) attack.
Content Security Policy (CSP)
HTTP Strict Transport Security
HTTP Strict Transport Security (also named HSTS) is a web security policy mechanism which helps to protect websites against protocol downgrade attacks and cookie hijacking. It allows web servers to declare that web browsers (or other complying user agents) should only interact with it using secure HTTPS connections, and never via the insecure HTTP protocol. A server implements an HSTS policy by supplying a header (Strict-Transport-Security) over an HTTPS connection (HSTS headers over HTTP are ignored).
Almost all browsers are designed to use a mime sniffing technique to guess the content type of the HTTP response instead of adhering to the Content-Type specified by the application in specific cases or ignoring the content when no mime type is specified. Inconsistencies introduced by the mime sniffing techniques could allow attackers to conduct Cross-Site Scripting attacks or steal sensitive user data. The application fails to instruct the browser to strictly enforce the Content-Type specification supplied in the response.
Different servers such as Nginx, Apache, IIS has different mechanism to configure security headers. However, if you are in Kubernetes and use Istio service mesh you can easily achieve this in sidecar Envoy proxy. Benefit of that is you can add the same configuration to the all web sites irrespective of the underline web server.
In the below code I use Envoy Lua Filter to do the header manipulation through response handlers. Note that I use SIDECAR_INBOUND as context and add this filter to all my front-end web apps (Angular, React, Nextjs etc..).
apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: "myweb-ef" spec: workloadSelector: labels: app: myweb configPatches: - applyTo: HTTP_FILTER match: context: SIDECAR_INBOUND listener: portNumber: 80 filterChain: filter: name: "envoy.http_connection_manager" subFilter: name: "envoy.router" patch: operation: INSERT_BEFORE value: # lua filter specification name: envoy.lua typed_config: "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua" inlineCode: | function envoy_on_response(response_handle) function hasFrameAncestors(rh) s = rh:headers():get("Content-Security-Policy"); delimiter = ";"; defined = false; for match in (s..delimiter):gmatch("(.-)"..delimiter) do match = match:gsub("%s+", ""); if match:sub(1, 15)=="frame-ancestors" then return true; end end return false; end if not response_handle:headers():get("Content-Security-Policy") then csp = "frame-ancestors none;"; response_handle:headers():add("Content-Security-Policy", csp); elseif response_handle:headers():get("Content-Security-Policy") then if not hasFrameAncestors(response_handle) then csp = response_handle:headers():get("Content-Security-Policy"); csp = csp .. ";frame-ancestors none;"; response_handle:headers():replace("Content-Security-Policy", csp); end end if not response_handle:headers():get("X-Frame-Options") then response_handle:headers():add("X-Frame-Options", "deny"); end if not response_handle:headers():get("X-XSS-Protection") then response_handle:headers():add("X-XSS-Protection", "1; mode=block"); end if not response_handle:headers():get("X-Content-Type-Options") then response_handle:headers():add("X-Content-Type-Options", "nosniff"); end if not response_handle:headers():get("Referrer-Policy") then response_handle:headers():add("Referrer-Policy", "no-referrer"); end if not response_handle:headers():get("X-Download-Options") then response_handle:headers():add("X-Download-Options", "noopen"); end if not response_handle:headers():get("Strict-Transport-Security") then response_handle:headers():add("Strict-Transport-Security", "max-age=31536000; includeSubDomains"); end if response_handle:headers():get("X-Powered-By") then response_handle:headers():remove("X-Powered-By"); end end
For testing this we can use testssl.sh. You can just pull the container from dockerhub and run it as below:
docker run --rm -ti drwetter/testssl.sh https://myweb.com.au
You can confirm the added security headers by looking at the output.
Another best practice that will strengthen your website’s security is disabling earlier versions of TLS (TLS v1.0 and 1.1) and enable only TLS v1.2 and higher. Reason behind this is earlier TLS versions including TLS v1.0 have known security issues and were decrypted using capable tools and systems resulting on data leakage on transmission. Also its important to disable the weak ciphers in TLS v1.2.
You can simply achieve both of them in Isito gateway as below. Note that I have setup both minProtocolVersion and cipherSuites.
- hosts: - 'myweb.com.au' port: name: https number: 443 protocol: HTTPS tls: cipherSuites: - ECDHE-RSA-AES128-GCM-SHA256 - ECDHE-RSA-AES256-GCM-SHA384 credentialName: myweb-certs minProtocolVersion: TLSV1_2 mode: SIMPLE
Now If you test this with testssl.sh using above docker run command, you will see the below output which will confirm the correct TLS version/ciphers.
That's It! These security header and best practices around TLS would increase the security of most websites.