All Products
Search
Document Center

Alibaba Cloud Service Mesh:Use an Envoy filter to add HTTP response headers in ASM

Last Updated:Mar 07, 2024

You can add HTTP response headers for web applications to improve the application security. This topic describes how to use an Envoy filter to add HTTP response headers in 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.

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.

In this example, a Bookinfo application is used. 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}/productpage
# Output example
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 application does not contain any of the HTTP response headers described in the preceding table. You can create an Envoy filter to add HTTP response headers for the application to improve the application security.

Procedure

  1. Deploy an Envoy filter based on the version of your ASM instance.

    For an ASM instance whose version is 1.12.4.0 or later

    You can deploy an Envoy filter on the Market Place page in the ASM console.

    1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

    2. On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose Plugin Extension Center > Market Place.

    3. On the Market Place page, click Add HTTP response headers. On the Plugin Detail page, click Create Plug-in Instance.

    4. In the Plugin Effective scope section, select Gateway Scope and click Add ASM Gateway to effective scope.

    5. In the Add ASM Gateway to effective scope dialog box, select ingressgateway in the Select ASM Gateway section, click the 添加 icon to add the ingressgateway to the selected section, and then click OK.

      Note

      ingressgateway is the name of the default ingress gateway. You can also select other gateways where you want the added HTTP response headers to take effect.

    6. In the Plugin Config section, delete all content from the YAML code editor, turn on Plugin Switch, and wait until the plug-in is enabled.

      After the plug-in is enabled, ASM automatically creates an Envoy filter.

    For an ASM instance whose version is earlier than 1.12.4.0

    You can run the following commands to deploy an Envoy filter:

    Expand to view commands

    kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1alpha3
    kind: EnvoyFilter
    metadata:
      name: addheader-into-ingressgateway
      namespace: istio-system
      labels:
        asm-system: 'true'
        provider: asm
    spec:
      workloadSelector:
        # You can use the workloadSelector field to select workloads in a specific namespace for the Envoy filter. 
        labels:
          istio: ingressgateway
      configPatches:
        # The Envoy configuration that you need to modify. 
      - applyTo: HTTP_FILTER
        match:
          context: GATEWAY
          proxy:
            proxyVersion: '^1\.9.*'
          listener:
            filterChain:
              filter:
                name: "envoy.filters.network.http_connection_manager"
                subFilter:
                  name: "envoy.filters.http.router"
        patch:
          operation: INSERT_BEFORE
          value: # Lua script configuration 
            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("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
    EOF

    proxyVersion: Specifies the Istio version to which the Envoy filter applies. Set the value to your Istio version. Some fields in the Envoy filter may be incompatible with the Istio version. You may need to modify the fields in the Envoy filter based on your Istio version:

    • If your Istio version is 1.8 or earlier, set the proxyVersion parameter to your Istio version and replace envoy.filters.network.http_connection_manager with envoy.http_connection_manager, envoy.filters.http.router with envoy.router, and type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua with type.googleapis.com/envoy.config.filter.http.lua.v2.Lua.

    • If your Istio version is 1.9 or later, set the proxyVersion parameter to your Istio version.

  2. Run the following command to check whether the HTTP response headers are added successfully:

    Replace {IP address of the ingress gateway} with the actual IP address of your ingress gateway. For more information about how to obtain the IP address of an ingress gateway, see "Obtain the IP address of the ingress gateway" in the Use Istio resources to route traffic to different versions of a service topic.

    curl -I http://{IP address of the ingress gateway}/productpage

    Expected output:

    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 application contains the basic HTTP response headers described in the preceding table.

FAQ

Why am I unable to access an application by using a URL with special characters?

The encoding formats of special characters may not comply with the URL encoding rule. For example, Unicode encoding instead of ASCII encoding is used for the special character Á. For more information, see Envoy cannot parse non-alphanumeric characters if not urlencoded.