Prepared Statement 预编译语句
先把 SQL 语句的结构传给数据库编译,再把用户输入作为参数填进去的编码技术。数据库知道”这是结构,那是数据”,不会把数据当代码执行 —— 这就堵死了 SQL injection。
拼字符串 vs Prepared Statement
危险写法(拼字符串):
"SELECT * FROM users WHERE name = '" + userInput + "'"用户输入 ' OR '1'='1 就完蛋。
安全写法(prepared statement):
SELECT * FROM users WHERE name = ?然后单独传 userInput 作为参数。数据库永远把 ? 当数据,不当代码。
为啥这是 SQL Injection 的克星
SQL injection 的本质是”用户输入被当成代码执行”。Prepared statement 在协议层就把代码和数据分开了 —— 不是过滤、不是转义,而是结构上不可能被注入。
主流语言里的写法
| 语言/框架 | API |
|---|---|
| PHP | PDO prepare() + execute() |
| Python | cursor.execute(sql, params) |
| Java | PreparedStatement |
| Node.js | mysql2 的 ? 占位符 |
| Go | db.Query(sql, args...) |
注意
- ORM(如 SQLAlchemy、Prisma)底层都是 prepared statement,但字符串拼接绕过 ORM 一样危险
- Table name、column name 不能参数化,需要白名单校验
跟输入验证(input validation)配合使用,纵深防御。