亚马逊云科技 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.rhkb.cn/news/241950.html

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

相关文章

postgresql安装

一、官方找到对应的版本,下载 官方下载地址(rpm方式安装):PostgreSQL: Linux downloads (Red Hat family) PostgreSQL: The worlds most advanced open source database 滑到最下面

C# 图解教程 第5版 —— 第22章 命名空间和程序集

文章目录 22.1 引用其他程序集22.2 命名空间22.2.1 命名空间名称22.2.2 命名空间的补充22.2.3 命名空间跨文件伸展22.2.4 嵌套命名空间 22.3 using 指令22.3.1 using 命名空间指令22.3.2 using 别名指令22.3.3 using static 指令 22.4 程序集的结构22.5 程序集标识符22.6 强命名…

JS执行顺序

众所周知&#xff0c;JavaScript 是单线程语言,只能同时执行做一件事(js只有一个线程&#xff0c;称之为main thread-主线程) 1.Javascript 运行机制 main thread 主线程和 call-stack 调用栈(执行栈)&#xff0c;所有的任务都会被放到调用栈等待主线程执行。 2.Javascript 任…

【Vue】vue项目中Uncaught runtime errors:怎样关闭

vue项目中Uncaught runtime errors:怎样关闭 一、背景描述二、报错原因三、解决方案3.1 只显示错误信息不全屏覆盖3.2 取消全屏覆盖 四、参考资料 一、背景描述 项目本来运行的好好&#xff0c;换了个新的浏览器&#xff0c;新的Chrome浏览器版本号是116.0.5845.97&#xff08…

Windows系统下使用docker-compose安装mysql8和mysql5.7

windows环境搭建专栏&#x1f517;点击跳转 win系统环境搭建&#xff08;十四&#xff09;——Windows系统下使用docker安装mysql8和mysql5.7 文章目录 win系统环境搭建&#xff08;十四&#xff09;——Windows系统下使用docker安装mysql8和mysql5.7MySQL81.新建文件夹2.创建…

【 Qt 快速上手】-①- Qt 背景介绍与发展前景

文章目录 1.1 什么是 Qt1.2 Qt 的发展史1.3 Qt 支持的平台1.4 Qt 版本1.5 Qt 的优点1.6 Qt的应用场景1.7 Qt的成功案例1.8 Qt的发展前景及就业分析行业发展方向就业方面的发展前景 1.1 什么是 Qt Qt 是一个跨平台的 C 图形用户界面应用程序框架。它为应用程序开发者提供了建立…

路飞项目--02

补充&#xff1a;axios封装 # 普通使用&#xff1a;安装 &#xff0c;导入使用 const filmListreactive({result:[]}) axios.get().then() async function load(){let responseawait axios.get()filmList.resultresponse.data.results } # 封装示例&#xff1a;请求发出去之前…

【Qt】对象树与坐标系

需要云服务器等云产品来学习Linux的同学可以移步/-->腾讯云<--/-->阿里云<--/-->华为云<--/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;新用户首次下单享超低折扣。 目录 一、Qt Creator快捷键 二、对象树 1、对象树的析构 2、自定义类的编写…

SpringBoot中整合ElasticSearch快速入门以及踩坑记录

场景 若依前后端分离版手把手教你本地搭建环境并运行项目&#xff1a; 若依前后端分离版手把手教你本地搭建环境并运行项目_本地运行若依前后端分离-CSDN博客 参考上面搭建项目。 ElaticSearch Elasticsearch 是java开发的&#xff0c;基于 Lucene 的搜索引擎。它提供了一…

SQL注入实战操作

一&#xff1a;SQl注入分类 按照注入的网页功能类型分类&#xff1a; 1、登入注入&#xff1a;表单&#xff0c;如登入表单&#xff0c;注册表单 2、cms注入&#xff1a;CMS逻辑:index.php首页展示内容&#xff0c;具有文章列表(链接具有文章id)、articles.php文 章详细页&a…

29、WEB攻防——通用漏洞SQL注入增删改查盲注延迟布尔报错

