【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 如何抵擋各類***來保護你的應用安全

相關文章
相關標籤/搜索