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
An Alibaba Cloud Service Mesh (ASM) instance is created. The ACK cluster is added to the ASM instance. For more information, see Create an ASM instance and Add a cluster to an ASM instance.
kubectl is connected to the ASM instance. For more information, see Use kubectl on the control plane to access Istio resources.
An application is deployed in the ASM instance. For more information, see Deploy an application in an ASM instance.
Required Istio resources are defined. To define the Istio resources, perform Step 1 to Step 3 in the Use Istio resources to route traffic to different versions of a service topic.
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
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
Create an Envoy filter.
If the version of your ASM instance is earlier than v1.12.4.0-g7d140f10-aliyun, run the following command to create an Envoy filter:
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
withenvoy.http_connection_manager
,envoy.filters.http.router
withenvoy.router
, andtype.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
withtype.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.
If the version of your ASM instance is v1.12.4.0-g7d140f10-aliyun or later, create an Envoy filter on the Market Place page in the ASM console.
Log on to the ASM console.
In the left-side navigation pane, choose
.On the Mesh Management page, find the ASM instance that you want to configure. Click the name of the ASM instance or click Manage in the Actions column.
On the details page of the ASM instance, choose
in the left-side navigation pane.On the Market Place page, click Add HTTP response headers. On the Plugin Detail page, click the Plugin Config tab.
In the Plugin Effective scope section, select Gateway Scope and click Add ASM Gateway to effective scope.
In the Add ASM Gateway to effective scope dialog box, select ingressgateway in the Select ASM Gateway section, click the
icon to add ingressgateway to the selected section, and then click OK.
Noteingressgateway 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.
In the Plugin Config section, delete all content from the YAML code editor, turn on Plugin Switch, and wait until the plugin is enabled.
After the plugin is enabled, ASM automatically creates an Envoy filter.
Run the following curl command to query the HTTP response headers of the application:
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 HTTP response headers described in Basic HTTP response headers.
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, special character Á uses Unicode encoding instead of ASCII encoding. For more information, see Envoy cannot parse non-alphanumeric characters if not urlencoded.