SQL注入如何防护_高频场景实例讲解便于理解使用【教程】

1次阅读

sql注入防护核心是禁用字符串拼接,优先使用参数化查询,辅以白名单校验动态标识符整型转换限制分页参数,并叠加最小权限、错误脱敏和禁用raw SQL。

SQL注入如何防护_高频场景实例讲解便于理解使用【教程】

sql注入防护核心是不拼接用户输入到sql语句,优先使用参数化查询(预编译),辅以输入校验、最小权限和错误信息脱敏。下面结合高频场景讲清楚怎么落地。

场景一:登录验证——别用字符串拼接查账号

常见错误写法(危险!):

sql = “select * FROM users WHERE username = ‘” + user_input + “‘ AND password = ‘” + pwd_input + “‘”

攻击者输入用户名 ' OR '1'='1 就能绕过密码验证。

正确做法:

  • java(JDBC)用 PreparedStatement:
  • String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
  • ps.setString(1, username); ps.setString(2, password);
  • python(sqlite3 / pymysql)用占位符 %s 或 ?,数据库驱动自动转义:
  • cursor.execute("SELECT * FROM users WHERE username = %s AND password = %s", (user, pwd))

场景二:搜索功能——动态字段名/表名不能参数化?那就白名单校验

比如前端传参 sort=agetable=orders,这些不能直接当参数填入 SQL(因为 ? 只适用于值,不适用于标识符)。

安全方案:

  • 定义允许的字段名白名单:valid_sorts = ["name", "age", "create_time"]
  • 收到 sort 参数后先检查是否在白名单内,不在就拒绝或默认 name
  • 表名同理:if table_name not in ["users", "orders", "products"]: raise ValueError("非法表名")
  • 绝对不要用 format() 或 f-string 拼接字段或表名

场景三:分页查询——offset 和 limit 是数字,也要防注入

错误示例:"SELECT * FROM news LIMIT " + limit + " OFFSET " + offset

虽然看起来是数字,但若没严格类型转换,攻击者可传 10; DROP TABLE news--(某些数据库支持多语句时极危险)。

安全做法:

  • 强制转为整型并做范围限制(如最大只允许 100 条)
  • limit = max(1, min(100, int(request.args.get("limit", 10))))
  • 再用参数化方式传入(多数数据库支持 limit ? offset ?)
  • mysql / postgresql 都支持:SELECT * FROM goods LIMIT %s OFFSET %s

额外但关键的三层加固

光靠参数化还不够,建议叠加以下措施:

  • 数据库账号最小权限:Web 应用连接数据库的账号,只给 SELECT/INSERT/UPDATE 权限,禁用 DROP、deleteunion 等高危操作
  • 关闭详细错误回显:生产环境把数据库报错(如 “You have an error in your SQL syntax”)替换成统一提示,避免泄露表结构
  • 使用 ORM 时也别手写 raw SQL:DjangoFilter(name__icontains=x)、SQLAlchemy 的 query.filter(User.name.contains(x)) 默认安全;但 session.execute("SELECT ... WHERE name = '" + x + "'") 依然危险

基本上就这些。记住:参数化是底线,白名单是补充,权限和错误控制是保险。不复杂但容易忽略。

text=ZqhQzanResources