通过在客户端集成亚马逊云科技 WAF Client SDK,可以高效方便地帮助业务抵御 7 层 DDoS 攻击。对比通过 WAF 自定义规则进行 Token 过滤,WAF 智能威胁检测只需要前端做 SDK 的接入(支持 iOS/Android/Web),免去了自己开发一整套复杂的 Token 管理分发流程。WAF SDK 和 WAF 后端自动实现了基于 Client Session 的 Token 分发和校验机制。
互联网行业的客户端应用,一般是使用静态的Token Header 进行有效的合法请求过滤。可以利用亚马逊云科技高性能大容量的 WAF 来在源站之前进行精准的请求过滤。把 HTTP Flood 类型的 DDoS 请求阻挡在近攻击源的位置。使源站得到良好的保护。
这种在静态自定义 Token 分发的实现方面各个用户都会采用不同的方法, 可以依靠高容量的 WAF 来精准保护源站。
动态分发 Token 到各种平台的海量客户端,能够用统一的开发 SDK 完成同样完成静态Token的需求,亚马逊云科技的 WAF Client SDK就是完美的解决了上述问题。
https://docs.aws.amazon.com/waf/latest/developerguide/waf-js-challenge-api.html
JavaScript集成-captcha SDK:
https://docs.aws.amazon.com/waf/latest/developerguide/waf-js-captcha-api.html
WAF Client SDK 与应用程序客户端进行集成后,能自动与后台配置的 WAF ACL Bot Control 规则进行联动,完成 token 获取。SDK 也会把应用程序发送的请求,自动带上 Token 信息发送给 WAF 后台进行校验,Token 刷新的功能也原生就支持了。 WAF Client SDK 提供 iOS/Android Mobile SDK 和 Web JavaScript API。
下面分步骤介绍如何为 Web 应用集成 JavaScript API 并配置 WAF ACL 规则进行攻击流量防护,具体可参考AWS WAF JavaScript 集成接入文档。

JavaScript集成-challenge SDK:
参考手册:https://docs.aws.amazon.com/waf/latest/developerguide/waf-js-challenge-api.html
添加 AWSManagedRulesBotControlRuleSet 托管规则到 ACL 中,并把 Rule 级别设置为 Target,可以实现客户端请求的 token 验证。如果请求中不包含 token 或者 token 无效,这条托管规则会触发 Challenge rule action,从而触发 Client SDK 在后台静默完成 Challenge 计算任务得到 token。

选择 Bot Control inspection level 为 Targeted

Rule action 选择 Challenge

从 WAF 的控制台中进入 Application integration,选择 Intelligent threat integration 选项,这里会显示已经开启 AWSManagedRulesBotControlRuleSet 规则的 ACL。

需要把 ACL 所对应的 JavaScript Integration URL 复制到 Web 应用的前端代码的<head></head>之间。
<html>
<head>
<script type="text/javascript" src="https://xxxxxxxxxxxx.us-west-2.sdk.awswaf.com/xxxxxxxxxxxx/xxxxxxxxxxxx/challenge.js" defer></script>
</head>
<body>
<h1>Login Page</h1>
<p>Click on the below button to login</p>
<button onclick="login()">Login</button>
<script>
async function login(){
let user = {
name: 'username',
surname: 'surname'
};
const response = await AwsWafIntegration.fetch('https://yourdomain.com/waf/query',{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(user)
});
const responseText = await response.text()
document.getElementById("display").innerText = responseText
console.log(responseText)
}
</script>
<p>Hello WAF!</p>
<div id='display'></div>
</body>
</html> |
WAF Client JavaScript API 提供了 AwsWafIntegration.fetch()方法,是原生 JS fetch()方法的 Wrapper。与原生 fetch()方法相比,内部逻辑封装了 token 的请求和计算,并在业务 http 请求中自动加上了 token, 调用方法的参数与原生 JS fetch()相同。
样例代码使用 WAF client API 向后端发起了一个 Post 请求。后端使用 AWS EC2 部署 Echo-Server 做为测试用的 Web 服务器,实现返回 http response,并通过 ALB 提供对外访问。ALB 被刚才配置的 WEB ACL 所保护。
上传样例代码到EC2的NGINX里面,呈现为客户端可访问的网页如下:

当 WAF 从 web 请求中侦测 token 时,默认只会接受与 ACL 所关联资源的 host domain。当请求是通过 Cloudfront 到 ALB 时,需要把 Cloudfront 所对应的 custom host domain 配置到 Token domain 列表中。配置参考文档。

