thinkphp防sql注入须坚持参数绑定,不可依赖“自动过滤”;where()传字符串等于裸奔,数组语法仅对标准字段值生效,exp/原生sql/动态表名等必须白名单校验或手动bind。

ThinkPHP防SQL注入:用对预处理,别信“自动过滤”
ThinkPHP 5.x/6.x 默认使用 PDO 或 MySQLi 扩展,并支持参数化查询,这是防 SQL 注入的基石。但很多开发者误以为框架“自动做了安全处理”,结果在手动拼接 SQL 时翻车。例如:
✘ 错误写法(字符串拼接):
$map['title'] = ['like', '%' . $_GET['q'] . '%'];
$list = Db::name('article')->where($map)->select();
看似用了数组查询语法,但如果 $_GET['q'] 含恶意内容(如 %' OR '1'='1),且未做输入校验,仍可能触发绕过逻辑(尤其在复杂条件组合或闭包查询中)。
✔ 正确做法是坚持参数绑定:
- 使用原生预处理语句:
$sql = "SELECT * FROM article WHERE title LIKE ?";<br>$list = Db::query($sql, ["%{$_GET['q']}%"]); - 或统一走 QueryBuilder 的占位符方式:
$list = Db::name('article')<br> ->where('title', 'like', "%:keyword%")<br> ->bind(['keyword' => $safeKeyword])<br> ->select(); - 对数字类参数,强制类型转换:
$id = (int)$_GET['id'];<br>$user = Db::name('user')->where('id', $id)->find();
特别注意:ThinkPHP 的 where() 数组语法虽内置转义,但仅对标准字段值生效;若涉及原始 SQL 片段(如 exp 类型)、子查询、或 order/group 动态传参,必须手动过滤或白名单限制。
ThinkPHP防XSS:输出在哪转义,就在哪处理
XSS 不是“提交时过滤干净就一劳永逸”,而是“谁输出、谁负责转义”。ThinkPHP 模板引擎(ThinkTemplate)默认不自动 HTML 转义,这点和 Laravel 的 {{ }} 不同。所以:
✘ 危险写法:
{$user_comment} —— 直接输出未处理的用户内容
✔ 安全写法:
{:htmlspecialchars($user_comment, ENT_QUOTES | ENT_HTML5, 'UTF-8')}
更推荐在控制器层统一处理敏感字段:
- 返回 JSON 接口时:
return json(['content' => htmlspecialchars($data['content'], ENT_NOQUOTES, 'UTF-8')]); - 模板中批量处理:
定义公共函数或使用模板变量修饰器:{:text($user_comment)},并在配置中注册text为htmlspecialchars别名 - 富文本内容不能简单转义,需用白名单过滤:
引入HTMLPurifier或 ThinkPHP 插件think-helper中的HtmlFilter类,只允许<p><strong><ul></ul></strong></p>等安全标签
ThinkPHP专属风险点:别踩这些“默认陷阱”
ThinkPHP 提供了便捷的快捷方法,但部分特性在特定场景下会弱化安全边界:
-
路由变量未校验:定义
route/[:id]后,直接用$this->request->param('id')取值,若未验证是否为数字或长度,可能被用于路径遍历或盲注探测 -
数据库调试模式开启:开发环境
app_debug = true时,SQL 错误会暴露表名、字段甚至完整语句。上线前务必确认app_debug = false且show_error_msg = false -
动态模型名/表名拼接:
$model = new $className();或Db::name($_GET['table'])—— 这属于高危行为,必须用白名单严格限制可选值,如:$allowed = ['user', 'article', 'order'];<br>if (!in_array($_GET['table'], $allowed)) { throw new HttpException(400); }
纵深防御:不止代码层,还要配好环境与头
安全不是单点防护。ThinkPHP 项目上线前应叠加以下配置:
-
PHP 配置加固:
关闭display_errors、expose_php、allow_url_include;启用open_basedir限制文件访问范围 -
HTTP 安全头(在中间件或全局过滤器中添加):
header('X-Content-Type-Options: nosniff');<br>header('X-Frame-Options: DENY');<br>header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https:;");
注意:unsafe-inline仅限兼容旧 JS,新项目建议用nonce或哈希 -
Cookie 安全:
在config/session.php中设置:'httponly' => true,<br>'secure' => true, // 仅 HTTPS 传输<br>'samesite' => 'Strict'
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











