如何通过正则表达式校验防止网站注册页面的用户名SQL注入?
- 内容介绍
- 文章标签
- 相关推荐
本文共计825个文字,预计阅读时间需要4分钟。
用户提交的用户名如直接拼接进以下SQL语句,则可能导致攻击者输入如`admin' --`或`test' OR '1'='1`等恶意内容,从而绕过验证、写入异常数据,甚至拖库。这不是会不会发生的问题,而是只要没有防护,就一定会被扫到的问题。
只用正则校验用户名够不够防SQL注入
不够。正则只是第一道过滤,不是银弹:
- 正则只能拦住明显恶意字符(比如单引号、分号、
--、/*),但绕过方式极多:Unicode 编码、宽字节注入、双写关键字(seleselectct)、空字节截断等 - 正则规则太松 → 漏掉攻击载荷;太严 → 拦住合法用户名(如昵称含中文、emoji、连字符的用户)
- 正则在前端做毫无意义,必须后端执行,且不能替代参数化查询
推荐组合策略:
- 前端用正则简单提示(提升体验,不依赖它防攻击)
- 后端用正则做初步清洗(如 preg_replace('/['";-+/*\]/', '', $username))
- 但最终插入数据库前,必须走参数化查询
PHP 中注册逻辑怎么写才真正安全
核心是:永远不用字符串拼接构造 SQL。
错误写法(哪怕加了正则):
$username = $_POST['username']; $username = preg_replace('/['";-+/*\]/', '', $username); $sql = "INSERT INTO users (username) VALUES ('$username')"; // 危险!
正确写法(PDO + 预处理):
$pdo = new PDO($dsn, $user, $pass); $stmt = $pdo->prepare("INSERT INTO users (username) VALUES (?)"); $stmt->execute([$username]); // 用户输入原样传入,由驱动处理转义
注意点:
- 不要自己写 mysql_real_escape_string —— 已废弃,且无法防御所有绕过
- 如果用 MySQLi,必须用 mysqli_prepare() + bind_param(),不能用 mysqli_real_escape_string() 拼接
- 正则清洗后的 $username 仍要进预处理,不要以为“洗过了就安全了”
正则表达式该匹配什么、不该匹配什么
目标不是“拦住所有坏字符”,而是“定义合法用户名范围”,再配合参数化兜底。
常见合理正则(以 PHP preg_match 为例):
- 英文+数字+下划线:/^[a-zA-Z0-9_]{3,20}$/
- 支持中文和常见符号:/^[x{4e00}-x{9fa5}a-zA-Z0-9_-u3002uff1fuff01uff0cu3001uff1buff1au201cu201du2018u2019u300au300bu3008u3009u3010u3011u300cu300du2014u2026u300eu300f]{2,30}$/u
- 必须加 ^ 和 $ 锚定,否则只校验开头一段
别踩的坑:
- 不要用 stripslashes 或 addslashes 替代预处理
- 不要对已过滤的变量再做一次 htmlspecialchars() 再插库(这是防 XSS 的,和 SQL 注入无关)
- 正则里别漏掉 Unicode 空格符(u00a0、u200b),它们可能干扰解析但逃过基础正则
真正的防线不在正则有多密,而在于那条 prepare() 调用有没有被执行。只要没走到这一步,前面所有过滤都只是减缓攻击速度,不是阻止。
本文共计825个文字,预计阅读时间需要4分钟。
用户提交的用户名如直接拼接进以下SQL语句,则可能导致攻击者输入如`admin' --`或`test' OR '1'='1`等恶意内容,从而绕过验证、写入异常数据,甚至拖库。这不是会不会发生的问题,而是只要没有防护,就一定会被扫到的问题。
只用正则校验用户名够不够防SQL注入
不够。正则只是第一道过滤,不是银弹:
- 正则只能拦住明显恶意字符(比如单引号、分号、
--、/*),但绕过方式极多:Unicode 编码、宽字节注入、双写关键字(seleselectct)、空字节截断等 - 正则规则太松 → 漏掉攻击载荷;太严 → 拦住合法用户名(如昵称含中文、emoji、连字符的用户)
- 正则在前端做毫无意义,必须后端执行,且不能替代参数化查询
推荐组合策略:
- 前端用正则简单提示(提升体验,不依赖它防攻击)
- 后端用正则做初步清洗(如 preg_replace('/['";-+/*\]/', '', $username))
- 但最终插入数据库前,必须走参数化查询
PHP 中注册逻辑怎么写才真正安全
核心是:永远不用字符串拼接构造 SQL。
错误写法(哪怕加了正则):
$username = $_POST['username']; $username = preg_replace('/['";-+/*\]/', '', $username); $sql = "INSERT INTO users (username) VALUES ('$username')"; // 危险!
正确写法(PDO + 预处理):
$pdo = new PDO($dsn, $user, $pass); $stmt = $pdo->prepare("INSERT INTO users (username) VALUES (?)"); $stmt->execute([$username]); // 用户输入原样传入,由驱动处理转义
注意点:
- 不要自己写 mysql_real_escape_string —— 已废弃,且无法防御所有绕过
- 如果用 MySQLi,必须用 mysqli_prepare() + bind_param(),不能用 mysqli_real_escape_string() 拼接
- 正则清洗后的 $username 仍要进预处理,不要以为“洗过了就安全了”
正则表达式该匹配什么、不该匹配什么
目标不是“拦住所有坏字符”,而是“定义合法用户名范围”,再配合参数化兜底。
常见合理正则(以 PHP preg_match 为例):
- 英文+数字+下划线:/^[a-zA-Z0-9_]{3,20}$/
- 支持中文和常见符号:/^[x{4e00}-x{9fa5}a-zA-Z0-9_-u3002uff1fuff01uff0cu3001uff1buff1au201cu201du2018u2019u300au300bu3008u3009u3010u3011u300cu300du2014u2026u300eu300f]{2,30}$/u
- 必须加 ^ 和 $ 锚定,否则只校验开头一段
别踩的坑:
- 不要用 stripslashes 或 addslashes 替代预处理
- 不要对已过滤的变量再做一次 htmlspecialchars() 再插库(这是防 XSS 的,和 SQL 注入无关)
- 正则里别漏掉 Unicode 空格符(u00a0、u200b),它们可能干扰解析但逃过基础正则
真正的防线不在正则有多密,而在于那条 prepare() 调用有没有被执行。只要没走到这一步,前面所有过滤都只是减缓攻击速度,不是阻止。