访问 Web 前端,打开浏览器开发者模式。可以看到,页面在初始化后自动与 WAF 后台进行交互,获取了 challenge.js 并进行静默计算得到 token。在发起 query 请求后,会自动在 cookie header 中带上 aws-waf-token。WAF 后台的 Bot control Rule 进行 token 校验成功后,流量被发送到 ALB。Echo-Server 会把发送的请求原样返回,可以看到请求中包含了 token 信息。

对于 Request 中不带有 token,或者 token 无效,我们希望 WAF 进行阻止的操作。需要做如下配置。
从流程上看,token 无效的请求,AWSManagedRuleBotControlRuleSet 会给这条 Request 加上 Label,用于表示 token 不存在或 token 无效。我们可以继续配置自定义规则,如果 request 包含特定 label,则说明请求来自非法客户端,进行阻断。
Awswaf:managed:token:absent,包含这个 label 说明 token 不存在
Awswaf:managed:token:rejected,包含这个 label 说明 token 无效
增加 Custom Rule,如果请求中包含上述 Label,则 Block


增加 Custom Rule,如果请求的 token 无效,则 Block。以下是等效配置的 JSON 描述:

现在有三条 Rule 作用在 WAF ACL 上:

修改 Web 前端,使用 JS 原生 fetch(),不带 token 发送请求给业务后端。
<html>
<head>
</head>
<body>
<h1>Login Page</h1>
<p>Click on the below button to login</p>
<button onclick="login()">Login</button>
<script>
async function login(){
let user = {
name: 'username',
surname: 'surname'
};
const response = await fetch('https://yourdomain.com/waf/query',{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(user)
});
const responseText = await response.text()
document.getElementById("display").innerText = responseText
console.log(responseText)
}
</script>
<p>Hello WAF!</p>
<div id='display'></div>
</body>
</html> |
通过 Chrome 浏览器开发者模式可以看到,由于请求不带 token,请求被 WAF 所拒绝。

JavaScript集成-captcha SDK:
参考手册:https://docs.aws.amazon.com/waf/latest/developerguide/waf-js-captcha-api.html
添加 AWSManagedRulesBotControlRuleSet 托管规则到 ACL 中,并把 Rule 级别设置为 Target,可以实现客户端请求的 token 验证。如果请求中不包含 token 或者 token 无效,这条托管规则会触发 Captcha rule action,从而触发 Client SDK 在后台静默完成 Captcha 计算任务得到 token。


选择 Bot Control inspection level 为 Targeted



Bot Control Rules 选择 CAPTCHA

webacl-alb-api-001默认规则:AWS-AWSManagedRulesBotControlRuleSet规则如下
{
"Name": "AWS-AWSManagedRulesBotControlRuleSet",
"Priority": 0,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesBotControlRuleSet",
"ScopeDownStatement": {
"AndStatement": {
"Statements": [
{
"ByteMatchStatement": {
"SearchString": "/waf/query",
"FieldToMatch": {
"UriPath": {}
},
"TextTransformations": [
{
"Priority": 0,
"Type": "LOWERCASE"
}
],
"PositionalConstraint": "EXACTLY"
}
},
{
"NotStatement": {
"Statement": {
"ByteMatchStatement": {
"SearchString": "POST",
"FieldToMatch": {
"Method": {}
},
"TextTransformations": [
{
"Priority": 0,
"Type": "NONE"
}
],
"PositionalConstraint": "EXACTLY"
}
}
}
}
]
}
},
"ManagedRuleGroupConfigs": [
{
"AWSManagedRulesBotControlRuleSet": {
"InspectionLevel": "TARGETED",
"EnableMachineLearning": true
}
}
],
"RuleActionOverrides": [
{
"Name": "SignalNonBrowserUserAgent",
"ActionToUse": {
"Captcha": {}
}
},
{
"Name": "TGT_VolumetricIpTokenAbsent",
"ActionToUse": {
"Captcha": {}
}
}
]
}
},
"OverrideAction": {
"None": {}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "AWS-AWSManagedRulesBotControlRuleSet"
}
} |
Webacl-alb-api-001自定义规则:
{
"Name": "Block-Requests-With-Missing-Or-Rejected-Token-Label",
"Priority": 1,
"Statement": {
"AndStatement": {
"Statements": [
{
"OrStatement": {
"Statements": [
{
"LabelMatchStatement": {
"Scope": "LABEL",
"Key": "awswaf:managed:token:absent"
}
},
{
"LabelMatchStatement": {
"Scope": "LABEL",
"Key": "awswaf:managed:token:rejected"
}
}
]
}
},
{
"NotStatement": {
"Statement": {
"ByteMatchStatement": {
"SearchString": "POST",
"FieldToMatch": {
"Method": {}
},
"TextTransformations": [
{
"Priority": 0,
"Type": "NONE"
}
],
"PositionalConstraint": "EXACTLY"
}
}
}
}
]
}
},
"Action": {
"Block": {}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "Block-Requests-With-Missing-Or-Rejected-Token-Label"
}
} |
从 WAF 的控制台中进入Application integration,选择Captcha integration 选项,这里会显示已经开启 AWSManagedRulesBotControlRuleSet 规则的 ACL。

