题目
电商系统用户搜索功能中的SQL注入防护
信息
- 类型:问答
- 难度:⭐⭐
考点
SQL注入原理,参数化查询实现,输入验证策略,ORM安全实践
快速回答
防御SQL注入的核心措施:
- 使用参数化查询:通过预编译语句分离代码与数据
- 严格输入验证:对用户输入进行白名单过滤和长度限制
- 最小权限原则:数据库账号仅授予必要权限
- 避免动态拼接SQL:禁止直接拼接用户输入到SQL语句
- ORM框架安全使用:正确使用ORM的查询方法而非原生SQL拼接
1. 原理说明
SQL注入是攻击者通过构造恶意输入,改变原始SQL语义的攻击方式。在电商用户搜索场景中,若直接拼接用户输入:
# 危险示例(Python伪代码)
query = "SELECT * FROM products WHERE name LIKE '%" + user_input + "%'"当用户输入' OR '1'='1';--时,SQL变为:
SELECT * FROM products WHERE name LIKE '%' OR '1'='1';-- %'这将返回所有产品数据,导致信息泄露。
2. 代码示例
易受攻击代码:
// Java JDBC危险示例
String sql = "SELECT * FROM users WHERE username = '" + request.getParameter("user") + "'";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);修复方案(参数化查询):
// 使用PreparedStatement
String sql = "SELECT * FROM users WHERE username = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, request.getParameter("user")); // 自动处理特殊字符
ResultSet rs = pstmt.executeQuery();ORM框架示例(Hibernate):
// 安全用法
String hql = "FROM Product WHERE name LIKE :name";
Query query = session.createQuery(hql);
query.setParameter("name", "%" + userInput + "%"); // 参数化设置
// 危险用法(仍存在注入风险)
Query unsafeQuery = session.createQuery(
"FROM Product WHERE name LIKE '%" + userInput + "%'"
);3. 最佳实践
- 参数化查询优先:始终使用
PreparedStatement或ORM参数绑定 - 输入验证双层防护:
- 白名单验证:例如搜索词仅允许字母数字和空格
if (!userInput.matches("[a-zA-Z0-9\\s]+")) { throw new InvalidInputException(); } - 长度限制:
userInput.length() < 50
- 白名单验证:例如搜索词仅允许字母数字和空格
- 最小权限原则:数据库账号禁用
DROP、DELETE等危险权限 - 错误处理:返回通用错误信息,避免泄露数据库结构
4. 常见错误
- 部分参数化:仅对部分参数使用预处理,其他仍拼接
// 错误!tableName仍可被注入 String sql = "SELECT * FROM " + tableName + " WHERE id = ?"; - 错误转义:依赖自定义过滤函数(如
replace("'", "''")),可能被绕过 - 信任ORM绝对安全:错误认为ORM完全免疫注入(实际需正确使用API)
5. 扩展知识
- 二次注入:从数据库取出的“安全数据”被再次拼接使用时触发
- 自动化检测:使用SQLMap等工具进行注入点扫描
- 防御深度:结合WAF(Web应用防火墙)提供额外防护层
- 新趋势:
- Java Persistence API (JPA) 的
CriteriaQuery类型安全查询 - R2DBC响应式驱动的参数化查询
- Java Persistence API (JPA) 的