PHP场景下防SQL_Injection的自定义字符过滤函数改进咨询
现有自写
charfilter函数的防护缺陷评估 - 黑名单逻辑天生存在覆盖盲区:仅靠列出来的8个禁字符完全挡不住主流的SQL注入手法。一方面列表混入了
<、>这类和SQL注入风险无关的字符,把XSS防护的职责和SQL注入防护混在一个函数里,既增加了业务误判概率,又漏了大量高风险字符:比如过滤了等号,攻击者可以用LIKE、IN、BETWEEN等运算符构造条件表达式;过滤了--注释符,攻击者可以用#、/*...*/内联注释截断后续SQL;而UNION联合查询这类常见注入手法,根本不需要用到列表里的任何禁字符,就能直接穿透过滤。 - 替换逻辑既损伤正常业务,又没有刚性拦截能力:把禁字符直接替换成空格的方式,会直接破坏正常输入——比如带单引号的外国人名、带特殊符号的用户昵称、需要包含HTML标签的富文本内容,都会被替换成空格导致业务异常。更关键的是函数里定义了
$count接收替换次数,但后续完全没有基于这个值做拦截(比如检测到敏感字符直接返回错误、记录日志),就算识别到异常输入也只是替换后放行,攻击者的试错成本几乎为0。 - 无差别过滤完全不匹配SQL上下文场景:SQL注入的风险和变量在SQL语句中的位置强绑定——是字符串占位、整数占位、表名占位还是排序规则占位,对应需要的防护逻辑完全不同。全局无差别替换既挡不住数值型位置的注入(比如
1 UNION SELECT user,pass FROM users这类不含禁字符的注入语句),又会给正常的字符串输入造成不必要的破坏。 - 存在编码处理的先天漏洞:直接用原生
substr按字节截断字符串长度,碰到UTF-8、GBK这类多字节编码的场景,很容易把中文字符截成乱码,甚至可能把相邻的转义字符截断,反过来破坏防护逻辑;同时没有匹配数据库连接字符集的转义处理,完全挡不住宽字节注入这类经典绕过手法。
可落地的防护强化方向
- 放弃自写黑名单替换作为SQL注入的核心防护,直接使用数据库驱动原生的参数化预处理机制:PHP环境下优先用PDO或mysqli的prepared statement接口,将SQL逻辑和用户输入完全分离,从根源上杜绝注入风险。注意使用PDO时要关闭模拟预处理,避免宽字节绕过的隐患。
- 输入校验采用白名单逻辑替代黑名单过滤:对每个输入字段先定义明确的合法规则,比如用户ID就强制转成整数、邮箱字段就用内置格式校验函数校验、排序字段/表名这类无法做参数化的位置,就拿预定义的合法取值列表做精确匹配,完全不允许未校验的用户输入直接拼接到SQL语句里。
- 历史场景下必须做字符转义时,不要用手动替换空格的逻辑:使用数据库官方提供的转义函数(比如
mysqli_real_escape_string()),且转义前必须匹配当前数据库连接设置的字符集,从根源消除宽字节注入的可能性。 - 长度截断逻辑适配多字节编码:需要做输入长度限制时,使用
mb_substr()按对应业务的字符编码计算截断位置,不要用原生substr按字节截断,避免产生乱码或破坏转义逻辑。 - 补充兜底防护:Web应用使用的数据库账号要配置最小权限,不给
DROP、FILE、SUPER这类高危操作权限,就算出现注入点也不会让攻击者拿到服务器权限或拖取全库数据;同时不要把数据库报错信息直接抛给前端,避免攻击者通过报错反推SQL结构。
内容的提问来源于stack exchange,提问作者Sara Briccoli
相关产品推荐
相关产品推荐

