数组参数本身不危险,但未经校验就拼接SQL(如IN子句)极易导致SQL注入;必须逐项校验类型并配合参数化绑定,且需处理空数组等边界情况。

前端传入的数组参数本身不会直接导致 SQL 注入,但一旦你用它拼接 SQL(比如 IN 子句),就极易出事。关键不是“数组”这个结构有多危险,而是你如何把它变成 SQL 字符串的一部分。
为什么 JSON.stringify(arr) 直接塞进 SQL 是高危操作
常见错误是把前端传来的 ids=[1,2,3] 解析成数组后,用 arr.join(',') 拼进 WHERE id IN (1,2,3) —— 看似干净,但只要数组里混进字符串或恶意构造值(比如 ["1", "2 OR 1=1 --"]),就会触发注入。
更隐蔽的是后端没做类型校验,把字符串 "1' UNION SELECT password FROM users--" 当作合法数组元素保留下来,最终拼进 SQL。
- 数组成员必须逐个校验类型,不能只校验
Array.isArray() - 不能依赖前端传来的 JSON 类型,
["1", "2"]在 JS 里全是字符串,后端解析后仍是字符串 -
parseInt(x, 10)或Number(x)遇到非法内容会返回NaN或0,需主动拦截而非静默 fallback
PHP 中对数组成员做安全整型转换的实操
PHP 的 filter_var_array() 是最省心的方式,它能批量处理并拒绝非法项,比手写循环 + intval() 更可靠。
$_GET['ids'] = ['1', '2', 'abc', '4'];
$allowed_ids = filter_var_array($_GET['ids'], [
'filter' => FILTER_VALIDATE_INT,
'options' => ['min_range' => 1, 'max_range' => 999999]
]);
// 结果:[1, 2, false, 4] → 过滤掉 false
$clean_ids = array_filter($allowed_ids, 'is_int');
if (count($clean_ids) === 0) {
throw new InvalidArgumentException('No valid IDs provided');
}
// 最终用于 SQL:implode(',', $clean_ids)
- 别用
array_map('intval', $arr):它把'abc'变成0,而0可能是有效主键 -
FILTER_VALIDATE_INT配合min_range能同时防负数、超大数、空字符串和非数字 - 务必检查过滤后数组长度,空数组直接报错,避免
WHERE id IN ()这类语法错误或逻辑漏洞
Node.js 里用 zod 或 ajv 校验数组成员类型
靠手写 map(Number).filter(Number.isSafeInteger) 容易漏掉 Infinity、NaN、科学计数法字符串(如 "1e5")等边界情况。用 schema 校验更稳。
HISUI 前端框架基础开发指南。HISUI 是基于 easyui 二次开发的 jQuery UI 组件库,专为医疗信息系统设计。当涉及 HISUI 组件开发、jQuery easyui 表格/表单/布局/窗口、医疗系统前端页面编写时使用此 skill。 涵盖 40 个组件的官方文档参考,支持声明式与编程式两种初始化方式,提供 $cm/$m 数据访问方法。
import { z } from 'zod';
const idArraySchema = z.array(z.number().int().positive().finite());
try {
const cleanIds = idArraySchema.parse(req.query.ids);
// ✅ 此时 cleanIds 是严格 number[],可放心用于参数化查询
} catch (err) {
throw new Error('Invalid ID list format');
}
-
z.number()不接受字符串,哪怕它是"123"—— 这正是你要的:强制前端传数字,不替它“好心”转换 - 如果必须兼容字符串数字(如 query string 里的
?ids=1&ids=2),先用z.string().regex(/^\d+$/)校验,再转Number - 永远不要在 ORM 的
whereIn里直接传未经校验的原始数组,哪怕它看起来“只是数字”
真正安全的 SQL 构建方式:数组 ≠ 拼字符串
即使数组成员全过校验,也别自己拼 IN (?, ?, ?)。所有主流数据库驱动都支持数组参数绑定:
- MySQL2(Node.js):
conn.execute('SELECT * FROM t WHERE id IN (?)', [cleanIds]) - Python psycopg2:
cursor.execute("SELECT * FROM t WHERE id = ANY(%s)", (cleanIds,)) - PHP PDO:
$stmt = $pdo->prepare("SELECT * FROM t WHERE id IN (" . str_repeat('?,', count($cleanIds) - 1) . "?)"); $stmt->execute($cleanIds);
重点在于:数组成员校验是前置防线,参数化绑定才是最终保险。两者缺一不可——漏掉校验,恶意数据可能绕过绑定逻辑;漏掉绑定,校验再严也白搭。
最容易被忽略的是:当数组为空时,IN () 语法不合法,且业务逻辑往往没覆盖这个分支。别让它走到数据库层才报错。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