文章目录 盲注增删改查 盲注 概念&#xff1a;在注入过程中&#xff0c;获取的数据不能回显至前端页面&#xff0c;此时我们需要利用一些方法进行判断或尝试&#xff0c;这个过程被称为盲注。 解决&#xff1a;常规的联合查询注入不行的情况。 分类&#xff1a; 基于布尔的SQ…

Spring | Spring中的Bean--下

Spring中的Bean: 4.Bean的生命周期5.Bean的配装配式 ( 添加Bean到IOC容器的方式 依赖注入的方式 )5.1 基于XML的配置5.2 基于Annotation (注解) 的装配 (更常用&#xff09;5.3 自动装配 4.Bean的生命周期 Spring容器可以管理 singleton作用域的Bean的生命周期&#xff0c;在此…

什么是OSPF?为什么需要OSPF?OSPF基础概念

什么是OSPF&#xff1f; 开放式最短路径优先OSPF&#xff08;Open Shortest Path First&#xff09;是IETF组织开发的一个基于链路状态的内部网关协议&#xff08;Interior Gateway Protocol&#xff09;。 目前针对IPv4协议使用的是OSPF Version 2&#xff08;RFC2328&#x…

《Python数据分析技术栈》第01章 02 Jupyter入门(Getting started with Jupyter notebooks)

02 Jupyter入门&#xff08;Getting started with Jupyter notebooks&#xff09; 《Python数据分析技术栈》第01章 02 Jupyter入门&#xff08;Getting started with Jupyter notebooks&#xff09; Before we discuss the essentials of Jupyter notebooks, let us discuss…

DC-3靶机刷题记录

靶机下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1-P5ezyt5hUbmmGMP4EI7kw?pwdrt2c 提取码&#xff1a;rt2c 参考&#xff1a; http://t.csdnimg.cn/hhPi8https://www.vulnhub.com/entry/dc-32,312/ 官网http://t.csdnimg.cn/5mVZ7DC-3 (1).pdfhttps://…

软件是什么?前端,后端,数据库

软件是什么&#xff1f; 由于很多东西没有实际接触&#xff0c;很难理解&#xff0c;对于软件的定义也是各种各样。但是我还是不理解&#xff0c;软件开发中的前端&#xff0c;后端&#xff0c;数据库到底有什么关系呢&#xff01; 这个问题足足困扰了三年半&#xff0c;练习时…

C# 实现单线程异步互斥锁

文章目录 前言一、异步互斥锁的作用是什么&#xff1f;示例一、创建和销毁 二、如何实现&#xff1f;1、标识&#xff08;1&#xff09;标识是否锁住&#xff08;2&#xff09;加锁&#xff08;3&#xff09;解锁 2、异步通知&#xff08;1&#xff09;创建对象&#xff08;2&a…

C++类与对象(四):再谈构造函数(详解初始化列表)、Static成员

上次把默认的成员函数部分梳理完毕了&#xff1a;C初阶类与对象&#xff08;三&#xff09;&#xff1a;详解复制构造函数和运算符重载 今天接着讲下面的内容&#xff1a; 文章目录 1.再谈构造函数1.1构造函数体赋值1.2初始化列表1.2.1格式和概念1.2.2由来情况1情况2 1.2.3特性…

如何在云端加速缓存构建

缓存是指将某类数据存储起来以便以后重复使用的过程&#xff0c;它的运用在开发场景中非常普遍。类似于你习惯把最常用的调料放在厨房台面上&#xff0c;而不是橱柜里&#xff0c;这样你在准备大餐时就可以轻松取用。 但对于一个更为技术性、更精确的用例&#xff0c;比如像谷…

linux 使用笔记

1.查看运行内存 a.Free 快速查看内存的方法&#xff0c;也是经常使用的命令&#xff0c; -h 更人性化的显示内存的单元 -m 以M的形式显示 b.Top Top命令提供了实时性的运行中的程序的资源使用统计。可以根据内存的使用和大小来进行排序。 如上所示&#xff0c;top命令可以看…