需要把 ACL 所对应的 JavaScript Integration URL 复制到 Web 应用的前端代码的<head></head>之间。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Waf Captcha Test</title>
<script type="text/javascript" src="https://73f53964xxxx.ap-southeast-1.captcha-sdk.awswaf.com/73f53964xxxx/jsapi.js" defer></script>
</head>
<body>
<h1>Login Page</h1>
<p>Click on the below button to login</p>
<button onclick="userAction()">Login</button>
<script type="text/javascript">
const apiURL = 'http://api001.bosicloud.one/waf/query';
function showMyCaptcha() {
const container = document.getElementById('container');
AwsWafCaptcha.renderCaptcha(container, {
apiKey: 'xxxxUYC7iqJbIcvhB5W21s/w9s3oAGcPai9tKFpadOUctVCXTZ0KndUbGATzSVqLx7s5dzl4MKwudqYWIEeyv0gnYZuSPchyf1mgZAXjRveATBmosCj2h3LEC2jAsagSWpzQGofjBvhFlC8CMnSmapPY8kekeIABcCyycj4rGUPVIX/iRAlGyZEFat68AfMJmsvoxRYiSIQQt1cJZnTNFlg/Uam3fQW9hFy/n6HJnO3nxs+kFwjotKnzMbHGOJXpbZlakYivF6t6mFoEea5PftXxszvDEdjJ6sUZI4aQbrJTfIcRF/9cM2L2WjNs0sVCj9fqu1lI75k2txelIrwoHOBxgJlSo8P23e5CShd1fBkYJgGdj8BobiIoMEqWgtIUN8s54EcaRzGUAZqinqsEONpBn8SBViBpl5I+RuiiEYsRBXpfHUzb5mbo/lzgO5YRCezY+B2LFAHmLzy6xeq390ig6xKmPRNXItxTDIudPELhIVO8rJ5vrYm+yf8wV1ppyJXuNP9pq9ifS2+jFfCt5kCNrjunTF0Hzbt08qHgPE1OZb9c2dSyXK8pvDGyaIbjROLgcCcJ7mRKqk2BvzSTCkY34SC98upXGUkMn1o36aOrbZoM15GcBGKPnQ0E0PmQrnfGGaIDJFZJRH8Hv/Q2s/o1GrluRmGEN39eeGuyYEs=_0_1xxxx',
onSuccess: successFunction,
onError: errorFunction,
});
}
function successFunction() {
const container = document.getElementById('container');
container.innerHTML = '';
AwsWafIntegration.fetch(apiURL, {}).then(response => {
response.json().then(myJson => { renderResponse(myJson) });
});
}
function errorFunction(error) {
console.log(error);
}
function renderResponse(json) {
if (json) {
container.innerHTML = "Result: The request resulted is Success.";
} else {
container.innerHTML = "Result: The request resulted is Error.";
}
}
function userAction() {
const container = document.getElementById('container');
container.innerHTML = '';
AwsWafIntegration.fetch(apiURL,{method: 'POST'}).then(response => {
if ( response.status == 405) {
showMyCaptcha();
} else {
response.json().then(myJson => { renderResponse(myJson) });
}
});
}
</script>
<p>Hello WAF!</p>
<div id='container'></div>
</body>
</html> |
WAF Client JavaScript API 提供了 AwsWafIntegration.fetch()方法,是原生 JS fetch()方法的 Wrapper。与原生 fetch()方法相比,内部逻辑封装了 token 的请求和计算,并在业务 http 请求中自动加上了 token, 调用方法的参数与原生 JS fetch()相同。
样例代码使用 WAF client API 向后端发起了一个 Post 请求。后端使用 AWS EC2 部署 Echo-Server 做为测试用的 Web 服务器,实现返回 http response,并通过 ALB 提供对外访问。ALB 被刚才配置的 WEB ACL 所保护。
上传样例代码到EC2的NGINX( /usr/share/nginx/html )里面,呈现为客户端可访问的网页如下:
server {
listen 80;
#listen [::]:80;
#server_name _;
root /usr/share/nginx/html;
index index.html index.htm
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
} |
效果如下:


当 WAF 从 web 请求中侦测 token 时,默认只会接受与 ACL 所关联资源的 host domain。当请求是通过ALB 时,需要把custom host domain 配置到 Token domain 列表中。配置参考文档。

