亚马逊云科技 WAF 部署小指南(六)追踪 Amazon WAF Request ID,排查误杀原因

352343ca6db03fcb4a991cb650b04b41.gif

众所周知,中国是全球制造业的巨大力量,许多中国企业通过 2B 电商平台网站进行商品销售和采购。在这些电商平台上,Web 应用防火墙(WAF)成为不可或缺的安全工具。然而,WAF 也可能导致误杀问题。一旦误杀发生,网站管理员需要尽快解决,以免企业客户无法正常下单,造成巨大的损失。而要解决误杀问题,首先需要有能够定位相关日志的线索。

本文将介绍如何利用 Amazon Lambda@Edge,在 Amazon CloudFront 自定义错误页面上展示每个由 Amazon WAF 返回的“403 Forbidden”错误的 Request ID。通过这个唯一的 WAF Request ID,网站运维工程师能够快速查询相应的 WAF 日志,找到误杀的原因。随后,可以配置 Scope-down 来修复误杀问题。

  • Amazon CloudFront 自定义错误页面:

    https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/GeneratingCustomErrorResponses.html

  • Scope-down:

    https://docs.aws.amazon.com/zh_cn/waf/latest/developerguide/waf-rule-scope-down-statements.html

01

工作原理

CloudFront 的请求事件包含有 requestId 字段,每一个请求都有一个唯一的 Request ID 作为标识。以下是 Lambda@Edge 请求事件的 requestId 数据结构。

  • 请求事件:

    https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html#lambda-event-structure-request

  • Request ID:

    https://repost.aws/zh-Hans/knowledge-center/cloudfront-latency-diagnosis-data

{
  "Records": [
    {
      "cf": {
        "config": {
          "eventType": "viewer-request",
          "requestId": "4TyzHTaYWb1GX1qTfsHhEqV6HUDd_BzoBZnwfnvQc_1oF26ClkoUSEQ=="
        },
      }
    }
  ]
}

左滑查看更多

如图 1 所示,CloudFront 自定义错误页面是由 CloudFront(而不是 Client)发起的,它的 Request ID 与 Client 原始请求的 Request ID 相同。因此,我们使用 Lambda@Edge 捕获自定义错误页面的请求,从请求事件中读取 Request ID,插入到预先定义好的 HTML 代码中,直接将这个 HTML 作为 Response body 返回给 CloudFront。

18b28c6376803fa95deb6ecf340cd5ba.png

图 1:CloudFront 自定义错误页面展示 WAF Request ID 的工作流程

02

配置步骤

1. 为 HTTP 状态码 403 

创建 CloudFront 自定义错误页面

ad375766cfdc4ead92a5ad41f7740b12.png

图 2:为 HTTP 状态码 403 创建 CloudFront 自定义错误页面

按照图 2 所示的方法,为 HTTP 状态码 403 创建 CloudFront 自定义错误页面,并配置错误页面的缓存时间(TTL)和错误页面的 URI path。这个步骤需要注意:

  • Client 看到的 403 错误页面的 Request ID 都应该是唯一的,所以需要设置“Error caching minimum TTL”为“0”,即不缓存。

  • 为了避免错误页面的 URI 受到 DDoS 攻击,产生不必要的 Lambda@Edge 费用,需要将这个 URI path 设置的尽量长一些,复杂一些。我们建议随机生成一个 Universally Unique ID(UUID)作为错误页面的 URI path,并且不要泄露这个 UUID。这个 URI path 所对应的网页并不需要真正存储在源站,因为 Lambda@Edge 会提前终结 CloudFront 的请求。

2. 为 CloudFront 自定义错误页面的 URI path

单独创建一个 Cache Behavior

我们目的是只允许 CloudFront 向自定义错误页面发起的请求才能触发 Lambda@Edge,因此,需要为自定义错误页面的 URI path 单独创建一个 Cache behavior,单独关联 Lambda@Edge 函数。

  • Cache behavior:

    https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#DownloadDistValuesCacheBehavior

60673f1ac61b3d1f7e63c31d687e8808.png

图 3:为 CloudFront 自定义错误页面的 URI path 单独创建一个 Cache Behavior

如图 3 所示,这个 Behavior 所配置的缓存策略必须是“Managed-CachingDisabled”。任何一个 Maximum TTL>0 的缓存策略都会使得 CloudFront 向自定义错误页面发起的请求无法触发 Viewer request Lambda@Edge 函数,而只能触发 Origin request Lambda@Edge 函数。

3. 创建 Lambda@Edge 函数,

并添加 CloudFront viewer request trigger

