AWS WAF 是一種 Web 應用程序防火牆,讓您可以監控轉發到 一個 Amazon CloudFront 分配、一個 Amazon API Gateway REST API 或一個 應用程序負載均衡器的 HTTP(S) 請求。它有助於保護您的 Web 應用程序或 API 免受可能影響可用性、危害安全性或消耗過多資源的常見 Web ***。html
使用 WAF 是向 Web 應用程序添加深度防護的一個很好的方法。一個 WAF 能夠幫助下降諸如 SQL 注入、跨網站腳本***和其餘常見***的風險。WAF 容許您建立本身的自定義規則,以決定是否在 HTTP 請求到達您的應用程序以前阻止或容許 HTTP 請求。linux
爲了測試 WAF 的攔截效果,咱們須要準備一個測試站點,目前比較流行的就是 OWASP Juice Shop 。web
OWASP Juice Shop 多是最現代和最複雜的不安全的網絡應用程序!它能夠用於安全培訓、意識演示、 CTFs,也能夠做爲安全工具的試驗品!Juice Shop 包含了整個 OWASP 十大漏洞以及在現實世界應用程序中發現的許多其餘安全漏洞!docker
由於咱們的測試環境在 AWS,咱們直接建立 EC2,在 EC2 上面部署 Juice Shop 站點進行測試。json
#!/bin/bash sudo yum update -y sudo amazon-linux-extras install docker sudo service docker start sudo docker pull bkimminich/juice-shop sudo docker run -d -p 80:3000 bkimminich/juice-shop
由於 WAF 不能直接添加到 EC2 上面,咱們須要給 EC2 建立一個 ALB。安全
Web ACL (Web Access Control List)是 AWS WAF 部署的核心資源。它包含對其接收的每一個請求求值的規則。Web ACL 經過 Amazon CloudFront distribution、 AWS API Gateway API 或 AWS Application Load Balancer 與您的 Web 應用程序相關聯。bash
開始使用 WAF 的最快方法是將 AWS WAF 的 AWS 託管規則組部署到 WebACL。網絡
Managed Rule Groups 是一組規則,由 AWS 或 AWS 市場上的第三方建立和維護。這些規則提供了針對常見類型,或者針對特定的應用程序類型***的保護。負載均衡
每一個託管規則組均可以防範一組常見的***,如 SQL 或命令行***,下面咱們看看在 WAF 中 AWS 提供了哪些託管規則組。curl
這裏咱們作個演示,在沒有 WAF 加持的狀況下是什麼情況,加上 WAF 託管規則又是什麼效果。
測試兩種類型的模擬***,一種是跨站腳本***,還有一種是 SQL 注入***,以下:
export JUICESHOP_URL=<Your Juice Shop URL>
# This imitates a Cross Site Scripting attack # This request should be blocked. curl -X POST $JUICESHOP_URL -F "user='<script><alert>Hello></alert></script>'"
# This imitates a SQL Injection attack # This request should be blocked. curl -X POST $JUICESHOP_URL -F "user='AND 1=1;"
咱們分別請求一下,看看是否能夠***成功:
經過測試看到,兩種***都成功,下面咱們來建立 WAF,並和 ALB 進行關聯,而後再進行測試
添加好託管規則組以後,咱們在模擬***查看效果。
如今能夠看到,所有攔截成功,經過咱們簡單的配置,對通常常見的***很快攔截下載,保障的應用程序的安全。
若是你不使用 AWS 提供的託管規則組,WAF 容許您爲處理請求建立本身的規則。這對於添加與特定應用程序相關的邏輯很是有用。
經過自定義規則,咱們能夠檢測一些 HTTP 請求的組件,好比:
經過這些檢測,WAF 能夠攔截或容許任何相關的請求。
在觀察訪日日誌的過程當中,發現全部的***都帶有一個請求頭X-TomatoAttack
,阻止這個請求頭能夠阻止全部的***,下面咱們將建立自定義規則來攔截這個請求頭,在沒有 WAF 加持的狀況下面,咱們模擬***,查看狀況。
curl -H "X-TomatoAttack: Red" "${JUICESHOP_URL}" curl -H "X-TomatoAttack: Green" "${JUICESHOP_URL}"
而後咱們建立自定義規則:
Header
規則添加好以後,咱們在進行測試,發現帶有 X-TomatoAttack
Header 的都被攔截,其餘的 Header 能夠正常請求。
自定義規則容許您實現本身的邏輯來處理 WAF 中的請求。自定義規則能夠檢查請求的許多組件,而後在規則語句爲真時採起行動阻止或容許請求。
每一個 Web ACL 都有一個最大的 Web ACL 容量單元(WCU)。這是1500,可是若是須要能夠增長。Web ACL 中的每一個規則和規則組都有助於實現這一限制。
咱們已經建立了一個簡單的 WAF 規則,用於評估請求的一部分。如何建立一個規則來對一個請求的多個部分進行評估呢?
全部 WAF 規則都定義爲 JSON 對象。對於複雜的規則,直接使用 JSON 格式比使用 Console 規則編輯器更有效。可使用 get-rule-group 命令使用 API、 CLI 或 Console 檢索 JSON 格式的現有規則。使用您最喜歡的 JSON 文本編輯器修改它們,而後在 API、 CLI 或控制檯中使用 update-rule-group 從新上傳它們。
在 JSON 中定義規則容許使用版本控制,以查看複雜規則集是如何、什麼是以及爲何發生了更改。
可使用 AND、OR 和 NOT 運算符建立更復雜的規則。這對於檢查請求的多個部分頗有用。例如,您只能在查詢字符串或 Header 包含某個鍵/值時才容許請求。
咱們把以前建立好的自定義規則使用 JSON editor 查看,以下:
{ "Name": "header-tomato", "Priority": 0, "Action": { "Block": {} }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "header-tomato" }, "Statement": { "SizeConstraintStatement": { "FieldToMatch": { "SingleHeader": { "Name": "x-tomatoattack" } }, "ComparisonOperator": "GE", "Size": 0, "TextTransformations": [ { "Type": "NONE", "Priority": 0 } ] } } }
好比咱們又收到了一個新的***,***具備以下特徵:
這個複合規則比較複雜,難以使用 console 完成,咱們須要經過編輯 json 來完成,咱們先製做一個空 rule:
{ "Name": "complex-rule", "Priority": 0, "Action": { "Block": {} }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "complex-rule" }, "Statement": { // We will add the rule here } }
有兩點咱們須要注意:
x-upload-body: true
,阻止請求咱們須要 OrStatement
和 NotStatement
來表達規則邏輯。
{ "Statement": { "OrStatement": { "Statements": [ { // Inspect Body Size here }, { "NotStatement": { // Inspect Header here } } ] } }
要檢查 body 的大小,咱們將使用 SizeConstraintStatement 來驗證請求 body 的大小。
"SizeConstraintStatement": { "FieldToMatch": { "Body": {} }, "ComparisonOperator": "GT", "Size": "100", "TextTransformations": [ { "Type": "NONE", "Priority": 0 } ] }
要檢查請求的 header,使用 ByteMatchStatement
"ByteMatchStatement": { "FieldToMatch": { "SingleHeader": { "Name": "x-upload-image" } }, "PositionalConstraint": "EXACTLY", "SearchString": "true", "TextTransformations": [ { "Type": "NONE", "Priority": 0 } ] }
最終生成的規則以下:
{ "Name": "complex-rule", "Priority": 0, "Action": { "Block": {} }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "complex-rule" }, "Statement": { "OrStatement": { "Statements": [ { "SizeConstraintStatement": { "FieldToMatch": { "Body": {} }, "ComparisonOperator": "GT", "Size": "100", "TextTransformations": [ { "Type": "NONE", "Priority": 0 } ] } }, { "NotStatement": { "Statement": { "ByteMatchStatement": { "FieldToMatch": { "SingleHeader": { "Name": "x-upload-body" } }, "PositionalConstraint": "EXACTLY", "SearchString": "true", "TextTransformations": [ { "Type": "NONE", "Priority": 0 } ] } } } } ] } } }
這樣一個複雜的規則就一步步建立好了,能夠抵擋特定的一些***。
假設咱們目前有一個複雜的規則組,能夠阻擋包含下面任一條件的請求:
x-milkshake: chocolate
,阻止請求milkshake=banana
,阻止請求規則的 json 格式以下:
{ "Name": "complex-rule-challenge", "Priority": 0, "Action": { "Block": {} }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "complex-rule-challenge" }, "Statement": { "OrStatement": { "Statements": [ { "ByteMatchStatement": { "FieldToMatch": { "SingleHeader": { "Name": "x-milkshake" } }, "PositionalConstraint": "EXACTLY", "SearchString": "chocolate", "TextTransformations": [ { "Type": "NONE", "Priority": 0 } ] } }, { "ByteMatchStatement": { "FieldToMatch": { "SingleQueryArgument": { "Name": "milkshake" } }, "PositionalConstraint": "EXACTLY", "SearchString": "banana", "TextTransformations": [ { "Type": "NONE", "Priority": 0 } ] } } ] } } }
可是最近***者近期升級了***請求,如今的請求變爲以下:
x-milkshake: chocolate
和 x-favourite-topping: nuts
milkshake=banana
和 favourite-topping=sauce
咱們須要更新現有規則。使用 AndStatement 擴展兩個現有語句。 更新後的 json 格式以下:
{ "Name": "complex-rule-challenge", "Priority": 0, "Action": { "Block": {} }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "complex-rule-challenge" }, "Statement": { "OrStatement": { "Statements": [ { "AndStatement": { "Statements": [ { "ByteMatchStatement": { "FieldToMatch": { "SingleHeader": { "Name": "x-milkshake" } }, "PositionalConstraint": "EXACTLY", "SearchString": "chocolate", "TextTransformations": [ { "Type": "NONE", "Priority": 0 } ] } }, { "ByteMatchStatement": { "FieldToMatch": { "SingleHeader": { "Name": "x-favourite-topping" } }, "PositionalConstraint": "EXACTLY", "SearchString": "nuts", "TextTransformations": [ { "Type": "NONE", "Priority": 0 } ] } } ] } }, { "AndStatement": { "Statements": [ { "ByteMatchStatement": { "FieldToMatch": { "SingleQueryArgument": { "Name": "milkshake" } }, "PositionalConstraint": "EXACTLY", "SearchString": "banana", "TextTransformations": [ { "Type": "NONE", "Priority": 0 } ] } }, { "ByteMatchStatement": { "FieldToMatch": { "SingleQueryArgument": { "Name": "favourite-topping" } }, "PositionalConstraint": "EXACTLY", "SearchString": "sauce", "TextTransformations": [ { "Type": "NONE", "Priority": 0 } ] } } ] } } ] } } }
更新規則以後,以前被攔截的如今能夠容許。
# Allowed curl -H "x-milkshake: chocolate" "${JUICESHOP_URL}" curl "${JUICESHOP_URL}?milkshake=banana"
使用新的參數請求的,將被阻止。
# Blocked curl -H "x-milkshake: chocolate" -H "x-favourite-topping: nuts" "${JUICESHOP_URL}" curl "${JUICESHOP_URL}?milkshake=banana&favourite-topping=sauce"
在這一節,咱們爲你們演示瞭如何經過 json 制定一個複雜的規則,這個規則是在 console 沒法實現的。
在部署新規則以前,對其進行測試是相當重要的。這是爲了確保您不會意外地阻止有效的請求。
到目前爲止,在指定對請求採起什麼操做時,您已經使用了 Block 和 Allow。還有第三個動做 Count。Count 容許您度量知足規則條件的請求數量。
Count 是一個非終止操做。當請求與 Count 操做匹配規則時,web ACL 將繼續處理其他的規則。
當具備 Count 的規則動做被匹配時,事件將做爲 CloudWatch 指標發出。要查看規則的計數,請到 CloudWatch 指標控制檯。選擇 AWS/WAFv2,而後選擇 Region、 Rule、 WebACL 以查看指標。