在第一章结尾的时候我就已经说了,这一章将会更详细的介绍前端防火墙的报警机制及代码。在一章出来后,有人会问为什么不直接防御,而是不防御报警呢。很简单,因为防御的话,攻击者会定位到那一段的JavaScript代码,从而下次攻击的时候绕过代码。如果不防御而报警的话,攻击者会降低警觉,不会在看JavaScript代码(至少我是这样)。回到正题,下面说的代码,是基于thinkphp框架和bootstrap3.3.5框架。如果你的网站没有使用thinkphp3.2.3框架的话,可以参照我的思路重新写一个。这里我强调一下“前端防御XSS是建立在后端忘记做过滤,没有做过滤,疏忽做过滤的基础上的...
其实标题应该改成“XSS报警机制”的,因为在这一章里使用了大量的后端代码。但是第一章的标题都出来了,也没法改了。
前端要做的事情在第一章的时候就已经说了,代码如下:
现在我们就是针对第38行进行修改,改成我们后台接受的API URL。就像这样:
对,就这一行。没有其他代码。在实际的线上环境中,也只需要上面5行。可以直接copy到您的线上环境中,记得把倒数第二行的url改成自己的地址就行了。难道就那么简单?不,0x05节还有一部分前端代码。0x01~0x04主要是针对于平台。
一共两个表。fecm_user和fecm_bugdata。
fecm_user的字段信息如下:
为了安全起见(其实就是懒)没有写添加管理员的,自行在数据库里添加
fecm_bugdata的字段信息如下:
因为后端代码太多,所以我就说一些核心的后端处理代码。
在0x01节里,有个核心的代码是new Image().src = 'http://fecm.cn/Api/addVul/';
接下来我们来说说这个Api的处理方式(ThinkPHP代码)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
public function addVul(){ if (I( 'get.category' , '' , 'int' ) == "" ){ $this ->ajaxReturn( array ( "typeMsg" => "error" , "msgText" => "漏洞类型错误" , )); } switch (I( 'get.category' , '' , 'int' )) { case '1' : $vul [ 'category' ] = "触发alret函数" ; break ; case '2' : $vul [ 'category' ] = "发现不在白名单里的第三方JavaScript资源" ; break ; default : $this ->ajaxReturn( array ( "typeMsg" => "error" , "msgText" => "漏洞类型错误" , )); break ; } if ( $_SERVER [ 'HTTP_X_FORWARDED_FOR' ] === null){ $vul [ 'hxff_ip' ] = "攻击者没有通过代理服务器访问" ; } else { $vul [ 'hxff_ip' ] = I( 'server.HTTP_X_FORWARDED_FOR' ); //获取攻击者的HTTP_X_FORWARDED_FOR } if ( $_SERVER [ 'HTTP_CLIENT_IP' ] === null){ $vul [ 'hci_ip' ] = "攻击者数据包头部没有HTTP_CLIENT_IP" ; } else { $vul [ 'hci_ip' ] = I( 'server.HTTP_CLIENT_IP' ); //获取攻击者的HTTP_CLIENT_IP } $vul [ 'ra_ip' ] = I( 'server.REMOTE_ADDR' ); //获取攻击者的REMOTE_ADDR $vulcookie = I( 'cookie.' ); //获取攻击者的cookies for ( $i = 0; $i < count ( $vulcookie ); $i ++){ $vul [ 'cookies' ] .= array_keys ( $vulcookie )[ $i ]. '=' . $vulcookie [ array_keys ( $vulcookie )[ $i ]]. '; ' ; //拼接成方便查看的cookies格式 } $vul [ 'url' ] = I( 'server.HTTP_REFERER' ); //获取攻击者攻击成功的url $vul [ 'ua' ] = I( 'server.HTTP_USER_AGENT' ); //获取攻击者的User-Agent $vul [ 'time' ] = date ( "Y-m-d" ); //获取攻击者攻击的时间 $vul [ 'fixes' ] = 0; //默认为漏洞未修复 $bugData = M( 'bugdata' ); //连接fecm_bugdata数据库 $bugData ->data( $vul )->add(); //添加到数据库中 } |
因为这里是接受攻击信息,不能有管理员验证。
后台有一个数据库可视化的表格,这里我使用的Chart.js,下面是后端代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public function index(){ $reportForm = M( 'bugdata' ); //连接fecm_bugdata数据库 $dateTimeLabels = []; $dateTimeTotal = []; for ( $i = 0; $i < 7; $i ++){ //获取近7天的数据 $time = date ( "Y-m-d" , strtotime (- $i . " day" )); array_unshift ( $dateTimeLabels , $time ); $data [ 'time' ] = array ( 'like' , '%' . $time . '%' ); array_unshift ( $dateTimeTotal , $reportForm ->where( $data )-> count ()); } $reportForm = json_encode([ "Labels" => $dateTimeLabels , "Total" => $dateTimeTotal ]); //转化成json格式 $this ->assign( 'reportForm' , $reportForm )->assign( 'total' ,total()); //交给前端模块 $this ->display(); //前端页面生成 } |
前端代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
var lineChartData = { labels :eval({$reportForm})[ 'Labels' ], datasets : [ { fillColor : "rgba(151,187,205,0.5)" , strokeColor : "rgba(151,187,205,1)" , pointColor : "rgba(151,187,205,1)" , pointStrokeColor : "#fff" , data : eval({$reportForm})[ 'Total' ] } ] } var myLine = new Chart(document.getElementById( "Statistics" ).getContext( "2d" )).Line(lineChartData); |
实际的效果图:
代码就用0x01节的代码。我们输入<script>alert(1)</script>
。看一下:
我们再去平台看一下:
成功显示了。
这一节需要用到之前长短短分享的代码:
1
2
3
4
5
6
7
|
for ( var i=0,tags=document.querySelectorAll( 'iframe[src],frame[src],script[src],link[rel=stylesheet],object[data],embed[src]' ),tag;tag=tags[i];i++){ var a = document.createElement( 'a' ); a.href = tag.src||tag.href||tag.data; if (a.hostname!=location.hostname){ console.warn(location.hostname+ ' 发现第三方资源[' +tag.localName+ ']:' +a.href); } } |
但是他这里只是在console里显示,没有进一步的操作,而且他这里同时检测了iframe、frame、script、link、object、embed标签,对我们来说只需要script标签就行了,于是我重写了这段代码,首先我们需要一个白名单列表,用于放置网站允许第三方加载的url地址:
1
2
3
|
var scriptList = [ location.hostname, ] |
这里只是默认的只允许当前域名加载,打击爱可以根据自己的需要添加。
然后就是获取当前网页的所有script标签:
1
|
var webScript = document.querySelectorAll( 'script[src]' ); |
在把当前的地址赋值var webHost = location.hostname;
至于为什么不放在for循环里,因为根据js优化规则,for循环里避免多次一样的赋值。
接下来就是for循环里的代码了:
1
2
3
4
5
6
7
8
9
10
11
|
for ( var i = 0;i < webScript.length;i++){ var a = document.createElement( 'a' ); //建立一个新的a标签,方便取值 a.href = webScript[i].src; //把script里的src赋值给a标签里的href属性 if (a.hostname != webHost){ //对比,是否为第三方资源 for ( var j = 0;j < scriptList.length;j++){ if (a.hostname != scriptList[i]){ //判断当前的第三方资源是否在白名单里 new Image().src = 'http://fecm.cn/Api/addVul/category/2' ; //发送给FECM } } } } |
这里我做了一个测试,加载hi.baidu.com的资源:
刷新后,打开FECM平台,看一下:
因为穷,没有服务器和域名,也没法添加邮件自动提醒功能了。感兴趣的可以自己添加,如果后来我有钱了,我买个服务器,会添加邮件自动提醒的,第一时间会在乌云社区里发布。本来打算采用ED的on事件拦截代码的,但是发现on事件在程序里也会大量使用,索性就没有添加,如果你有思路
下载地址:http://pan.baidu.com/s/1jGVP7Ps
使用时记得在Application\Home\Conf\config.php
改下配置(我已经全部加了注释,即使不会thinkphp的也可以搭建)
个人代码写的没有多好,思路可能也比较烂。如果您有什么意见欢迎提出来,我会进一步修改的。
关于我们 |
服务报价 |
常见问题 |
服务流程 |
服务承诺 |
服务条款 |
诚聘英才 |
中国网络安全联盟(ChinaNSU)核心会员 |
新浪微博
技术支持:018628103302. 客户服务:028-67874987. 商务传真:028-89993093. Email:admin@fwqaq.com
服务器安全.COM(FWQAQ.COM) 版权所有 Copyright © 2005 - 2016 成都锐盾信息技术有限公司. All Right Reserved.
蜀ICP备09009354号-17
川公网安备 51192302000130号
< 电脑桌面版 | 触屏手机版 >