您现在的位置是:网站首页 > 心得笔记
laravel框架中防止XSS 安全漏洞 插件包
XSS 也称跨站脚本攻击 (Cross Site Scripting),恶意攻击者往 Web 页面里插入恶意 JavaScript 代码,当用户浏览该页之时,嵌入其中 Web 里面的 JavaScript 代码会被执行,从而达到恶意攻击用户的目的。
一种比较常见的 XSS 攻击是 Cookie 窃取。我们都知道网站是通过 Cookie 来辨别用户身份的,一旦恶意攻击者能在页面中执行 JavaScript 代码,他们即可通过 JavaScript 读取并窃取你的 Cookie,拿到你的 Cookie 以后即可伪造你的身份登录网站。(扩展阅读 —— IBM 文档库:跨站点脚本攻击深入解析 )
有两种方法可以避免 XSS 攻击:
第一种,对用户提交的数据进行过滤;
第二种,Web 网页显示时对数据进行特殊处理,一般使用
htmlspecialchars()
输出。
Laravel 的 Blade 语法 {{ }}
会自动调用 PHP htmlspecialchars
函数来避免 XSS 攻击。但是因为我们支持 WYSIWYG 编辑器,我们使用的是 {!! !!}
来打印用户提交的话题内容:
<div class="topic-body"> {!! $topic->body !!}</div>
Blade 的 {!! !!}
语法是直接数据,不会对数据做任何处理。在我们这种场景下,因为业务逻辑的特殊性,第二种方法不适用,我们将使用第一种方法,对用户提交的数据进行过滤来避免 XSS 攻击。
编辑器 Simditor 默认为我们的内容提供转义,我们可以使用以下这段代码来测试:
编辑器中输入:
测试xss攻击 <script>alert(211);</script> 测试xss攻击
存入数据库中的是:
<p>测试xss攻击</p> <p><script>alert(211);</script></p> <p><br /></p> <p>测试xss攻击<br /></p>
可见 Simditor编辑器默认为我们输入的内容提供转义了!
页面上显示:
很多同学会大意地认为前端页面有 WYSIWYG 为我们做转义,就是安全的,事实并不是这样的。
现实生活中,不良用户不一定是网页上向服务器提交内容,有太多的工具可以执行此操作
接下来我们一起解决此问题。
HTMLPurifier
PHP 一个比较合理的解决方案是 HTMLPurifier 。HTMLPurifier 本身就是一个独立的项目,运用『白名单机制』对 HTML 文本信息进行 XSS 过滤。这种过滤机制可以有效地防止各种 XSS 变种攻击。只通过我们认为安全的标签和属性,对于未知的全部过滤。
『白名单机制』指的是使用配置信息来定义『HTML 标签』、『标签属性』和『CSS 属性』数组,在执行 clean()
方法时,只允许配置信息『白名单』里出现的元素通过,其他都进行过滤。
如配置信息:
'HTML.Allowed' => 'div,em,a[href|title|style],ul,ol,li,p[style],br','CSS.AllowedProperties' => 'font,font-size,font-weight,font-style,font-family',
当用户提交时:
<a someproperty="somevalue" href="http://example.com" style="color:#ccc;font-size:16px"> 文章内容<script>alert('Alerted')</script></a>
会被解析为:
<a href="http://example.com" style="font-size:16px"> 文章内容</a>
以下内容因为未指定会被过滤:
someproperty
未指定的 HTML 属性color
未指定的 CSS 属性script
未指定的 HTML 标签
1. 安装 HTMLPurifier for Laravel 5
使用 Composer 安装:
$ composer require "mews/purifier:~2.0"
2. 配置 HTMLPurifier for Laravel 5
命令行下运行
$ php artisan vendor:publish --provider="Mews\Purifier\PurifierServiceProvider"
请将配置信息替换为以下:
config/purifier.php
<?phpreturn [ 'encoding' => 'UTF-8', 'finalize' => true, 'cachePath' => storage_path('app/purifier'), 'cacheFileMode' => 0755, 'settings' => [ 'user_topic_body' => [ 'HTML.Doctype' => 'XHTML 1.0 Transitional', 'HTML.Allowed' => 'div,b,strong,i,em,a[href|title],ul,ol,ol[start],li,p[style],br,span[style],img[width|height|alt|src],*[style|class],pre,hr,code,h2,h3,h4,h5,h6,blockquote,del,table,thead,tbody,tr,th,td', 'CSS.AllowedProperties' => 'font,font-size,font-weight,font-style,margin,width,height,font-family,text-decoration,padding-left,color,background-color,text-align', 'AutoFormat.AutoParagraph' => true, 'AutoFormat.RemoveEmpty' => true, ], ],];
配置里的 user_topic_body
是我们为话题内容定制的,配合 clean()
方法使用:
$topic->body = clean($topic->body, 'user_topic_body');
开始过滤
一切准备就绪,现在我们只需要在数据入库前进行过滤即可:
app/Observers/TopicObserver.php
<?phpnamespace App\Observers;use App\Models\Topic;// creating, created, updating, updated, saving,// saved, deleting, deleted, restoring, restoredclass TopicObserver{ public function saving(Topic $topic) { $topic->body = clean($topic->body, 'user_topic_body'); $topic->excerpt = make_excerpt($topic->body); }}
HTMLPurifier 把白名单里设定的内容通过,script
标签未设定,自动过滤掉。
至此 XSS 安全漏洞已修复。