diff --git a/notes/攻击技术.md b/notes/攻击技术.md index 9c56e27c..ec3bfea8 100644 --- a/notes/攻击技术.md +++ b/notes/攻击技术.md @@ -194,6 +194,14 @@ stmt.setString(2, password); ResultSet rs = stmt.executeQuery(); ``` +需要注意的是,MySQL 的 JDBC 驱动(Connector/J)默认并不在服务器上预编译,而是在客户端把参数中的单引号等字符转义后,拼成完整的语句发送。在本机用 Connector/J 8.3 执行上面的查询,两个参数都传入 1' OR '1'='1,MySQL 通用查询日志中记录的是: + +```text +Query SELECT * FROM users WHERE name = '1'' OR ''1''=''1' AND pw = '1'' OR ''1''=''1' +``` + +参数仍然只是一个普通的字符串,查询结果为空。连接参数加上 useServerPrepStmts=true 后,驱动才会先发送 Prepare、再发送 Execute。两种方式都能防止注入,关键在于参数由驱动或数据库处理,而不是由开发者拼接。表名、列名和 ORDER BY 的字段不能使用占位符,只能用白名单校验,见 [MyBatis 的 #{} 和 ${}](Spring.md#-和--的区别)。 + #### 2. 单引号转换 将传入的参数中的单引号转换为连续两个单引号。PHP 的 Magic Quotes 曾经自动完成这个功能,但是因为不可靠已经被移除,应该使用数据库驱动提供的转义函数,并且只在无法使用参数化查询时使用。