nginx实现CSRF和XSS防御

   版权声明:本文为博主原创文章,未经博主允许不得转载。



nginx实现CSRF和XSS防御

 最近,因为公司任务要求,搞了一下nginx配置。任务要求是实现CSRF和XSS防护,至于什么是CSRF和XSS请自行学习一下。首先需要解释的是,这里所提到的CSRF和XSS防御全是基于后台基于Nginx配置。
1.CSRF防御
网上搜一下解决方案大概是有四种:
(1)验证HTTP Referer 字段
(2)在请求地址中添加token并验证
(3)在HTTP头中自定义属性并验证
(4)Chrome浏览器端启用SameSite cookie
以上四种方法:方法二难点在于如何把 token 以参数的形式加入请求,并且该方法有一个缺点是难以保证 token 本身的安全。方法3局限性非常大。XMLHttpRequest 请求通常用于 Ajax 方法中对于页面局部的异步刷新,并非所有的请求都适合用这个类来发起,而且通过该类请求得到的页面不能被浏览器所记录下,从而进行前进,后退,刷新,收藏等操作,给用户带来不便。另外,对于没有进行 CSRF 防护的遗留系统来说,要采用这种方法来进行防护,要把所有请求都改为XMLHttprequest请求,这样几乎是要重写整个网站,这代价无疑是不能接受的。方法四显然是有很大的局限性。因此我采用了方法1来实现CSRF的防御,方法一实现起来更简单。然而,这种方法并非万无一失。Referer 的值是由浏览器提供的,虽然 HTTP 协议上有明确的要求,但是每个浏览器对于 Referer 的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞。使用验证 Referer 值的方法,就是把安全性都依赖于第三方(即浏览器)来保障,从理论上来讲,这样并不安全。事实上,对于某些浏览器,比如 IE6 或 FF2,目前已经有一些方法可以篡改 Referer 值。如果 www.bank.example网站支持 IE6 浏览器,黑客完全可以把用户浏览器的 Referer 值设为以 www.bank.example域名开头的地址,这样就可以通过验证,从而进行 CSRF 攻击。
即便是使用最新的浏览器,黑客无法篡改 Referer 值,这种方法仍然有问题。因为 Referer 值会记录下用户的访问来源,有些用户认为这样会侵犯到他们自己的隐私权,特别是有些组织担心 Referer 值会把组织内网中的某些信息泄露到外网中。因此,用户自己可以设置浏览器使其在发送请求时不再提供 Referer。当他们正常访问银行网站时,网站会因为请求没有 Referer 值而认为是 CSRF 攻击,拒绝合法用户的访问。
另外,如果Referer的判断逻辑写的不严密的话,也容易被攻破,例如
constreferer = request.headers.referer;if (referer.indexOf('www.bank.example') > -1) { // pass}
如果黑客的网站是www.bank.example.hack.com,则referer检查无效。
***************************************************************************************************
基于上述分析,采用nginx配置文件自带检查Referer模块对Herder Referer字段进行check。
通过java文件动态的配置nginx.conf文件,凡是通过UI 进入到环境的全部进行check,模块代码如下:
valid_referers none blocked server_names www.baidu.com
if ($invalid_referer) {
return 403;
}
valid_referers 代表可信referer,此处可信referer的设置将会使变量$invalid_referer的值为「0」,反之$invalid_referer的值为「1」,则执行IF条件名并返回相关限制结果。

none是指当referer为空的时候,比如在链接器中直接打开一个图片链接,若要禁止用户直接访问,则必须省掉none。

blocked 是指经过某些代理或firewall过滤后的referer,比如省略了url前缀等, 同样地,若要禁止用户直接访问,则必须省掉blocked。

server_names 是nginx配置文件中的server name项,代指网站域名。
根据实际需求将模块写进相应的location中,正则要慎重,可能会影响的环境正常运行。
2.CSRF防御的生效验证问题
尝试过使用soapUI进行测试,但是可能是本人的soapUI功力尚浅,使用HTTP Request测试加入Referer头信息对接口进行测试,总是不生效,这部分将在soapUI的总结中详细说。本人采用的是Chrome内置的免费插件postman,这是我最近才接触到,但是发现十分好用,和soapUI相比,操作起来要简便太多了,而且功能十分强大,真的是强烈推荐给大家。
3.XSS防御
cross site scripting(跨站脚本攻击),为了和cascading style sheets(层叠样式表)区分,取名为XSS。通过嵌入脚本的方式进行攻击,获取用户的cookie等信息,或者在服务器端执行来篡改数据。
相比于CSRF防御问题,XSS的防御问题显得略显繁琐一些。网上搜一下解决办法基本上思路也是很清晰了大致要做如下几步(此处直接引用我在task上的comments并稍加修改):
1)Add the following headers in response (nginx)
add_header X-Frame-Options 'SAMEORIGIN';  #只允许本网站的frame嵌套
add_header X-XSS-Protection '1; mode=block';  #开启XSS过滤器
add_header X-Content-Type-Options 'nosniff';  #禁止嗅探文件类型
2.Add the HttpOnly and secure flag
这一步根据实际情况的不同,有不同的执行方式。一般的可以在我们的Tomcat配置或是nginx配置中设置,也可以在后台设置。
HTTP消息之间是无状态的,cookie和session可以维护信息。黑客一旦窃取cookie,就可以获得用户身份。通过浏览器的document对象,就可以获取cookie。HttpOnly会禁止脚本访问cookie,防止XSS。(进行设定之前一定要和前台人员确认以防对系统环境造成影响)
secure的设定则是将只允许HTTPS。
3.add XSS-Blocking (nginx)
set $block_xss 0;
if ($query_string ~ "base64_(en|de)code(.*)")
{ set $block_xss 1; }
if ($request_uri ~ "base64_(en|de)code(.*)") { set $block_xss 1; }
if ($query_string ~ "(<|%3C)*.script.*(/?>|%3E)")
{ set $block_xss 1; }
if ($request_uri ~ "(<|%3C)*.script.*(/?>|%3E)") { set $block_xss 1; }
if ($query_string ~ "(<|%3C)*.iframe.*(/?>|%3E)")
{ set $block_xss 1; }
if ($request_uri ~ "(<|%3C)*.iframe.*(/?>|%3E)") { set $block_xss 1; }
if ($query_string ~ "GLOBALS(=|[|%[0-9A-Z]
{0,2})")
{ set $block_xss 1; }
if ($query_string ~ "_REQUEST(=|[|%[0-9A-Z]{0,2}
)")
{ set $block_xss 1; }
if ($block_xss = 1)
{ return 403; }
It can catch more Matching items in Request URL e.g. <script> <script/> <script src=123456789.js />
此处直接把公司task完成后的comments贴出来了。
网上说的大多数是把星号放在script和iframe的两侧,但是通过我的实际验证后发现,例如
"(<|%3C).*script*.(/?>|%3E)" 正则是不能catch到<script src=123456789.js />,读者可自行测试。
XSS-Blocking主要就是针对UI界面里在比如Description或是comments里面写入可执行脚本的问题进行防御。
1.3两步的nginx的配置要根据项目的实际需求写在不同的location中。
4.XSS防御的生效验证问题
我仍然使用的Chrome自带插件postman进行测试,当然主要是针对nginx里面的XSS-Blocking代码块进行的测试说白了也就是对正则规则进行测试。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章