复制以下 Python 代码,创建一个 Runtime 为 Python3.X,Architecture 为 X86_64 的 Lambda 函数。您可以编辑 CONTENT 变量的值——它实际上就是一个 HTML 网页的代码。您可以根据需求调用合适的 CSS 文件,插入您想要的图片。

CONTENT = '''
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>WAF custom error page</title>
    <link rel="stylesheet" href="/css/style.css"/>
  </head>
  <body>
    <h1>403 Forbidden!</h1>
    <p>Your request was blocked.</p>
    <p>Request ID: <span id="requestId">{CF_RID}</span></p>
    <button onclick="copyToClipboard()">Copy Request ID</button>
    <div id="copyMessage"></div>
    <script>
      function copyToClipboard() {
        var requestId = document.getElementById("requestId").innerText;
        var tempTextArea = document.createElement("textarea");
        tempTextArea.value = requestId;
        document.body.appendChild(tempTextArea);
        tempTextArea.select();
        document.execCommand("copy");
        document.body.removeChild(tempTextArea);
        document.getElementById("copyMessage").textContent = "Copied!";
      }
    </script>
  </body>
</html>
'''


def lambda_handler(event, context):
    record = event['Records'][0]['cf']
    request_id = record['config']['requestId']
    response = CONTENT.replace('{CF_RID}', request_id)
    return {
        'status': 403,
        'statusDescription': 'Forbidden',
        'headers': {
                'content-type': [{
                    'key': 'Content-Type',
                    'value': 'text/html'
                }]
            },
        'body': response
    }

左滑查看更多

如图 4 所示,为这个 Lambda 函数添加一个 Trigger。Resource 类型为“CloudFront”,Event type 类型为“viewer-request”,Path pattern 为 CloudFront 自定义错误页面的 URI path。

8f4870ec7911be3e47f6304317bbeb3a.png

图 4:为 Lambda 函数添加 Trigger

4. 创建 WAF WebACL 

并关联 CloudFront distribution

最后,我们创建一个 WAF WebACL,配置一个 WAF 规则,匹配 URI path /waf-id 来产生 Block 的动作。另外,我们还创建了一个限速规则匹配 URI path /rate-based-rule 并配置了 WAF 自定义响应。我们会在下文介绍这样做的目的。

a3e197f17126094e58c84e7620ee18cf.png

图 5:配置 WAF WebACL 用于测试 Block 动作

03

CloudFront 自定义错误页面

展示 WAF Request ID 的效果

浏览器访问 https://d123.cloudfront.net/waf-id,触发了 WAF block 动作,成功显示如图 6 所示的自定义错误页面(截图中的几个 JS 脚本是 Chrome 浏览器的插件所产生的,与本次测试无关)。

372ff3b54803bef9c55cf1e253c17209.png

图 6:自定义错误页面和 WAF unique request ID 测试结果

测试结果如下:

  • 自定义错误页面可以显示 CloudFront request ID,并且和 X-Amz-Cf-Id response header 的值相同

  • 每一次请求都可以得到不同的 Request ID

  • 浏览器无法观察到 CloudFront 自定义错误页面的真实 URI path

  • 点击“Copy Request ID”按钮即可将 Request ID 复制到操作系统剪切板

04

通过 Request ID 查询 WAF 日志的方法

企业客户通常习惯于使用在线通讯工具直接与网站运营方联系。在遇到 WAF 误杀时,他们通常使用通讯工具向网站提供错误页面的截图。我们的错误页面提供一键复制 Request ID 的按钮,企业客户也可以很方便地使用通讯工具发送 Request ID 的文本。网站运维工程师在收到 Request ID 之后,即可在 WAF 日志监控系统上查询到对应的 WAF 拦截日志。具体的查询方法取决于监控 WAF 日志的方式。

在 Centralized Logging with OpenSearch 

监控平台上查询 Request ID

如果网站使用了 Centralized Logging with OpenSearch 解决方案监控 WAF 日志,可以在仪表盘上添加“Request ID”作为过滤条件。

  • Centralized Logging with OpenSearch 解决方案:

    https://aws.amazon.com/cn/solutions/implementations/centralized-logging-with-opensearch/

步骤如下:

1)点击仪表盘右上角的“Edit”按钮

c5e9d722c6225cb93eec5462b548bfcd.png

2)点击“Filters”面板右上角的齿轮图标,再点击“Edit visualization”菜单

0994c57536d8159146d05915d6f5aa97.png

3)“Add”一个 Options list,输入 Control Label 名称,选择 Index Pattern,Field 选择 httpRequest.requestId.keyword

