【AWS征文】带你探秘 AWS WAF 如何抵挡各类***来保护你的应用安全

1、概述

什么是 WAF

AWS WAF 是一种 Web 应用程序防火墙,让您可以监控转发到 一个 Amazon CloudFront 分配、一个 Amazon API Gateway REST API 或一个 应用程序负载均衡器的 HTTP(S) 请求。它有助于保护您的 Web 应用程序或 API 免受可能影响可用性、危害安全性或消耗过多资源的常见 Web ***。html

使用 WAF 是向 Web 应用程序添加深度防护的一个很好的方法。一个 WAF 能够帮助下降诸如 SQL 注入、跨网站脚本***和其余常见***的风险。WAF 容许您建立本身的自定义规则,以决定是否在 HTTP 请求到达您的应用程序以前阻止或容许 HTTP 请求。linux

OWASP Juice Shop

为了测试 WAF 的拦截效果,咱们须要准备一个测试站点,目前比较流行的就是 OWASP Juice Shopweb

OWASP Juice Shop 多是最现代和最复杂的不安全的网络应用程序!它能够用于安全培训、意识演示、 CTFs,也能够做为安全工具的试验品!Juice Shop 包含了整个 OWASP 十大漏洞以及在现实世界应用程序中发现的许多其余安全漏洞!docker

安装 Juice Shop

由于咱们的测试环境在 AWS,咱们直接建立 EC2,在 EC2 上面部署 Juice Shop 站点进行测试。json

  1. 在 EC2 界面,选择启动一个实例
  2. 选择一个 AMI,咱们这里选择 Amazon Linux 2 AMI
  3. 配置实例的一些属性,而后把下面的启动脚本拷贝到用户数据里面
#!/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
  1. 配置好安全组,容许 80 端口流量进入
  2. 启动实例

建立 ALB

由于 WAF 不能直接添加到 EC2 上面,咱们须要给 EC2 建立一个 ALB。安全

  1. 导航到 Load Balancers 界面,选择建立 Application Load Balancer
  2. 选择面向互联网的,监听 80,选好好 EC2 主机所在的子网
  3. 从新建立一个目标组
  4. 注册机器
  5. 建立完成,访问 ALB 的 public DNS

image-20200815110456079

2、Web ACLs 和 Managed Rules

Web ACLs

Web ACL (Web Access Control List)是 AWS WAF 部署的核心资源。它包含对其接收的每一个请求求值的规则。Web ACL 经过 Amazon CloudFront distribution、 AWS API Gateway API 或 AWS Application Load Balancer 与您的 Web 应用程序相关联。bash

Managed Rules

开始使用 WAF 的最快方法是将 AWS WAF 的 AWS 托管规则组部署到 WebACL。网络

Managed Rule Groups 是一组规则,由 AWS 或 AWS 市场上的第三方建立和维护。这些规则提供了针对常见类型,或者针对特定的应用程序类型***的保护。负载均衡

每一个托管规则组均可以防范一组常见的***,如 SQL 或命令行***,下面咱们看看在 WAF 中 AWS 提供了哪些托管规则组。curl

image-20200815103846867

image-20200815103904651

使用托管规则组

这里咱们作个演示,在没有 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;"

咱们分别请求一下,看看是否能够***成功:

image-20200815133134879

image-20200815133216930

建立规则

经过测试看到,两种***都成功,下面咱们来建立 WAF,并和 ALB 进行关联,而后再进行测试

  1. 打开 AWS WAF Console 界面,选择建立 Web ACLs
  2. 类型选择 Regional,由于咱们的 EC2 在 US East 区域,选择 N. Virginia
  3. 在资源管理里面选择咱们的 ALB
  4. 选择 Add Rules > Add Managed Rule Groups
  5. 从 AWS 托管组里面选择 Core Rule Set 和 SQL Database

image-20200815133729597

image-20200815133746446

  1. 建立 web ACL

拦截测试

添加好托管规则组以后,咱们在模拟***查看效果。

image-20200815134103928

