必须用参数化查询修复sql注入,正则仅作辅助校验;订单id需按业务规则严格限定格式,模糊搜索仍可用参数化;响应须收敛避免泄露数据库细节。

订单搜索功能一旦被注入,攻击者能直接拖出全量订单、篡改状态甚至伪造支付记录。仅靠正则校验无法修复SQL注入漏洞,它最多算一道提示性过滤;真正有效的修复必须用参数化查询,且正则规则本身必须严格匹配业务预期范围。
订单ID搜索为什么不能用宽泛正则
很多开发者写 preg_match('/[^\w]/', $order_id) 或更松的 /[^a-zA-Z0-9\-_]/,以为拦住单引号就安全了。实际问题在于:
- 订单ID若设计为纯数字(如
123456789),正则应强制ctype_digit($order_id)或/^\d+$/,多一个字母或横线都是非法输入 - 若支持带前缀的格式(如
ORD-2026-0001),正则必须精确到结构:/^ORD-\d{4}-\d{4}$/,不能写成/ORD.*\d+/—— 后者会被ORD' OR '1'='1绕过 - 正则放在前端毫无防护意义,攻击者绕过浏览器直接发请求;后端即使做了正则,也绝不能跳过参数化查询
PHP 中搜索 SQL 必须用 prepare + bind_param
错误写法(哪怕加了正则):$sql = "SELECT * FROM orders WHERE order_id = '$order_id'";
正确路径只有一条:剥离用户输入与 SQL 结构。
- MySQLi 示例:
$stmt = $mysqli->prepare("SELECT * FROM orders WHERE order_id = ?");,然后$stmt->bind_param("s", $order_id); - PDO 示例:
$stmt = $pdo->prepare("SELECT * FROM orders WHERE order_id = ?");,然后$stmt->execute([$order_id]); - 注意:不要用
mysql_real_escape_string—— 已废弃,且对宽字节、十六进制编码等场景完全失效 - 如果搜索支持模糊匹配(
LIKE),参数化仍有效:WHERE order_id LIKE CONCAT('%', ?, '%'),问号依然走 bind
响应行为要收敛,避免泄漏数据库细节
当用户输入非法格式(如含单引号、空格、SQL 关键字)时,系统不应返回 MySQL 错误码 1064 或堆栈信息。这类响应等于告诉攻击者:“你打中了SQL解析层”。
- 正则校验失败时,统一返回
HTTP 400 Bad Request+ 简短提示:“订单号格式错误” - 参数化查询执行出错(极小概率),捕获异常并记录日志,但对外返回通用错误页,不暴露表名、字段名、驱动类型
- 特别警惕“基于时间的盲注”:如果攻击者发现输入
1' AND SLEEP(5)--导致响应延迟,说明服务端未做输入格式强约束,且错误处理未收敛
真正难的不是写对那行 prepare(),而是从需求评审阶段就定义清楚订单ID的生成规则和合法字符集——一旦允许用户自由输入任意字符串去搜“订单”,再严密的正则和参数化都挡不住业务逻辑层面的失控。











