本文的示例代码参考xss
目录
XSS
关于XSS基础知识 可以参考
本文主要讨论应对XSS的3种常见方法
HTTPOnly: 禁止页面JavaScript访问带有HttpOnly属性的Cookie
数据有效性: 对数据有效性做校验 例如: 邮箱 / 手机号/ 账号 / 密码是否合理(符合规则)等
数据的过滤: 对特殊数据进行过滤 例如: script标签等
方法1 HTTPOnly
vim httponly.php
<?php
header("Set-Cookie: cookie1=test1;");
header("Set-Cookie: cookie2=test2;httponly", false);
?>
<script>
alert(document.cookie);
</script>
sudo vim /etc/nginx/conf.d/httponly.conf
server {
listen 80;
server_name httponly.test;
location / {
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_param SCRIPT_FILENAME /home/saas/httponly.php;
}
}
sudo nginx -s reload
关于Nginx的安装配置 更多参考Nginx简明教程
- 测试
sudo sh -c "echo '127.0.0.1 httponly.test' >> /etc/hosts"
浏览器打开http://httponly.test/ 查看当前cookie
此时 页面弹框只能获取到未设置HTTPOnly的Cookie
方法2 数据有效性
composer create-project laravel/laravel validation --prefer-dist "5.5.*"
# cd validation
php artisan make:controller DemoController
vim app/Http/Controllers/DemoController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DemoController extends Controller
{
public function store(Request $request)
{
$this->validate($request, [
'email' => 'required|email|max:255',
]);
return 'ok';
}
}
vim routes/web.php
<?php
Route::post('/validation', 'DemoController@store')->name('validation');
vim app/Http/Middleware/VerifyCsrfToken.php
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
protected $except = [
'/validation'
];
}
关于Laravel框架的CSRF 更多参考Laravel框架 之 CSRF
- 测试
php artisan serve
curl -X POST -H "Content-type: application/json" -d '{"email":"test@test.com"}' http://localhost:8000/validation
校验成功 返回信息如下
ok
curl -X POST -H "Content-type: application/json" -d '{"email":"test"}' http://localhost:8000/validation
校验失败 返回信息如下
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="0;url=http://localhost:8000" />
<title>Redirecting to http://localhost:8000</title>
</head>
<body>
Redirecting to <a href="http://localhost:8000">http://localhost:8000</a>.
</body>
</html>
- 优化
现在校验失败会重定向到一个页面 并且显示html
下面我们做一个优化 自己控制校验异常的处理
php artisan make:request ValidationRequest
vim app/Http/Requests/ValidationRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\ValidationException;
class ValidationRequest extends FormRequest
{
public function authorize(){
return true;
}
public function rules()
{
return [
'email' => 'required|email|max:255',
];
}
protected function failedValidation(Validator $validator)
{
throw new ValidationException($validator);
}
}
vim app/Http/Controllers/DemoController.php
<?php
namespace App\Http\Controllers;
use App\Http\Requests\ValidationRequest;
class DemoController extends Controller
{
public function store(ValidationRequest $request)
{
return 'ok';
}
}
vim app/Exceptions/Handler.php
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Validation\ValidationException;
class Handler extends ExceptionHandler
{
protected $dontReport = [
//
];
protected $dontFlash = [
'password',
'password_confirmation',
];
public function report(Exception $exception)
{
parent::report($exception);
}
public function render($request, Exception $exception)
{
if ($exception instanceof ValidationException) {
$message = $exception->getMessage() ?: '您没有权限操作';
$code = $exception->getCode() ?: 401;
return response()->json([ 'message' => $message ], $code);
}
return parent::render($request, $exception);
}
}
- 测试
php artisan serve
curl -X POST -H "Content-type: application/json" -d '{"email":"test@test.com"}' http://localhost:8000/validation
校验成功 返回信息如下
ok
curl -X POST -H "Content-type: application/json" -d '{"email":"test"}' http://localhost:8000/validation
校验失败 返回信息如下
{"message":"The given data was invalid."}
方法3 数据的过滤
composer create-project laravel/laravel purifier --prefer-dist "5.5.*"
# cd purifier
php artisan make:controller DemoController
vim app/Http/Controllers/DemoController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DemoController extends Controller
{
public function store(Request $request)
{
return $request->data;
}
}
vim routes/web.php
<?php
Route::post('/purifier', 'DemoController@store')->name('purifier');
vim app/Http/Middleware/VerifyCsrfToken.php
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
protected $except = [
'/purifier'
];
}
- 测试
php artisan serve
curl -X POST -H "Content-type: application/json" -d '{"data":"hello<script>alert(\"data\")</script>"}' http://localhost:8000/purifier
返回信息如下
hello<script>alert("data")</script>
上述<script>标签 可能会导致注入的风险
关于Web注入更多介绍 可以参考web攻击 之 注入
这里 我们可以使用HTMLPurifier来对数据进行过滤 它运用白名单机制对HTML文本信息进行XSS过滤
关于HTMLPurifier更多介绍 可以参考官网
composer require "mews/purifier:~2.0"
php artisan vendor:publish --provider="Mews\Purifier\PurifierServiceProvider"
vim config/purifier.php
<?php
return [
'encoding' => 'UTF-8',
'finalize' => true,
'cachePath' => storage_path('app/purifier'),
'cacheFileMode' => 0755,
'settings' => [
'demo' => [
'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.RemoveEmpty' => true,
],
],
];
vim app/Http/Controllers/DemoController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DemoController extends Controller
{
public function store(Request $request)
{
return clean($request->data, 'demo');
}
}
- 测试
php artisan serve
curl -X POST -H "Content-type: application/json" -d '{"data":"hello<script>alert(\"data\")</script>"}' http://localhost:8000/purifier
返回信息如下
hello