您现在的位置是:网站首页 > 心得笔记

laravel框架中防止XSS 安全漏洞 插件包

盛悦2019-08-07739人围观
简介作为一个合格的 Web 开发工程师,必须遵循一个安全原则:永远不要信任用户提交的数据。

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>&lt;script&gt;alert(211);&lt;/script&gt;</p>

<p><br /></p>

<p>测试xss攻击<br /></p>

可见 Simditor编辑器默认为我们输入的内容提供转义了!

页面上显示:

10(1).png

很多同学会大意地认为前端页面有 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>

以下内容因为未指定会被过滤:

  1. someproperty 未指定的 HTML 属性

  2. color 未指定的 CSS 属性

  3. 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 安全漏洞已修复。