c8c14e662be1097fc6b2c770d0b7b044.png

4)点击网页右下角蓝色的“Update”按钮,更新 Visualization

5)点击网页右上角“Save”按钮,保存对仪表板所做的更改

Centralized Logging with OpenSearch 的仪表盘支持模糊查询。虽然 WAF Request ID 比较长,但只需要输入几个字符就可以找到完整的 Request ID,进而找到对应的 WAF 日志。

2dcf312f99d85526f06b8d6f1dcb7761.png

图 7:使用 Centralized Logging with OpenSearch 检索 Request ID

使用 Amazon CloudWatch Log Insight 

查询 Request ID

如果 WAF 日志保存在 CloudWatch log group,可以使用下面的 CloudWatch log insight 查询语句检索 Request ID:

fields @message, httpRequest.requestId as requestId
| filter requestId = "tMzyyrTJhk5XiBbowY2v-WY5m-PGluVYKggI6KIJhlTHBlqpDEGQOQ=="    # 替换成需要检索的Request ID.
| display @message

左滑查看更多

也可以使用 like 方法进行模糊查询:

fields @message, httpRequest.requestId as requestId
| filter requestId like "tMzyy"    # 替换成需要检索的 Request ID
| display @message

左滑查看更多

下面的图 8 是 CloudWatch log insight- 检索结果的部分截图。点击左边的黑色三角形符号,即可展开完整的日志。

5d3267003c426b29e8b60b1ca4f11830.png

图 8:CloudWatch log insight 检索 Request ID 的部分截图

使用 Amazon Athena 查询 Request ID

如果 WAF 日志保存在 Amazon S3 桶,并且没有使用 OpenSearch 等工具创建仪表盘,则先创建 WAF 日志表,再使用下面的 SQL 语句检索 Request ID,并使用 like 方法进行模糊查询:

  • WAF 日志表:

    https://docs.aws.amazon.com/zh_cn/athena/latest/ug/waf-logs.html

select from_unixtime(timestamp/1000) as datetime, * from "waf_log_db"."waf_request_id"
where httprequest.requestid like '%mLNIV%'

左滑查看更多

您需要将“waf_request_id”替换成您自己的数据表的名字,并将“mLNIV”替换成您希望检索的 Request ID(需要保留前后两个“%”符号)。下面的图 9 是 Athena 检索结果的部分截图,向右滚动页面即可显示所有日志字段。

da2cedba086c7c10769d63759a2a5df2.png

图 9:Athena 检索 Request ID 的部分截图

成本估算

假设每月 10 Billion WAF 请求,其中 0.1% 为 Blocked 请求,即 10 Million。Lambda@Edge 内存 128GB,保守估计平均每个请求 Duration 为 5ms。使用 Amazon 价格计算器评估的每月 Lambda@Edge 含免费套餐的成本为 1.80 USD,不含免费套餐的成本为 2.10 USD。

另外,CloudFront 自定义页面所返回的 HTML 和 CSS 也会增加少量的数据流出(DTO)费用。本文所使用的 HTML 和 CSS,加上它们的 HTTP response headers,一共不到 2KB。10 Million 请求一共产生 20GB 的 DTO,没有超出免费套餐。如果不考虑免费套餐,每月产生大约 2 USD 的 CloudFront DTO 成本。如果不使用 CSS 美化自定义页面,成本可以更低。

  • Amazon 价格计算器:

    https://calculator.aws/#/addService/Lambda

05

避免 DDoS 事件消耗 Lambda@Edge 成本

上文“配置步骤 1”介绍了使用 UUID 作为 CloudFront 自定义错误页面的 URI path,避免错误页面的 URI 受到 DDoS 攻击,产生不必要的 Lambda@Edge 费用。另外,HTTP Flood 等 DDoS 攻击会触发 WAF 限速规则产生大量的 403 error。我们通常不需要关注限速规则的误杀,所以不需要使用 Lambda@Edge 函数为限速规则的 Block 动作展示 WAF Request ID。解决办法是使用 WAF 自定义响应覆盖 CloudFront 自定义错误页面。

按照图 10 的方法,为 WAF 规则的 Block 动作配置自定义响应。WAF 自定义响应的优先级高于 CloudFront 自定义错误页面,所以限速规则返回的 403 error 并不会触发 CloudFront 请求自定义错误页面,因此也不会触发 Lambda@Edge 函数。

8aafe9b5717c6f65375a34047bff7c42.png

图 10:为 WAF 规则配置自定义响应

