本文目录导读:

在ThinkPHP项目中防御点击劫持(Clickjacking)攻击,可以通过以下几种方式实现:
HTTP响应头防御(最常用)
使用中间件方式(推荐)
在 app/middleware.php 中注册全局中间件:
<?php
// app/middleware.php
return [
// 全局请求缓存
// \think\middleware\CheckRequestCache::class,
// 多语言加载
// \think\middleware\LoadLangPack::class,
// Session初始化
// \think\middleware\SessionInit::class,
// 添加防点击劫持中间件
\app\middleware\ClickjackingProtection::class,
];
创建中间件 app/middleware/ClickjackingProtection.php:
<?php
namespace app\middleware;
use Closure;
use think\Request;
use think\Response;
class ClickjackingProtection
{
public function handle(Request $request, Closure $next)
{
$response = $next($request);
// 设置X-Frame-Options响应头
$response->header([
'X-Frame-Options' => 'SAMEORIGIN', // 或者 'DENY'
'Content-Security-Policy' => "frame-ancestors 'self'",
]);
return $response;
}
}
在控制器中动态设置
<?php
namespace app\controller;
use think\Request;
class Index
{
public function index(Request $request)
{
// 设置防iframe加载
header('X-Frame-Options: SAMEORIGIN');
header("Content-Security-Policy: frame-ancestors 'self'");
return view();
}
}
使用路由中间件
在 route/app.php 中对特定路由添加中间件:
<?php
use think\facade\Route;
// 给特定路由添加防点击劫持中间件
Route::group('admin', function () {
Route::get('dashboard', 'admin/Dashboard/index');
Route::post('data/save', 'admin/Data/save');
})->middleware(\app\middleware\ClickjackingProtection::class);
Nginx层防御(服务器配置)
在 Nginx 配置中添加:
server {
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Content-Security-Policy "frame-ancestors 'self'" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}
Apache层防御
在 .htaccess 或虚拟主机配置中添加:
Header always append X-Frame-Options SAMEORIGIN Header set Content-Security-Policy "frame-ancestors 'self'"
前端页面防御(JavaScript方式)
在项目入口文件或公共模板中添加:
<!-- 在公共模板文件如 public/header.html 中添加 -->
<script>
// 防止页面被iframe加载
if (window.top !== window.self) {
window.top.location = window.self.location;
// 或者直接显示警告
// document.body.innerHTML = "该页面不允许被嵌入iframe中";
}
</script>
或者在公共控制器中:
<?php
namespace app\common;
class BaseController
{
protected function preventClickjacking()
{
// 判断是否为iframe环境
if (isset($_SERVER['HTTP_SEC_FETCH_DEST']) && $_SERVER['HTTP_SEC_FETCH_DEST'] === 'iframe') {
// 返回错误页面或跳转
return redirect('/');
}
}
}
完整的中间件实现(含多策略)
<?php
namespace app\middleware;
use Closure;
use think\Request;
use think\Response;
class ClickjackingProtection
{
/**
* 防御策略
* allow - 允许所有
* deny - 禁止所有
* sameorigin - 仅允许同源
* whitelist - 白名单
*/
protected $strategy = 'sameorigin';
// 白名单域名
protected $whitelist = [
'example.com',
'admin.example.com'
];
public function handle(Request $request, Closure $next)
{
$response = $next($request);
// 检查来源
$origin = $request->header('origin', '');
$referer = $request->header('referer', '');
switch ($this->strategy) {
case 'deny':
$response->header('X-Frame-Options', 'DENY');
$response->header('Content-Security-Policy', "frame-ancestors 'none'");
break;
case 'sameorigin':
$response->header('X-Frame-Options', 'SAMEORIGIN');
$response->header('Content-Security-Policy', "frame-ancestors 'self'");
break;
case 'whitelist':
if ($this->checkWhitelist($origin, $referer)) {
$response->header('X-Frame-Options', 'ALLOW-FROM ' . $origin);
} else {
$response->header('X-Frame-Options', 'DENY');
$response->header('Content-Security-Policy', "frame-ancestors 'none'");
}
break;
}
// 添加其他安全头
$response->header([
'X-Content-Type-Options' => 'nosniff',
'X-XSS-Protection' => '1; mode=block',
]);
return $response;
}
private function checkWhitelist($origin, $referer)
{
$url = $origin ?: $referer;
if (empty($url)) return true;
$host = parse_url($url, PHP_URL_HOST);
if (!$host) return false;
foreach ($this->whitelist as $domain) {
if ($host === $domain || str_ends_with($host, '.' . $domain)) {
return true;
}
}
return false;
}
// 设置策略的方法
public function setStrategy($strategy)
{
$this->strategy = $strategy;
return $this;
}
}
配置文件方式
在 config/safe.php 中新增配置:
<?php
return [
// 点击劫持防御
'clickjacking' => [
'enable' => true,
'x_frame_options' => 'SAMEORIGIN', // DENY, SAMEORIGIN, 或自定义地址
'csp_frame_ancestors' => "'self'", // 或具体域名列表
],
];
然后在中间件中读取配置:
public function handle(Request $request, Closure $next)
{
$response = $next($request);
$config = config('safe.clickjacking');
if ($config['enable']) {
$response->header('X-Frame-Options', $config['x_frame_options']);
$response->header('Content-Security-Policy',
"frame-ancestors {$config['csp_frame_ancestors']}");
}
return $response;
}
推荐使用组合防御
建议采用多层防御策略:
- Nginx/Apache层:设置基础响应头
- ThinkPHP中间件层:应用级别的防御逻辑
- 前端JavaScript:提供额外保护
这样即使某一层被绕过,其他层还能提供保护,需要根据项目实际需求选择合适的防御级别,对于后台管理页面建议使用DENY或SAMEORIGIN策略。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播