You can add HTTP response headers for web applications to improve the security of the web applications. This topic describes how to define an EnvoyFilter resource to add HTTP response headers in Alibaba Cloud Service Mesh (ASM).

Prerequisites

Background information

Open Web Application Security Project (OWASP) provides best practices and a coding framework to describe how to use HTTP response headers to improve the security of applications. The following table describes basic HTTP response headers.
Table 1. Basic HTTP response headers
HTTP response header Default value Description
Content-Security-Policy frame-ancestors none; Prevents clickjacking attacks from other websites.
X-XSS-Protection 1;mode=block Activates the cross-site scripting (XSS) filter (if it is available) of a browser so that the browser can stop rendering when XSS attacks are detected.
X-Content-Type-Options Nosniff Disables content sniffing of a browser.
Referrer-Policy no-referrer Specifies to send no referrer information along with requests.
X-Download-Options noopen Prevents old versions of Internet Explorer from allowing downloads to be automatically executed.
X-DNS-Prefetch-Control off Disables DNS prefetching for external hyperlinks on web pages.
Server envoy The server that generates the response. This HTTP response header is automatically set by the Istio ingress gateway.
X-Powered-by N/A Contains information about the hosting environments or other frameworks. Do not set this HTTP response header if you want to hide the name and version information of vulnerable application servers.
Feature-Policy

camera 'none';

microphone 'none';

geolocation 'none';

encrypted-media 'none';

payment 'none';

speaker 'none';

usb 'none';

Specifies the features and API operations that are available to browsers.
This topic takes the Bookinfo application as an example. For more information, see Deploy an application in an ASM instance. You can run the following curl command to query the HTTP response headers of the application:
curl -I http://{IP address of the ingress gateway service}/productpage
HTTP/1.1 200 OK
content-type: text/html; charset=utf-8
content-length: 5183
server: istio-envoy
date: Tue, 28 Jan 2020 08:15:21 GMT
x-envoy-upstream-service-time: 28

The command output indicates that the response from the application homepage does not contain the security-related HTTP response headers that are described in Table 1. You can define an EnvoyFilter resource to add security-related HTTP response headers for the application.

Procedure

  1. Run the following command to deploy an Istio service entry:
    kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1alpha3
    kind: EnvoyFilter
    metadata:
      name: addheader-into-ingressgateway
      namespace: istio-system
    spec:
      workloadSelector:
        # select by label in the same namespace
        labels:
          istio: ingressgateway
      configPatches:
        # The Envoy config you want to modify
      - applyTo: HTTP_FILTER
        match:
          context: GATEWAY
          proxy:
            proxyVersion: '^1\.8.*'
          listener:
            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.config.filter.http.lua.v2.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("X-DNS-Prefetch-Control") then
                    response_handle:headers():add("X-DNS-Prefetch-Control", "off");
                    end
                    if not response_handle:headers():get("Feature-Policy") then
                    response_handle:headers():add("Feature-Policy",
                                                    "camera 'none';"..
                                                    "microphone 'none';"..
                                                    "geolocation 'none';"..
                                                    "encrypted-media 'none';"..
                                                    "payment 'none';"..
                                                    "speaker 'none';"..
                                                    "usb 'none';");
                    end
                    if response_handle:headers():get("X-Powered-By") then
                    response_handle:headers():remove("X-Powered-By");
                    end
                end
    proxyVersion: Set this parameter to your Istio version. When you create an EnvoyFilter resource, you must set the proxyVersion parameter to specify the Istio version to which the EnvoyFilter resource applies. Some fields in the EnvoyFilter configuration may be incompatible across different Istio versions. The EnvoyFilter configuration varies with Istio versions.
    • If you use Istio 1.8 or later, set the proxyVersion parameter to your Istio version.
    • If you use Istio 1.9 or later, set the proxyVersion parameter to your Istio version and replace envoy.http_connection_manager with envoy.filters.network.http_connection_manager, envoy.router with envoy.filters.http.router, and type.googleapis.com/envoy.config.filter.http.lua.v2.Lua with type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua in the EnvoyFilter configuration.
  2. Verify the HTTP response headers.
    Run the following curl command to check whether the HTTP response headers are added for the application:
    curl -I http://{IP address of the ingress gateway service}/productpage
    HTTP/1.1 200 OK
    content-type: text/html; charset=utf-8
    content-length: 4183
    server: istio-envoy
    date: Tue, 28 Jan 2020 09:07:01 GMT
    x-envoy-upstream-service-time: 17
    content-security-policy: frame-ancestors none;
    x-frame-options: deny
    x-xss-protection: 1; mode=block
    x-content-type-options: nosniff
    referrer-policy: no-referrer
    x-download-options: noopen
    x-dns-prefetch-control: off
    feature-policy: camera 'none';microphone 'none';geolocation 'none';encrypted-media 'none';payment 'none';speaker 'none';usb 'none';
    The command output indicates that the response from the application homepage contains the security-related HTTP response headers that are described in Table 1.