如今能够看到,所有拦截成功,经过咱们简单的配置,对通常常见的***很快拦截下载,保障的应用程序的安全。

3、自定义规则

若是你不使用 AWS 提供的托管规则组,WAF 容许您为处理请求建立本身的规则。这对于添加与特定应用程序相关的逻辑很是有用。

经过自定义规则,咱们能够检测一些 HTTP 请求的组件,好比:

  • Source IP
  • Headers
  • Body
  • URI
  • Query Parameters

经过这些检测,WAF 能够拦截或容许任何相关的请求。

特定***

在观察访日日志的过程当中,发现全部的***都带有一个请求头X-TomatoAttack,阻止这个请求头能够阻止全部的***,下面咱们将建立自定义规则来拦截这个请求头,在没有 WAF 加持的状况下面,咱们模拟***,查看状况。

curl -H "X-TomatoAttack: Red" "${JUICESHOP_URL}"
curl -H "X-TomatoAttack: Green" "${JUICESHOP_URL}"

image-20200815141037732

image-20200815141105054

建立规则

而后咱们建立自定义规则:

  1. 在 web ACL 中,选择添加 Custom Rule
  2. 在 Inspect 里面选择 Header
  3. 若是 X-TomatoAttack >=0,咱们就拦截请求

image-20200815141849044

拦截测试

规则添加好以后,咱们在进行测试,发现带有 X-TomatoAttack Header 的都被拦截,其余的 Header 能够正常请求。

image-20200815142143117

自定义规则容许您实现本身的逻辑来处理 WAF 中的请求。自定义规则能够检查请求的许多组件,而后在规则语句为真时采起行动阻止或容许请求。

每一个 Web ACL 都有一个最大的 Web ACL 容量单元(WCU)。这是1500,可是若是须要能够增长。Web ACL 中的每一个规则和规则组都有助于实现这一限制。

4、高级自定义规则

咱们已经建立了一个简单的 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
        }
      ]
    }
  }
}

如何制做复杂规则

好比咱们又收到了一个新的***,***具备以下特征:

  • 包含一个 body,大小超过 100kb
  • 缺乏请求头 x-upload-photo: true

这个复合规则比较复杂,难以使用 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
  }
}

有两点咱们须要注意:

  1. 若是请求 body 大于 100kb,阻止请求
  2. 若是请求不包含请求头 x-upload-body: true,阻止请求

咱们须要 OrStatementNotStatement 来表达规则逻辑。

{
"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
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

这样一个复杂的规则就一步步建立好了,能够抵挡特定的一些***。

***升级

假设咱们目前有一个复杂的规则组,能够阻挡包含下面任一条件的请求:

  1. 请求包含 header x-milkshake: chocolate,阻止请求
  2. 请求包含查询字符串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
              }
            ]
          }
        }
      ]
    }
  }
}

可是最近***者近期升级了***请求,如今的请求变为以下:

  1. 请求头包含 x-milkshake: chocolatex-favourite-topping: nuts
  2. 查询字符串包含milkshake=bananafavourite-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"

image-20200815170428990

在这一节,咱们为你们演示了如何经过 json 制定一个复杂的规则,这个规则是在 console 没法实现的。

5、测试新规则

在部署新规则以前,对其进行测试是相当重要的。这是为了确保您不会意外地阻止有效的请求。

到目前为止,在指定对请求采起什么操做时,您已经使用了 Block 和 Allow。还有第三个动做 Count。Count 容许您度量知足规则条件的请求数量。

Count 是一个非终止操做。当请求与 Count 操做匹配规则时,web ACL 将继续处理其他的规则。

当具备 Count 的规则动做被匹配时,事件将做为 CloudWatch 指标发出。要查看规则的计数,请到 CloudWatch 指标控制台。选择 AWS/WAFv2,而后选择 Region、 Rule、 WebACL 以查看指标。

欢迎你们扫码关注,获取更多信息

【AWS征文】带你探秘 AWS WAF 如何抵挡各类***来保护你的应用安全

相关文章
相关标签/搜索