以一个创建文章的post请求为例进行分析:
一、TP6代码控制器(app/controller/index.php)
php
public function addArticle(Request $request)
{
// 1. 仅提取需要校验的字段
$data = $request->only(['title', 'content']);
// 2. 实例化验证器并执行校验
try {
validate(ArticleValidate::class)->check($data);
} catch (ValidateException $e) {
// 3. 如果校验失败,直接返回错误信息给前端
return json(['code' => 400, 'msg' => $e->getError()]);
}
// 4. 校验通过,安全地写入数据库
$article = Article::create($data);
return json(['code' => 200, 'msg' => '添加成功', 'data' => ['id' => $article->id]]);
}
二、验证器代码(app/validate/ArticleValidate.php)
php
<?php
declare(strict_types=1);
namespace app\validate;
use think\Validate;
class ArticleValidate extends Validate
{
// 1. 定义验证规则
protected $rule = [
'title' => 'require|max:100', // 标题必填,最多100个字符
'content' => 'require|max:20000', // 内容必填,最多20000个字符
];
// 2. 定义自定义错误提示(如果不写,系统会返回默认的英文提示)
protected $message = [
'title.require' => '文章标题不能为空',
'title.max' => '文章标题最多不能超过100个字符',
'content.require' => '文章内容不能为空',
'content.max' => '文章内容最多不能超过20000个字符',
];
}
三、数据库表模型代码(app/model/Article.php)
php
<?php
declare(strict_types=1);
namespace app\model;
use think\Model;
class Article extends Model
{
// 显式指定数据表名为 mf_article,表名为示例,可以根据实际修改
protected $table = 'mf_article';
// 重要:开启自动时间戳(推荐),当数据库表中存在create_time和update_time两个字段时,tp会自动插入和更新两个字段
protected $autoWriteTimestamp = 'datetime';
}
四、本例安全机制解析
- 使用了 ORM 模型(Article::create) :ThinkPHP 的 ORM 模型在执行
create()或save()时,底层默认使用的是 PDO 预处理语句(Prepared Statements)。这意味着数据在传入数据库时,会被当作纯粹的"字符串值"来处理,而不是可执行的 SQL 代码。 - 使用了验证器(Validate) :你在写入数据库前,通过
validate(ArticleValidate::class)->check($data)对数据进行了严格的格式和长度校验。这属于"输入验证",从源头上过滤掉了大量不符合预期的恶意数据。 - 使用了字段提取( $ request->only) :你只提取了
title和content,避免了黑客通过伪造请求传入其他敏感字段进行篡改。
五、扩展:防范XSS攻击
防范 XSS(跨站脚本攻击) :黑客可能会在 content 字段中提交 <script>alert('xss')</script> 这样的代码。虽然这不会破坏数据库,但会在前端渲染时执行恶意脚本。建议在 config/app.php 中配置全局过滤规则,或者在接收数据时使用 htmlspecialchars 进行过滤。
1. 输出层防御:模板引擎自动转义(最核心)
ThinkPHP 6 的模板引擎默认开启了自动转义功能。当你在模板中输出变量时(例如 {$content}),框架会自动调用 htmlspecialchars 函数,将 <script> 等危险标签转换为无害的 HTML 实体(如 <script>)。
- 富文本处理注意 :如果你需要输出包含合法 HTML 标签的富文本内容,可以使用
{$content|raw}来输出原始内容。但务必确保该内容在入库前已经经过了严格的净化,否则极易引发存储型 XSS 攻击。
2. 输入层防御:全局过滤与验证器
虽然输出层能挡住大部分攻击,但"永远不要信任用户的输入"是安全原则。
-
全局默认过滤 :你可以在
config/app.php中配置default_filter,让框架自动对获取到的输入数据进行清洗:php1// config/app.php 2'default_filter' => 'htmlspecialchars', -
富文本专用净化 :如果你的
content字段允许用户输入复杂的 HTML 富文本,单纯使用htmlspecialchars会把正常的排版标签也过滤掉。此时建议在入库前使用专业的 HTML 净化库(如HTMLPurifier),它可以精准移除危险的<script>和onerror属性,同时保留安全的排版标签。
3. 响应头防御:设置内容安全策略 (CSP)
CSP 是浏览器提供的一层额外防御机制。即使页面中存在 XSS 漏洞,CSP 也能阻止恶意脚本的执行。你可以在控制器中为响应添加安全头。