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 以查看指标。