访问 Web 前端,打开浏览器开发者模式。可以看到,页面在初始化后自动与 WAF 后台进行交互,获取了jsapi.js 并进行静默计算得到 token。在发起 query 请求后,会自动在 cookie header 中带上 aws-waf-token。WAF 后台的 Bot control Rule 进行 token 校验成功后,流量被发送到 ALB。Echo-Server 会把发送的请求原样返回,可以看到请求中包含了 token 信息。

对于 Request 中不带有 token,或者 token 无效,我们希望 WAF 进行阻止的操作。需要做如下配置。
从流程上看,token 无效的请求,AWSManagedRuleBotControlRuleSet 会给这条 Request 加上 Label,用于表示 token 不存在或 token 无效。我们可以继续配置自定义规则,如果 request 包含特定 label,则说明请求来自非法客户端,进行阻断。
Awswaf:managed:token:absent,包含这个 label 说明 token 不存在
Awswaf:managed:token:rejected,包含这个 label 说明 token 无效
增加 Custom Rule,如果请求中包含上述 Label,则 Block


增加 Custom Rule,如果请求的 token 无效,则 Block。以下是等效配置的 JSON 描述:

现在有三条 Rule 作用在 WAF ACL 上:

修改 Web 前端,使用 JS 原生 fetch(),不带 token 发送请求给业务后端。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Waf Captcha Test</title>
<script type="text/javascript" src="https://73f53964XXX.ap-southeast-1.captcha-sdk.awswaf.com/73f53964XXXX/jsapi.js" defer></script>
</head>
<body>
<h1>Login Page</h1>
<p>Click on the below button to login</p>
<button onclick="userAction()">Login</button>
<script type="text/javascript">
const apiURL = 'http://api001.bosicloud.one/waf/query';
function showMyCaptcha() {
const container = document.getElementById('container');
AwsWafCaptcha.renderCaptcha(container, {
apiKey: 'XXXXIIjdUYC7iqJbIcvhB5W21s/w9s3oAGcPai9tKFpadOUctVCXTZ0KndUbGATzSVqLx7s5dzl4MKwudqYWIEeyv0gnYZuSPchyf1mgZAXjRveATBmosCj2h3LEC2jAsagSWpzQGofjBvhFlC8CMnSmapPY8kekeIABcCyycj4rGUPVIX/iRAlGyZEFat68AfMJmsvoxRYiSIQQt1cJZnTNFlg/Uam3fQW9hFy/n6HJnO3nxs+kFwjotKnzMbHGOJXpbZlakYivF6t6mFoEea5PftXxszvDEdjJ6sUZI4aQbrJTfIcRF/9cM2L2WjNs0sVCj9fqu1lI75k2txelIrwoHOBxgJlSo8P23e5CShd1fBkYJgGdj8BobiIoMEqWgtIUN8s54EcaRzGUAZqinqsEONpBn8SBViBpl5I+RuiiEYsRBXpfHUzb5mbo/lzgO5YRCezY+B2LFAHmLzy6xeq390ig6xKmPRNXItxTDIudPELhIVO8rJ5vrYm+yf8wV1ppyJXuNP9pq9ifS2+jFfCt5kCNrjunTF0Hzbt08qHgPE1OZb9c2dSyXK8pvDGyaIbjROLgcCcJ7mRKqk2BvzSTCkY34SC98upXGUkMn1o36aOrbZoM15GcBGKPnQ0E0PmQrnfGGaIDJFZJRH8Hv/Q2s/o1GrluRmGEN39eeGXXXXuyYEs=_0_1',
onSuccess: successFunction,
onError: errorFunction,
});
}
function successFunction() {
const container = document.getElementById('container');
container.innerHTML = '';
AwsWafIntegration.fetch(apiURL, {}).then(response => {
response.json().then(myJson => { renderResponse(myJson) });
});
}
function errorFunction(error) {
console.log(error);
}
function renderResponse(json) {
if (json) {
container.innerHTML = "Result: The request resulted is Success.";
} else {
container.innerHTML = "Result: The request resulted is Error.";
}
}
function userAction() {
const container = document.getElementById('container');
container.innerHTML = '';
AwsWafIntegration.fetch(apiURL,{method: 'POST'}).then(response => {
if ( response.status == 405) {
showMyCaptcha();
} else {
response.json().then(myJson => { renderResponse(myJson) });
}
});
}
</script>
<p>Hello WAF!</p>
<div id='container'></div>
</body>
</html> |
通过 Chrome 浏览器开发者模式可以看到,由于请求不带 token,请求被 WAF 所拒绝。
