亚马逊云科技 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

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

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

相关文章

计算机毕设thinkphp+mysql+_vue房屋租赁系统h3sem

运行环境:phpstudy/wamp/xammp等 开发语言&#xff1a;php 后端框架&#xff1a;Thinkphp5 前端框架&#xff1a;vue.js 服务器&#xff1a;apache 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat/phpmyadmin 房屋租赁管理系统有不同的用户角色。不同的用户权限对应不…

【办公类-21-03】20240119 提取不连续的男女学号 set()和list法

背景需求&#xff1a;了解班级幼儿性别比例 查看点名册&#xff0c;发现中4班最初的学号是按照先男后女的方式排列&#xff0c;但是随着幼儿转出&#xff0c;空出一些学号&#xff0c;于是新插班的孩子就插入空的学号&#xff0c;空格插完了&#xff0c;就排在学号尾部。 我想…

Docker Consul详解与部署示例

目录 Consul构成 Docker Consul 概述 Raft算法 服务注册与发现 健康检查 Key/Value存储 多数据中心 部署模式 consul-template守护进程 registrator容器 consul服务部署&#xff08;192.168.41.31&#xff09; 环境准备 搭建Consul服务 查看集群信息 registrato…

YOLOv5改进 | 主干篇 | 华为GhostnetV1一种移动端的专用特征提取网络

一、本文介绍 本文给大家带来的改进机制是华为移动端模型Ghostnetv1,华为GhostnetV1一种移动端的专用特征提取网络,旨在在计算资源有限的嵌入式设备上实现高性能的图像分类。GhostNet的关键思想在于通过引入Ghost模块,以较低的计算成本增加了特征图的数量,从而提高了模型的…

深度剖析Spring循环依赖(实战Bug)

目录 前言1. 问题所示2. 原理分析3. 基本知识4. Lazy注解 前言 通过实战更好的回馈问题&#xff0c;意识更加深刻 起因是我出现如下问题之后&#xff0c;才意识到中了Spring的循环依赖了&#xff01; 1. 问题所示 在执行项目的时候&#xff0c;出现如下问题&#xff0c;问题…

面试之Glide如何绑定Activity的生命周期

Glide绑定Activity生命周期 Glide.with() 下面都是它的重载方法&#xff0c;Context&#xff0c;Activity&#xff0c;FragmentActivity, Fragment, android.app.Fragment fragment,View都可以作为他的参数&#xff0c;内容大同小异&#xff0c;都是先getRetriever&#xff0…

016-Vue-黑马2023:前后端分离开发(在线接口文档),前端工程化、Element、vue编写一个完成页面、Vue路由、vue打包部署到nginx

第三节 前后端分离开发 1、介绍 开发模式 前后端混合开发&#xff1a;传统开发模式 前后端分离开发&#xff1a;当前最为主流的开发模式 页面原型需求案例&#xff1a;分析出接口文档 离线开发文档示例&#xff1a; 2、YAPI&#xff08;官网已停用&#xff09; 202…

汽车微电机行业研究:预计2029年将达到188亿美元

微电机行业是技术密集型行业&#xff0c;其起源于欧洲的德国、瑞士等国家&#xff0c;发展于日本。随着改革开放&#xff0c;中国作为发展中国家&#xff0c;承接了德国、日本等发达国家的汽车微电机产业转移&#xff0c;技术扩散逐步向我国转移。 微特电机广泛应用于信息处理设…

优化微信小程序更新体验:异步更新与强制更新方案解析

在微信小程序的开发和迭代过程中&#xff0c;新版本覆盖率的问题一直备受关注。由于小程序采用异步更新机制&#xff0c;在用户首次打开或冷启动时才会检查并下载新版本&#xff0c;导致部分用户无法及时应用上最新版本。为了解决这一问题&#xff0c;微信团队经过深入研究和讨…

设计社交网络的数据结构

1: 确定 Use Case 和 约束 Use Cases User 搜索某人然后看到被搜索人的最短路径Service 有高可用 约束和假设 状态假设 Traffic 不是平均分布的 一些被搜索者是更加受欢迎的&#xff0c;某些被搜索者只会被搜索一次图数据不适用与单个机器图的分布是轻量级的一亿个 User每…

canvas绘制N角形,锯齿状

查看专栏目录 canvas实例应用100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

在线扒站网PHP源码-在线扒站工具网站源码

源码介绍 这是一款在线的网站模板下载程序&#xff0c;也就是我们常说的扒站工具&#xff0c;利用它我们可以很轻松的将别人的网站模板样式下载下来&#xff0c;这样就可以大大提高我们编写前端的速度了&#xff01;注&#xff1a;扒取的任何站点不得用于商业、违法用途&#…

kafka参数配置参考和优化建议 —— 筑梦之路

对于Kafka的优化&#xff0c;可以从以下几个方面进行思考和优化&#xff1a; 硬件优化&#xff1a;使用高性能的硬件设备&#xff0c;包括高速磁盘、大内存和高性能网络设备&#xff0c;以提高Kafka集群的整体性能。 配置优化&#xff1a;调整Kafka的配置参数&#xff0c;包括…

免费的爬虫软件【2024最新】

在国际市场竞争日益激烈的背景下&#xff0c;国外网站的SEO排名直接关系到网站在搜索引擎中的曝光度和用户点击量。良好的SEO排名能够带来更多的有针对性的流量&#xff0c;提升网站的知名度和竞争力。 二、国外网站SEO排名的三种方法 关键词优化&#xff1a; 关键词优化是SEO…

Red Hat Enterprise Linux 9.3 安装图解

引导和开始安装 选择倒计时结束前&#xff0c;通过键盘上下键选择下图框选项&#xff0c;启动图形化安装过程。需要注意的不同主板默认或者自行配置的固件类型不一致&#xff0c;引导界面有所不同。也就是说使用UEFI和BIOS的安装引导界面是不同的&#xff0c;如图所示。若手动调…

ITK + ANT,无法显示三维

背景&#xff1a;之前用ANT保存ima格式的数据&#xff0c;选择的是保存所有的序列 用python将dicom转为nii的格式&#xff0c; import nibabel as nib import torch"""不管是nii还是nii.gz都是二维的&#xff0c;为啥呢"""fobj nib.load("…

Qt弹框展示

1.相关说明 文件选择弹框、目录选择弹框、保存文件弹框、颜色选择弹框、字体选择弹框、进度条弹框、输入对话框、标准消息框等 2.相关界面 3.相关代码 #include "widget.h" #include "ui_widget.h" #include <QFileDialog> #include <QProgressD…

Red Hat Enterprise Linux 6.10 安装图解

引导和开始安装 选择倒计时结束前&#xff0c;通过键盘上下键选择下图框选项&#xff0c;启动图形化安装过程。需要注意的不同主板默认或者自行配置的固件类型不一致&#xff0c;引导界面有所不同。也就是说使用UEFI和BIOS的安装引导界面是不同的&#xff0c;如图所示。若手动调…

go 语言(九)----struct

定义一个结构体 type Book struct {title stringauth string }结构体使用 package mainimport "fmt"//定义一个结构体 type Book struct {title stringauth string }func main() {var book1 Bookbook1.title "Golang"book1.auth "zhang3"fmt…

使用 TiUP 部署 TiDB 集群

TIDB优点 支持分布式且支持事务的关系型数据库&#xff0c;不用考虑分库分表 同时满足了可伸缩&#xff0c;高可用&#xff0c;关系型&#xff0c;支持事务。 基本上按官网的文档来就行了。 在线部署 以普通用户身份登录中控机。以 tidb 用户为例&#xff0c;后续安装 TiUP …