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

news2024/9/23 21:32:42

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Deep MultimodalLearningA survey on recent advances and trends

深度多模态学习&#xff1a;对近期进展和趋势的综述 深度学习的成功已经成为解决越来越复杂的机器学习问题的催化剂&#xff0c;这些问题通常涉及多个数据模态。我们回顾了深度多模态学习的最新进展&#xff0c;并突出了该活跃研究领域的现状&#xff0c;以及存在的差距和挑战…

Java中打印图案最常用的25个图案程序

Java是公认的最流行的编程语言&#xff0c;因为它的简单性和多功能性。还可以使用它开发各种应用程序&#xff0c;包括Web、移动和桌面应用程序。此外&#xff0c;Java为开发人员提供了强大的工具来轻松高效地创建复杂的程序。Java最有前途的特性之一是它能够创建可以以特定格式…

爬虫-selenium自动化(3)-验证码

#验证码分很多种&#xff0c;奇葩也无处不在:哪个是真茅台&#xff0c;红绿灯&#xff0c;摩托车......(我是个人都看不出来) (๑﹏๑) #本节内容为selenium自动化实现验证码通过-------字符验证码&#xff0c;点触验证码。 验证码介绍 字符验证码案例 点触验证码案例

[Python] scikit-learn之mean_squared_error函数(Mean Squared Error(MSE))介绍和使用案例

什么是均方误差(MSE)和均方根误差(RMSE)? MSE 是均方误差(Mean Squared Error)的缩写&#xff0c;是一种常用的衡量回归模型预测精度的指标。它表示预测值与真实值之间差异的平方和的平均值&#xff0c;通常用于评估回归模型的性能。 RMSE 是均方根误差(Root Mean Squared Er…

C#,字符串匹配(模式搜索)有限自动机(Finite Automata)算法的源代码

一、有限状态自动机 图中两个圆圈&#xff0c;也叫节点&#xff0c;用于表示状态&#xff0c;从图中可以看成&#xff0c;它有两个状态&#xff0c;分别叫0和1。从每个节点出发&#xff0c;都会有若干条边。当处于某个状态时&#xff0c;如果输入的字符跟该节点出发的某条边的内…

tomcat与servlet

目录 一、Http服务器 二、tomcat 1、概念 2、tomcat解压缩文件 &#xff08;1&#xff09;bin文件夹 &#xff08;2&#xff09;conf文件夹 &#xff08;3&#xff09;logs &#xff08;4&#xff09;webapps 3、借助tomcat服务器访问网页 三、servlet 1、概念 2、s…

阿里云有哪些优势?为什么选择阿里云?

为什么选择阿里云&#xff1f;阿里云服务器有哪些优势&#xff1f;阿里云全球第三&#xff0c;国内第一云&#xff0c;阿里云服务器网aliyunfuwuqi.com分享云服务器ECS在丰富ECS实例架构、弹性灵活、稳定可靠、便捷易用、安全保障和成本优化多方面优势&#xff1a; 阿里云服务…

【Linux】磁盘结构 | 文件系统 | 软硬链接

文件的状态有被打开和没有被打开&#xff0c;之前谈到一个文件被进行读写&#xff0c;就要打开加载到内存中&#xff0c;通过对应的系统调用&#xff0c;fd文件描述符的管理&#xff0c;write和read等函数的增删查改。并且借助缓冲区对文件属性和内容的修改。 大部分文件是没有…

高级架构师是如何设计一个系统的?

架构师如何设计系统&#xff1f; 系统拆分 通过DDD领域模型&#xff0c;对服务进行拆分&#xff0c;将一个系统拆分为多个子系统&#xff0c;做成SpringCloud的微服务。微服务设计时要尽可能做到少扇出&#xff0c;多扇入&#xff0c;根据服务器的承载&#xff0c;进行客户端负…

HFSS实战(一)——仿真PCB微带线的损耗

文章目录 一、ODB文件的导出二、PCB文件导入2.1 pcb文件导入2.2层叠设置 三、模型的裁剪四、模型的简化五、端口设置六、将3D LAYOUT模型导出成HFSS模型七、HFSS仿真结束 主要学习目标&#xff1a;利用HFSS3D layout 完成微带线的电磁仿真 利用一个简单的仿真&#xff0c;完成…

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

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

2023.1.19 关于 Redis 事务详解

目录 Redis 事务对比 MySQL 事务 MySQL 事务 Redis 事务 Redis 事务原子性解释 Redis 事务详解 执行流程 典型使用场景 Redis 事务命令 WATCH 的使用 WATCH 实现原理 总结 阅读下文之前建议点击下方链接了解 MySQL 事务详解 MySQL 事务详解 Redis 事务对比 MySQL 事…

探索设计模式的魅力:一篇文章让你彻底搞懂建造者模式

建造者模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;旨在将一个复杂对象的创建过程与其表示分离&#xff0c;使得同样的构建过程可以创建不同的表示形式。 主要角色&#xff1a; 产品&#xff08;Product&#xff09;&#xff1a;表示正在构建…

小程序系列--9.生命周期

1. 什么是生命周期&#xff1f; 2. 生命周期的分类 3. 什么是生命周期函数 4. 生命周期函数的分类 5. 应用的生命周期函数 6. 页面的生命周期函数

SpringCloud Aliba-Sentinel【中篇】-从入门到学废【5】

目录 1.流控规则 2. 熔断规则 3.热点规则 1.流控规则 1.资源名&#xff1a;唯一名称&#xff0c;默认请求路径 2.针对来源: Sentinel可以针对调用者进行限流,填写微服务名,默认default (不区分来源) 3.阈值类型/单机阈值&#xff1a; QPS&#xff08;每秒钟的请求数量&…

pytorch学习(一)线性模型

文章目录 线性模型pytorch使用sklearn训练 pytorch是一个基础的python的科学计算库&#xff0c;它有以下特点&#xff1a; 类似于numpy&#xff0c;但是它可以使用GPU可以用它来定义深度学习模型&#xff0c;可以灵活的进行深度学习模型的训练和使用 线性模型 线性模型的基本形…

Studio One2024免费版下载及入门教程分享

众所周知&#xff0c;Studio One是一个专业的音频编辑软件&#xff0c;近几年随着音视频剪辑越来越火&#xff0c;Studio One也逐渐被人们所熟知。最近&#xff0c;就有许多小伙伴私信我&#xff0c;寻求Studio One的入门教程。 这不&#xff0c;今天小编就给大家带来了音频剪…

iphone5s基带部分电源部分主主电源供电及

时序: 1.,基带电源的供电&#xff0c;基带电源也叫pmu。 首先时序图说电池提供供电&#xff0c;电池是J6接口&#xff0c;视频习惯把接口称之为座子。查U2_RF芯片&#xff0c;发现供电信号为PP_BATT_VCC_CONN&#xff0c;但是没查到跟电池座子有关系&#xff0c;电池座子写的是…

Flask框架小程序后端分离开发学习笔记《1》网络知识

Flask框架小程序后端分离开发学习笔记《1》网络知识 Flask是使用python的后端&#xff0c;由于小程序需要后端开发&#xff0c;遂学习一下后端开发。 一、网址组成介绍 协议&#xff1a;http&#xff0c;https (https是加密的http)主机&#xff1a;g.cn zhihu.com之类的网址…

Python使用pyechart分析疫情确诊人数图(2024)

import json from pyecharts.charts import Map from pyecharts import options as opts# 首先打开文件获取数据 f open("/Desktop/python/Project/数据可视化/疫情.txt", "r", encoding"UTF-8") data f.read()# 字符串转化成json数据 data_js…