有什么有效的方法防止SQL注入攻击(SQL Injection)

你好,我是风一样的树懒,一个工作十多年的后端开发,曾就职京东、阿里等多家互联网头部企业。

点击下方👇关注公众号,带你一起复习后端技术,看看面试考点,补充积累技术知识,每天都为面试准备积累

SQL注入攻击(SQL Injection)是指攻击者通过在应用程序输入的字段中插入恶意的 SQL 代码,从而影响数据库的查询逻辑,最终达到未授权访问、篡改或删除数据库的目的。为了有效防止 SQL 注入攻击,可以采取以下几种措施:


01
使用预编译语句(Prepared Statements)


最有效的防止 SQL 注入攻击的方法是使用预编译语句(也叫参数化查询)。这确保了用户输入的数据不会被当作 SQL 代码执行,从而避免了 SQL 注入攻击。

String query = "SELECT * FROM users WHERE username = ? AND password = ?";PreparedStatement pstmt = connection.prepareStatement(query);pstmt.setString(1, username);  // 设置用户名参数pstmt.setString(2, password);  // 设置密码参数ResultSet rs = pstmt.executeQuery();


通过这种方式,SQL 查询中的参数值(如 username 和 password)会作为参数传入,而不会被直接拼接成 SQL 语句,从而避免了 SQL 注入攻击。


02
使用存储过程(Stored Procedures)


存储过程是预定义的 SQL 语句集合,通过调用存储过程来执行数据库操作。存储过程通常会对输入数据进行严格的检查和处理,因此可以有效避免 SQL 注入。

CREATE PROCEDURE GetUserData (IN username VARCHAR(255), IN password VARCHAR(255))BEGIN    SELECT * FROM users WHERE username = username AND password = password;END;

调用存储过程时,输入参数不会直接拼接进 SQL 查询中,从而降低了 SQL 注入的风险。


03
输入验证和过滤


输入验证:验证用户输入的数据是否符合预期类型和范围,例如检查是否为合法的数字、字母或预定格式(如邮箱、手机号等)。对于输入字段,限制其长度、类型和格式,减少恶意 SQL 注入的可能性。

过滤特殊字符:对于所有输入数据,尤其是字符串类型的输入,过滤掉可能被用来进行 SQL 注入的特殊字符,如 '、"、;、-- 等。

// 过滤掉可能的危险字符String safeInput = userInput.replaceAll("[^a-zA-Z0-9]""");


04
使用 ORM(对象关系映射)框架


ORM 框架如 Hibernate、JPA、MyBatis 等,封装了数据库的访问层,通过对象的方式访问数据。这些框架通常会自动使用参数化查询,并对数据进行安全处理,避免了手动拼接 SQL 语句时可能带来的 SQL 注入风险。

String hql = "FROM User WHERE username = :username AND password = :password";Query query = session.createQuery(hql);query.setParameter("username", username);query.setParameter("password", password);List results = query.list();


05
限制数据库权限


最小权限原则:限制数据库用户的权限,只赋予其执行特定操作所需的权限。比如,应用程序的数据库用户不应拥有 DROP、DELETE 等修改结构的权限,避免攻击者通过 SQL 注入获取权限进行更严重的攻击。


06
错误信息处理


避免暴露数据库错误信息,不向用户显示具体的错误信息(例如 SQL 语法错误或数据库连接失败)。攻击者可以利用这些错误信息来发现数据库的结构和漏洞。

  • 开发时:开启详细的错误日志记录。

  • 生产环境:只返回通用的错误消息,隐藏数据库的详细错误。

// 在捕获异常时,只返回通用错误信息try {    // 执行数据库操作catch (SQLException e) {    // 记录日志,返回通用错误信息    log.error("Database error", e);    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "An error occurred");}


通常,面试可能大家能回答一到两条,特别是第六种情况,很容易忽略,且容易暴露数据库相关信息。


今天的内容就分享到这儿,喜欢的朋友可以关注,点赞。有什么不足的地方欢迎留言指出,您的关注是我前进的动力!

END


扫码关注

一起积累后端知识
不积跬步,无以至千里
不积小流,无以成江海

喜欢此内容的人还喜欢

谈谈id那些事(五)——美团的 Leaf 的ID生成


一个阿里二面面试官必问的问题


Lambda表达式说爱你不容易


分享面试:mysql数据库索引失效的情况


Spring-Boot中一个不起眼的好工具StopWatch