AWS WAF 是一种 Web 应用程序防火墙,让您能够监控转发到 一个 Amazon CloudFront 分配、一个 Amazon API Gateway REST API 或一个 应用程序负载均衡器的 HTTP(S) 请求。它有助于保护您的 Web 应用程序或 API 免受可能影响可用性、危害安全性或消耗过多资源的常见 Web 攻*击。
使用 WAF 是向 Web 应用程序添加深度防御的一个很好的方法。一个 WAF 可以帮助降低诸如 SQL 注入、跨网站脚本和其他常见的风险。WAF 允许您创建自己的自定义规则,以决定是否在 HTTP 请求到达您的应用程序之前阻止或允许 HTTP 请求。
为了测试 WAF 的拦截效果,我们需要准备一个测试站点,目前比较流行的就是 OWASP Juice Shop 。
OWASP Juice Shop 可能是最现代和最复杂的不安全的网络应用程序!它可以用于安全培训、意识演示、 CTFs,也可以作为安全工具的试验品!Juice Shop 包含了整个 OWASP 十大漏洞以及在现实世界应用程序中发现的许多其他安全漏洞!
因为我们的测试环境在 AWS,我们直接创建 EC2,在 EC2 上面部署 Juice Shop 站点进行测试。
#!/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 应用程序相关联。
开始使用 WAF 的最快方法是将 AWS WAF 的 AWS 托管规则组部署到 WebACL。
Managed Rule Groups 是一组规则,由 AWS 或 AWS 市场上的第三方创建和维护。这些规则提供了针对常见类型,或者针对特定的应用程序类型***的保护。
每个托管规则组都可以防范一组常见的,如 SQL 或命令行,下面我们看看在 WAF 中 AWS 提供了哪些托管规则组。
这里我们做个演示,在没有 WAF 加持的情况下是什么状况,加上 WAF 托管规则又是什么效果。
测试两种类型的模拟,一种是跨站脚本,还有一种是 SQL 注入***,如下:
export JUICESHOP_URL=
# This imitates a Cross Site Scripting attack
# This request should be blocked.
curl -X POST $JUICESHOP_URL -F "user=''"
# 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 以查看指标。