WAF 自定义响应的测试结果

我们在之前的“配置步骤 4”已经创建了一个限速规则,匹配 URI path /rate-based-rule 并配置了 WAF 自定义响应。测试效果如图 11 所示:

e8b597ae0d073b47b27a0e4dbc09f3d2.png

图 11:WAF自定义响应测试结果

对于其他(几乎)不会产生误杀的规则,在错误页面展示 Request ID 并不必要,都可以按此方法为它们配置 WAF 自定义响应,避免执行 Lambda@Edge 函数。

06

方案总结

按照本文所介绍的方法,仅需支付少量的 Lambda@Edge 和 CloudFront DTO 费用,完成简单的配置操作,即可实现 WAF unique request ID 解决方案。通过唯一的 WAF request ID,网站管理员可以快速排查和解决误杀问题,缩短 WAF 规则的评估时间,改善用户体验。这个解决方案也适用于 Amazon ALB,Amazon API Gateway,以及其他所有能够作为 CloudFront 源站的 Web 应用或服务。只需要部署 CloudFront distribution 加速 ALB、API Gateway 或其他 Web 应用,并将 WAF WebACL 关联到 CloudFront distribution,即可支持 403 错误页面显示 WAF unique request ID。同时,CloudFront 还提供边缘加速,并降低 Amazon 源站的 DTO 成本。

本篇作者

8e678148c551f9b4cc6bcef3378bc5d1.jpeg

陈程

亚马逊云科技边缘产品架构师,有多年 OTT 行业相关的工作经验,熟悉云网络、CDN 和 WAF。非工作时间忙于抚养一娃俩猫。

ced1ee23d2f42179462377f3e04e0716.gif

星标不迷路,开发更极速!

关注后记得星标「亚马逊云开发者」

f6c8a29a7490d98ad09aba94846d26f9.gif

听说,点完下面4个按钮

就不会碰到bug了!

be1cd117f252bee0a25552568aa9c5aa.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/334957.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CodeReview 小工具

大家开发中有没有遇到一个版本开发的非常杂&#xff0c;开发很多个项目&#xff0c;改动几周后甚至已经忘了自己改了些什么&#xff0c;领导要对代码review的时候&#xff0c;理不清楚自己改过的代码&#xff0c;只能将主要改动的大功能过一遍。这样就很容易造成review遗漏&…

从技术大会到面试舞台:程序猿的蜕变之旅!

在这个技术日新月异的时代&#xff0c;程序员们需要不断地学习和提升自己的技能。 参加技术大会&#xff0c;无疑是程序员们拓宽视野、提升技能的重要途径之一。然而&#xff0c;技术大会只是程序员成长的一部分&#xff0c;掌握面试技巧同样至关重要。只有将这两者完美结合&a…

ubuntu-20.04.6-live-server-amd64安装教程-完整版

简介 Ubuntu 20.04.6 Live Server AMD64 安装教程 - 完整版" 提供了详细的指南&#xff0c;旨在帮助用户在使用 AMD64 架构的服务器上安装 Ubuntu 20.04.6 Live Server 版本。该教程包含全面的步骤和详细说明&#xff0c;使用户能够顺利完成整个安装过程&#xff0c;建立…

【AI的未来 - AI Agent系列】【MetaGPT】5. 更复杂的Agent实战 - 实现技术文档助手

在 【AI的未来 - AI Agent系列】【MetaGPT】2. 实现自己的第一个Agent 中&#xff0c;我们已经实现了一个简单的Agent&#xff0c;实现的功能就是顺序打印数字。 文章目录 0. 本文实现内容1. 实现思路2. 完整代码及细节注释 0. 本文实现内容 今天我们来实现一个有实际意义的Ag…

test0120测试1

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 磁盘满的本质分析 专栏&#xff1a;《Linux从小白到大神》 | 系统学习Linux开发、VIM/GCC/GDB/Make工具…

项目实战————苍穹外卖(DAY11)

苍穹外卖-day11 课程内容 Apache ECharts 营业额统计 用户统计 订单统计 销量排名Top10 功能实现&#xff1a;数据统计 数据统计效果图&#xff1a; 1. Apache ECharts 1.1 介绍 Apache ECharts 是一款基于 Javascript 的数据可视化图表库&#xff0c;提供直观&#x…

小红书怎么种草?小红书种草玩法全攻略你不容错过!

小红书是一个以分享购物心得和生活方式为主题的社交平台&#xff0c;近年来已经成为了许多品牌进行宣传和推广的重要渠道。那么&#xff0c;品牌如何在小红书上种草&#xff0c;打造自己的形象呢&#xff1f;以下是一些实用的方法。 1.选择合适的KOL合作 在小红书上&#xff0…

