在ASM中通過(guò)EnvoyFilter添加HTTP響應(yīng)頭
在應(yīng)用程序中添加HTTP響應(yīng)頭可以提高Web應(yīng)用程序的安全性。本文介紹如何通過(guò)定義EnvoyFilter添加HTTP響應(yīng)頭。
前提條件
已創(chuàng)建一個(gè)ASM實(shí)例,并已將ACK集群添加到ASM實(shí)例中。具體操作,請(qǐng)參見(jiàn)創(chuàng)建ASM實(shí)例和添加集群到ASM實(shí)例。
背景信息
OWASP提供了最佳實(shí)踐指南和編程框架,描述了如何使用安全響應(yīng)頭保護(hù)應(yīng)用程序的安全。HTTP響應(yīng)頭的基準(zhǔn)配置如下:
HTTP響應(yīng)頭 | 默認(rèn)值 | 描述 |
Content-Security-Policy | frame-ancestors none; | 防止其他網(wǎng)站進(jìn)行Clickjacking攻擊。 |
X-XSS-Protection | 1;mode=block | 激活瀏覽器的XSS過(guò)濾器(如果可用),檢測(cè)到XSS時(shí)阻止渲染。 |
X-Content-Type-Options | Nosniff | 禁用瀏覽器的內(nèi)容嗅探。 |
Referrer-Policy | no-referrer | 禁用自動(dòng)發(fā)送引薦來(lái)源。 |
X-Download-Options | noopen | 禁用舊版本IE中的自動(dòng)打開(kāi)下載功能。 |
X-DNS-Prefetch-Control | off | 禁用對(duì)頁(yè)面上的外部鏈接的推測(cè)性DNS解析。 |
Server | envoy | 由Istio的入口網(wǎng)關(guān)自動(dòng)設(shè)置。 |
X-Powered-by | 無(wú)默認(rèn)值 | 去掉該值來(lái)隱藏潛在易受攻擊的應(yīng)用程序服務(wù)器的名稱和版本。 |
Feature-Policy | camera ‘none’; microphone ‘none’; geolocation ‘none’; encrypted-media ‘none’; payment ‘none’; speaker ‘none’; usb ‘none’; | 控制可以在瀏覽器中使用的功能和API。 |
以Bookinfo應(yīng)用程序?yàn)槔ㄔ斍檎?qǐng)參見(jiàn)在ASM實(shí)例關(guān)聯(lián)的集群中部署應(yīng)用),通過(guò)Curl命令可以看到應(yīng)用程序的HTTP響應(yīng)頭信息如下。
curl -I http://{入口網(wǎng)關(guān)服務(wù)的IP地址}/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
可以看到,在默認(rèn)情況下,示例應(yīng)用程序的入口首頁(yè)響應(yīng)并沒(méi)有包含上述表格中安全相關(guān)的HTTP響應(yīng)頭。通過(guò)Istio EnvoyFilter可以快速添加安全相關(guān)的HTTP響應(yīng)頭。
操作步驟
按照ASM實(shí)例版本部署EnvoyFilter。
ASM實(shí)例版本為1.12.4.0及以上
您可以通過(guò)插件市場(chǎng)直接部署EnvoyFilter。
登錄ASM控制臺(tái),在左側(cè)導(dǎo)航欄,選擇 。
在網(wǎng)格管理頁(yè)面,單擊目標(biāo)實(shí)例名稱,然后在左側(cè)導(dǎo)航欄,選擇 。
在插件市場(chǎng)頁(yè)面,單擊添加HTTP響應(yīng)頭,然后在插件詳情頁(yè)面,單擊新建插件實(shí)例。
在插件生效范圍區(qū)域,選中網(wǎng)關(guān)生效,然后單擊添加網(wǎng)關(guān)生效范圍。
在添加網(wǎng)關(guān)生效范圍對(duì)話框中,在選擇網(wǎng)關(guān)區(qū)域選中ingressgateway,單擊圖標(biāo),將ingressgateway添加到已選擇區(qū)域中,然后單擊確定。
說(shuō)明ingressgateway為ASM默認(rèn)部署的網(wǎng)關(guān)名稱,您也可以選擇希望生效添加HTTP響應(yīng)頭能力的其它ASM網(wǎng)關(guān)。
在插件配置區(qū)域,刪除YAML框中的所有內(nèi)容,然后打開(kāi)生效開(kāi)關(guān),等待插件啟用。
在插件啟用后,ASM會(huì)自動(dòng)創(chuàng)建EnvoyFilter。
ASM實(shí)例版本為1.12.4.0以下
您可以執(zhí)行以下命令,直接部署EnvoyFilter。
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: # EnvoyFilter通過(guò)標(biāo)簽選擇同一命名空間下的工作負(fù)載。 labels: istio: ingressgateway configPatches: # 需要修改的Envoy配置。 - 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腳本配置。 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
:配置為您當(dāng)前的Istio版本。EnvoyFilter創(chuàng)建時(shí)需要設(shè)置proxyVersion來(lái)指定期望作用的Istio版本范圍,EnvoyFilter配置中的一些字段存在Istio版本不兼容的可能性。不同Istio版本的EnvoyFilter內(nèi)容不同:如果您使用的Istio1.8及以下版本,請(qǐng)根據(jù)版本替換
proxyVersion
字段,并且替換上述EnvoyFilter中的envoy.filters.network.http_connection_manager
為envoy.http_connection_manager
、envoy.filters.http.router
為envoy.router
、type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
為type.googleapis.com/envoy.config.filter.http.lua.v2.Lua
。如果您使用的Istio1.9及以上版本,請(qǐng)根據(jù)版本替換
proxyVersion
字段。
執(zhí)行以下命令,驗(yàn)證安全HTTP響應(yīng)頭是否添加成功。
請(qǐng)將
{入口網(wǎng)關(guān)的IP地址}
替換為實(shí)際的網(wǎng)關(guān)地址。關(guān)于如何獲取入口網(wǎng)關(guān)地址,請(qǐng)參見(jiàn)獲取入口網(wǎng)關(guān)地址。curl -I http://{入口網(wǎng)關(guān)的IP地址}/productpage
預(yù)期輸出:
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';
由預(yù)期輸出得到,示例應(yīng)用程序的入口首頁(yè)響應(yīng)已經(jīng)包含了HTTP響應(yīng)頭的基準(zhǔn)配置中所描述的安全相關(guān)的HTTP響應(yīng)頭。
FAQ
為什么無(wú)法訪問(wèn)帶有特殊字符的URL?
以特殊字符á為例,特殊字符á的編碼格式采用Unicode,而不是ASCII。因此請(qǐng)求的URL中帶有特殊字符,不符合URL規(guī)范。更多信息,請(qǐng)參見(jiàn)Envoy cannot parse non-alphanumeric characters if not urlencoded。