用claude修复php sql注入,要先追踪输入到sql执行的完整数据流,再改为参数绑定并补上回归测试。修复时还要保留用户数据隔离和排序白名单,不能只替换一个查询函数就认为已经安全。

先把查询入口、认证来源和数据库结构理清楚
先在测试分支或者项目副本里整理好查询文件、调用入口、表结构和预期返回值。只放脱敏后的必要片段就行,绝对不能上传生产密码、完整环境配置、访问令牌或者真实订单数据;如果代码是公司内部项目的,先确认好对外允许开放的处理范围再操作。
把PHP版本、PDO驱动、数据库种类和框架版本一起交代。页面可能先调用服务层再进入仓储层,Claude只看到最后一行查询时,未必知道输入来自哪里,也未必知道哪些过滤和权限检查已经执行。
为什么要优先修正查询边界,而不是只靠加过滤词解决问题
SQL注入的根源是把外部数据拼进查询结构,数据库随后把其中一部分解释为语法。参数化查询将语句结构与数据值分开传递,普通单引号因此无需被手工删掉。但占位符不能代表表名、列名或任意排序片段,这些结构仍需服务端固定映射。
参数绑定本身不会校验订单归属,身份和资源的权限判断逻辑,必须单独抽出来做验证。
验收目标是输入不能改变查询结构,同时正常查询和用户数据隔离仍然成立。只观察页面不报错,或看到Claude说“已修复”,都不足以完成验收。
分3步给Claude提交修复任务
登录Claude后新建会话,先说明只审查测试项目,再粘贴相关代码。文件较长时,可把脱敏片段存为TXT,通过输入框左下角“+”中的“Add files or photos”上传;不要默认任意代码扩展名都受支持。
交代认证用户的取值来源、允许搜索的字段和排序规则。让Claude先输出输入来源、传递过程和SQL执行位置,再提供最小修改差异,暂不执行数据库迁移或生产命令。
收到补丁后逐项核对绑定参数、动态列名、权限条件与错误处理。要求同时给出正常输入、带引号文本、SQL形状文本和跨用户数据的测试,不能只保留一条成功用例。
下面这套提示词,适配已经写了PDO查询的现有文件。提交任务的时候要附上脱敏后的真实代码,如果给出的信息不全,得让Claude把缺失的项明明白白列出来,绝对不能让它凭空脑补生产环境的数据库结构。
审查我附带的PHP订单查询代码,仅处理SQL注入及相关回归。 先列出输入来源→传递函数→SQL执行位置,并说明判断依据。 修复要求:值使用PDO参数绑定;排序列只从固定白名单选择;保留服务端认证用户的owner_id限制。 保持现有返回格式和业务行为,不增加远程请求,不操作生产数据库。 先给最小修改差异,再给完整修复函数和无外部服务依赖的回归测试。 覆盖正常查询、合法单引号、SQL形状输入、其他用户订单和非法排序字段。 无法确认的认证逻辑或数据库行为请明确列为待核验项。
完整实操演示:参数绑定、排序映射和5条回归校验
下面用内存SQLite建立三条教学订单,脚本结束后不会保留数据库。它是可复现的修复样例,不是Claude每次必然返回的代码;真实项目仍需按原有结构审查修改差异。
<?php declare(strict_types=1);
// 独立教学测试:数据库仅存在于当前进程内存,不连接生产系统。
if (!in_array('sqlite', PDO::getAvailableDrivers(), true)) {
throw new RuntimeException('This demo requires pdo_sqlite.');
}
$db = new PDO('sqlite::memory:', null, null, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
$db->exec('CREATE TABLE orders (id INTEGER PRIMARY KEY, owner_id INTEGER NOT NULL, item TEXT NOT NULL)');
$insert = $db->prepare('INSERT INTO orders (id, owner_id, item) VALUES (?, ?, ?)');
foreach ([[101, 7, 'Cup'], [102, 8, 'Keyboard'], [103, 7, "O'Reilly book"]] as $row) {
$insert->execute($row);
}
function findOrders(PDO $db, int $authenticatedUserId, string $item, string $sort): array {
// 标识符不能参数绑定:先由固定映射选出服务端列名。
$columns = ['id' => 'id', 'item' => 'item'];
if (!isset($columns[$sort])) {
throw new InvalidArgumentException('Unsupported sort key');
}
if ($authenticatedUserId 200) {
throw new InvalidArgumentException('Invalid search input');
}
$column = $columns[$sort];
// owner_id取自可信认证上下文,不能直接相信客户端提交的用户编号。
$stmt = $db->prepare("SELECT id FROM orders WHERE owner_id = :owner AND item = :item ORDER BY {$column}");
$stmt->bindValue(':owner', $authenticatedUserId, PDO::PARAM_INT);
$stmt->bindValue(':item', $item, PDO::PARAM_STR);
$stmt->execute();
return array_map('intval', array_column($stmt->fetchAll(), 'id'));
}
// 7在此代表教学夹具中的已认证用户,不是可直接复用的登录实现。
$cases = [
['own_item', 'Cup', [101]],
['apostrophe', "O'Reilly book", [103]],
['other_owner', 'Keyboard', []],
['sql_like_text', "' OR 1=1 --", []],
];
foreach ($cases as [$name, $input, $expected]) {
$actual = findOrders($db, 7, $input, 'id');
if ($actual !== $expected) { throw new RuntimeException('FAIL: ' . $name); }
echo $name, ': PASS ', json_encode($actual), PHP_EOL;
}
try {
findOrders($db, 7, 'Cup', 'id DESC');
throw new RuntimeException('FAIL: invalid sort accepted');
} catch (InvalidArgumentException $e) {
echo 'invalid_sort: PASS rejected', PHP_EOL;
}
echo 'Runtime: PHP ', PHP_VERSION, ' / ', PHP_SAPI, ' / PDO SQLite', PHP_EOL;
保存为audit.php,在启用PDO SQLite的PHP环境运行。这里的用户编号只用于测试夹具,接入网站时必须从可信的服务端认证上下文取得,不能直接读请求参数当作当前用户。
php audit.php
代码已在macOS上的PHP 8.5.10 WebAssembly运行时执行,使用内存SQLite,没有调用Claude模型或连接MySQL。实际结果应为五条PASS;若出现异常或非零退出状态,应停止验收并排查对应测试。

单文件、跨目录两类修复,要分别规划
| 场景 | 给Claude的上下文 | 验收重点 |
|---|---|---|
| 单个遗留PDO查询 | 入口、查询函数、表结构和返回格式 | 值绑定、排序映射与权限条件 |
| 已有框架的多文件项目 | 路由、认证中间件、服务层与仓储层 | 跨层输入流、原生SQL和完整业务回归 |
如果使用Claude Code处理多个文件,可以在项目副本中进行安全审查,再检查每个修改文件;官方的安全审查能力不能替代人工审核。普通网页会话只收到粘贴或上传的内容,不应被当成已经读取本地整个代码库。
换成MySQL时,核对连接字符集、驱动预处理行为、重复命名占位符及分页参数类型,并在测试库执行同一组业务用例。SQLite测试通过,不代表目标数据库的语法、索引或事务行为已经验证。
所有修改做完后,对照这四类问题逐一排查
- 查询还在直接用用户传入的表名或者排序片段:改成服务端做固定映射,占位符只用来绑定完整的数据值。
- 带单引号的合法名称查不到结果:检查是不是留了多余的手工转义或者删字符逻辑,别靠篡改原始数据来消报错。
- 改完之后还是能查到其他人的订单:核对认证上下文和资源归属的判断逻辑,参数绑定替代不了权限校验。
- 只有聊天里的文字结论,拿不到可运行的测试用例:让它输出补丁差异和实际执行结果,所有失败用例都跑通之后再做业务侧回归。
上线前复核最小数据库权限、异常日志与返回给用户的错误信息,并保留可回退的代码版本。搜索查询、导出接口和后台任务可能复用同一段拼接逻辑,应逐入口验收,不把修好一个页面当成整个项目已经清零风险。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