完整的性能测试流程

一、准备工作 1、系统基础功能验证 性能测试在什么阶段适合实施&#xff1f;切入点很重要&#xff01;一般而言&#xff0c;只有在系统基础功能测试验证完成、系统趋于稳定的情况下&#xff0c;才会进行性能测试&#xff0c;否则性能测试是无意义的。 2、测试团队组建 根据…

EasyRecovery2024免费电脑数据恢复软件下载

easyrecovery是一款功能强大、易于使用的硬盘数据恢复软件。这款软件可以帮助用户非常方便地恢复丢失的数据。软件非常容易使用和高效的数据恢复。感兴趣的朋友们赶快来下载吧。 无论是因为意外删除、格式化、病毒感染、系统崩溃还是其他原因&#xff0c;该软件可以帮助您恢复…

mybatis xml多表查询,子查询,连接查询,动态sql

项目结构 数据库表 student_type 表 student 表 依赖 <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.30</version></dependency><dependency><groupId>org.…

回溯算法篇-01:全排列

力扣46&#xff1a;全排列 题目分析 这道题属于上一篇——“回溯算法解题框架与思路”中的 “元素不重复不可复用” 那一类中的 排列类问题。 我们来回顾一下当时是怎么说的&#xff1a; 排列和组合的区别在于&#xff0c;排列对“顺序”有要求。比如 [1,2] 和 [2,1] 是两个不…

小白进阶之字符串处理

#include <cstdio> #include <cstring> int main() {char str[105];int count0,len0;scanf("%s",str);//输入字符lenstrlen(str);//求字符长for(int i0;i<len;i){if(str[i]A)//匹配计数count;}printf("%d",count); }#include <cstdio>…

test0120测试2

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 磁盘满的本质分析 专栏&#xff1a;《Linux从小白到大神》 | 系统学习Linux开发、VIM/GCC/GDB/Make工具…

day05_流程控制语句

今日内容 零、 复习昨日 一、流程控制语句 零、 复习昨日 1 解释/(除法)的特殊点 整数相除,除不尽舍弃小数 2 i和i有什么相同点和不同点 都会自增 1i,先用后自增,i先自增后用以后经常使用的就是i,并不会特别区分前后 3 && 短路与,是如何短路的? 第一个式子会错,后面式…

程序员的福利到了,轮转数组,经典算法实战

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

知识图谱的演进

目录 前言1 Memex&#xff1a;信息存储的雏形2 超文本和Web&#xff1a;链接的崛起3 Semantic Web&#xff1a;从文本链接到数据链接4 Linked Big Data&#xff1a;规范化的语义表示5 谷歌的知识图谱搜索引擎6 多种语义网/知识图谱项目结语 前言 随着人工智能和互联网的飞速发…

从零开始配置vim(Windows版)

linux下vim用习惯了...然后就给自己win下vscode也装了个vim插件&#xff0c;用下来还是感觉不顺手&#xff0c;并且处理太多文本时有明显卡顿&#xff0c;于是乎自己配了下win版的vim。 不过好像也并不是从零开始的...初始基础版的.vimrc有copy他们版本&#xff0c;在此基础上进…

Vue 2生命周期已达终点,正式结束使命

Vue.js是一款流行的JavaScript框架&#xff0c;拥有广泛的应用和开发者社区。自Vue.js 2发布以来&#xff0c;它在前端开发中扮演了重要角色&#xff0c;并且被广泛采用。然而&#xff0c;技术的发展是无法阻挡的&#xff0c;随着2024年的到来&#xff0c;Vue 2的生命周期也走到…

Qt 5.15.2 (MSVC 2019)编译 QWT 6.2.0 : 编译MingW或MSVC遇到的坑

MingW下编译QWt 6.2.0 下载qwt最新版本&#xff0c;用git工具 git clone下载源码 git clone https://git.code.sf.net/p/qwt/git qwt-git 或者使用我下载的 qwt 2.6.0 链接&#xff1a;https://pan.baidu.com/s/1KZI-L10N90TJobeqqPYBqw?pwdpq1o 提取码&#xff1a;pq1o 下载…

二叉树的基础概念及遍历

二叉树(Binary Tree)的基础 1、树的概念 1、树的概念 树是一种非线性的数据结构&#xff0c;是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合&#xff0c;将它称为树&#xff0c;是因为在形状上像一颗倒着的树&#xff0c;如下图所示就是一颗二叉…