使用WAF检查Referer Header对外部引用进行干预

一、背景

在CloudFront的控制台上,提供了一个TOP Refer的报表,这个报表用于显示本站的用户来源是来自哪个原始网站。这个机制是如何工作的呢?

假设如下的场景:

  • 主网站名为 https://www.abc.com/index.html
  • 图片的域名为 https://image.abc.com/image01.png

当客户端浏览器打开主网站时候,浏览器会向图片域名image.abc.com服务器的发送一个图片访问请求,并包含一个特殊的HTTP Header名为Referer。Referer Header的内容就是之前所在页面的域名,即www.abc.com。因此,图片服务器只需要检查Referer域名,即可获知引用此图片的原始网址。Referer Header可以被WEB应用服务器获取,并在应用层代码做判断。更高效的办法,是从客户访问前端的CloudFront和WAF上进行干预,来判断是否是合法的引用。

需要注意的是:检查Referer并不能完全阻断所谓的“盗链”和非法链接,因为攻击者可以简单去构造Referer Header来模拟一个正常请求。所以实施Referer检查的意义是可以避免图片等素材被其他网址的浏览器简单引用,可减少由此产生的外部流量等问题。如果需要100%的阻止外部访问且必须所有资源都经过身份验证,请参考CloudFront Signature签名功能。

下边介绍如何通过WAF检查Referer Header。

二、配置WAF ACL

本项目配置的WAF ACL配置在CloudFront CDN服务上,本项目假设已经配置好了CDN服务。

进入WAF控制台,将页面中部的区域选择为Global(CloudFront),然后点击右侧的Create web ACL按钮。如下截图。

输入要配置的WAF ACL的名称。如下截图。

将页面向下滚动,点击Add resource,关联AWS资源。如下截图。

在弹出窗口内,选择要绑定WAF ACL的CloudFront发布点。如下截图。

选中资源后,点击下一步继续。

在向导第二部,点击Add rules,点击Add my own rules and rule groups,输入自定义的rule。如下截图。

Rule type位置,选择Rule builder自行构建规则。然后在`RuleName位置输入规则名称,在类型位置输入Regular rule类型。将页面向下滚动。如下截图。

将页面向下滚动,在If arequest位置选择matches the statement,在Stagement下方,选择如下组合:

  • Inspect检查选项中,从下拉框中选择Single header检查单一的header
  • Header field name中,输入关键字referer全小写
  • Match type中,从下拉框中选择Contains string
  • String to match中,输入关键字域名全小写,这里表示原始网站,也就是合法引用图片的网站
  • Text transfermation中,从下拉框中选择Lowercase,表示将所有输入全部转换为小写。

接下来向下滚动页面,如下截图。

在页面下方的Action位置,选择Action行为是Allow,表示允许来自这个地址的访问。然后点击右下角的Add rule按钮。如下截图。

此时页面返回了上一步向导,在配置ACL的界面上,可以在页面中部看到刚才配置的自定义Rule。同时,将页面下方的Default action选项,设置为Block,表示默认禁止所有访问,仅允许刚才配置的一条自定义规则的一个指定域名来引用图片等资源。接下来点击页面右下角的Next下一步按钮。如下截图。

页面来到向导第三步,无需修改,点击右下角Next按钮继续。如下截图。

在向导第四步,上方的CloudWatch回自动带出设置,无需修改。下方的Request sampling options是快速采样显示最近的访问结果,这一项设置i为Enable sampled requests。这样即可在WAF控制台页面上快速显示最近的一些抽样的访问记录。然后点击右下角的Next按钮继续。如下截图。

向导最后一步,点击Create web ACL按钮,完成创建。如下截图。

至此WAF ACL创建完毕。

三、验证生效

1、使用浏览器带有Referer的跳转访问

现在我们在网站上build一个界面,引用刚才的图片:

<img src='https://waftest.bitipcman.com/meow.png'>

网站的URL使用WAF规则里边检查Referer Header步骤允许的URL。可看到图片能正常被访问,这是因为这个应用网址是WAF检查Referer Header时候被允许的网址。如下截图。

由此表示WAF的白名单放行成功。

2、复制URL地址到匿名模式浏览器窗口访问测试

现在打开一个浏览器匿名访问窗口,将刚才图片的网站直接粘贴到地址栏发起访问。可看到访问被拦截。这表示触发了整个规则组的default action,所有不匹配Referer header的都无法访问。如下截图。

至此表示整个WAF工作正常。

现在回到WAF设置ACL的界面,查看刚才配置的WAF ACL,在最下方也可以看到Sampled requests取样的信息,有正确的访问被通过,错误的被拦截。如下截图。

3、为WAF设置自定义错误信息

WAF支持自定义错误信息,因此在检查Referer不符合的,可以输出更友好信息。

进入WAF ACL的界面,在第5个标签页Custom response bodies界面下,点击Create创建按钮。如下截图。

在本界面上,输入自定义错误信息名称,选择自定义错误信息的格式是HTML,输入要现实的自定义错误信息。点击保存按钮。如下截图。

由此设置好了自定义错误信息。

进入WAF ACL的界面,在第二个标签页Rule的下方,可找到Default action的配置界面。点击编辑按钮。如下截图。

在自定义错误信息的位置,选中Enable按钮,在下方的Response code位置输入403,一般权限不对的代码都是使用403。在下方选择信息模版的下拉框位置,选择上一步录入的自定义信息。选择完毕后点击右下角的Save按钮。如下截图。

现在,回到刚才测试的浏览器匿名访问窗口,再次访问图片,可以看到报错信息已经不在是CloudFront标准的信息,转而是刚才自定义的message了。如下截图。

至此自定义错误信息功能生效。

4、使用curl模拟Referer header访问

Referer Header一般用于比较规范化的浏览器直接引用。但是如本文开头所说,检查Referer并不能完全阻断所谓的“盗链”和非法链接,因为攻击者可以简单去构造Referer Header来模拟一个正常请求。我们这里就使用curl,额外加上一个Referer Header去发起请求。

curl --referer blog.bitipcman.com https://waftest.bitipcman.com/meow.png

由此可以看到成功访问了图片。如下截图。

综上所述,Referer Header的检查不能完全阻隔盗链和恶意攻击,更多的是对规范性的网站的直接内容引用。对于恶意攻击者,还需要搭配其他AWS Managed-rule的WAF规则如Bad Input、IP Reputation、Rate-based limit、Common等几个重要的rule来进行防护。如果是私有内容的分发、以及内容授权访问,还可以使用CloudFront Signature签名功能,通过Signed-URL和Signed Cookie来控制用户访问行为。

四、参考文档

How to Prevent Hotlinking by Using AWS WAF, Amazon CloudFront, and Referer Checking:

https://aws.amazon.com/cn/blogs/security/how-to-prevent-hotlinking-by-using-aws-waf-amazon-cloudfront-and-referer-checking

全文完。