文档首页> 技术教程> SQL 注入离我们有多远:参数化示例

SQL 注入离我们有多远:参数化示例

发布时间:2025-12-29 21:08        更新时间:2025-12-29 22:52
SQL 语句里出现第一处字符串拼接,注入风险就产生了。它不是玄学攻击,原理一句话讲完:用户输入被当成了 SQL 代码执行。它离每个写后端的人都不远:只要有一条 SQL 拼接了用户输入,风险就是实打实存在的,和项目大小无关。 一个注入长什么样 登录查询拼字符串: sql = "SELECT * FROM users WHERE name='" + name + "' AND pwd='" + pwd + "'" 攻击者在密码框输入 ' OR '1'='1,拼出来的语句变成: SELECT * FROM users WHERE name='x' AND pwd='' OR '1'='1' OR '1'='1' 恒为真,密码校验被整个绕过。更狠的输入还能删表、拖库,原理相同:把数据当代码塞进了执行流。真实的攻击是工具化的:自动扫全站参数,把各种变形载荷挨个试一遍,远比手工试探高效。 参数化改写 参数化查询(预编译语句)把 SQL 结构和参数值分开传送,参数从头到尾只当数据解析: Python(pymysql): cursor.execute("SELECT * FROM users WHERE name=%s AND pwd=%s", (name, pwd)) PHP(PDO): $stmt = $pdo->prepare("SELECT * FROM users WHERE name=? AND pwd=?"); $stmt->execute([$name, $pwd]); 改写成本就这几行,但注入路径被彻底堵死,是安全措施里少有的"做了就等于修好"。查询条件动态变化的场景,把 SQL 骨架按分支拼好,值依然全部走占位符传入,灵活和安全可以兼得。 ORM 也别拼字符串 用了 ORM(对象关系映射框架)不等于进了保险箱。框架自带的查询接口是参数化的,可一旦写原生 SQL 片段,老问题就回来了:where("name='" + name + "'") 这种写法在 ORM 里照样注入。原则只有一条:任何用户输入进 SQL 必须走占位符,没有例外。代码评审时看到字符串拼进查询语句,无论出现在哪一层,都按注入风险处理。 附加防线 参数化之外再叠两层:数据库账号按最小权限配置,就算被打穿,能拖走的也有限;入口层拦掉明显异常的超长输入和特殊字符,能挡掉大量扫描器噪音。防线可以多层,但核心自始至终只有参数化这一条。另外,错误信息里别把用户输入原样回显,能少给探测者不少反馈。