101.XSS 过滤
- 本系列文章为
laracasts.com
的系列视频教程——Let's Build A Forum with Laravel and TDD 的学习笔记。若喜欢该系列视频,可去该网站订阅后下载该系列视频, 支持正版 ;- 视频源码地址:github.com/laracasts/Lets-Build-a-...;
- 本项目为一个 forum(论坛)项目,与本站的第二本实战教程 《Laravel 教程 - Web 开发实战进阶》 类似,可互相参照。
本节说明
- 对应视频教程第 101 小节:Sanitizing is a Must
本节内容
本节我们来完成最后一个功能点:防止 XSS 安全漏洞。我们依然从建立测试开始,我们对话题与回复均进行 XSS 过滤,所以我们新建两个测试:
forum\tests\Unit\ThreadTest.php
.
.
/** @test */
public function a_thread_body_is_sanitized_automatically()
{
$thread = create('App\Thread',['body' => "<script>alert('bad')</script><p>This is OK.</p>"]);
$this->assertEquals("<p>This is OK.</p>",$thread->body);
}
}
forum\tests\Unit\ReplyTest.php
.
.
/** @test */
public function a_reply_body_is_sanitized_automatically()
{
$reply = create('App\Reply',['body' => "<script>alert('bad')</script><p>This is OK.</p>"]);
$this->assertEquals("<p>This is OK.</p>",$reply->body);
}
}
我们借助 HTMLPurifier for Laravel 来过滤 XSS 攻击。首先我们进行安装:
$ composer require "mews/purifier:~2.0"
接着我们进行配置:
$ php artisan vendor:publish --provider="Mews\Purifier\PurifierServiceProvider"
将配置信息替换为以下:
config/purifier.php
<?php
return [
'encoding' => 'UTF-8',
'finalize' => true,
'cachePath' => storage_path('app/purifier'),
'cacheFileMode' => 0755,
'settings' => [
'thread_or_reply_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,
],
],
];
配置里的thread_or_reply_body
是我们为话题内容定制的,配合 clean() 方法使用:
$thread->body = clean($thread->body, 'thread_or_reply_body');
我们对话题和回复的body
属性进行过滤:
forum\app\Thread.php
.
.
protected static function boot()
{
parent::boot();
static::deleting(function ($thread) {
$thread->replies->each->delete();
});
static::created(function ($thread) {
$thread->update([
'slug' => $thread->title,
'body' => clean($thread->body,'thread_or_reply_body')
]);
});
}
.
.
forum\app\Reply.php
.
.
protected static function boot()
{
parent::boot(); //
static::created(function ($reply){
$reply->thread->increment('replies_count');
$reply->body = clean($reply->body,'thread_or_reply_body');
});
.
.
}
.
.
我们来运行测试:
不出意外的话,如果你现在运行全部测试,会有两个测试不能通过。这个就作为个人练习吧,欢迎发帖讨论。