专注Java教育14年 全国咨询/投诉热线:444-1124-454
星辉LOGO图
始于2009,口口相传的Java黄埔军校
首页 hot资讯 如何防止sql注入攻击

如何防止sql注入攻击

更新时间:2022-04-25 09:57:19 来源:星辉 浏览573次

SQL注入是一种注入攻击。当攻击者提交恶意制作的输入时,就会发生注入攻击,从而导致应用程序执行意外操作。由于SQL数据库无处不在,SQL 注入是互联网上最常见的攻击类型之一。

如果您只有时间保护自己免受一个漏洞的影响,那么您应该检查代码库中的 SQL 注入漏洞!

风险

当您遭受 SQL 注入攻击时,可能发生的最糟糕的事情是什么?

我们的示例 hack向您展示了如何绕过登录页面:银行网站的一个巨大安全漏洞。更复杂的攻击将允许攻击者在数据库上运行任意语句。过去,黑客使用注入攻击来:

提取敏感信息,例如社会安全号码或信用卡详细信息。

枚举在网站上注册的用户的身份验证详细信息,因此这些登录信息可用于对其他网站的攻击。

删除数据或删除表,破坏数据库,使网站无法使用。

当用户访问该站点时,注入要执行的更多恶意代码。

SQL 注入攻击非常普遍。雅虎和索尼等大公司的应用程序受到了损害。在其他情况下,黑客组织针对 特定的应用程序或编写旨在收集身份验证详细信息的脚本。即使是安全公司 也不能幸免!

保护

所以 SQL 注入是一个严重的风险。你怎么能保护自己?

参数化语句

编程语言使用数据库驱动程序与 SQL 数据库对话。 驱动程序允许应用程序针对数据库构建和运行 SQL 语句,根据需要提取和操作数据。参数化语句确保传递给 SQL 语句的参数(即输入)以安全的方式处理。

例如, 使用参数化语句在JDBC中运行 SQL 查询的安全方法是:

// Connect to the database.
Connection conn = DriverManager.getConnection(URL, USER, PASS);
// Construct the SQL statement we want to run, specifying the parameter.
String sql = "SELECT * FROM users WHERE email = ?";
// Generate a prepared statement with the placeholder parameter.
PreparedStatement stmt = conn.prepareStatement(sql);
// Bind email value into the statement at parameter index 1.
stmt.setString(1, email);
// Run the query...
ResultSet results = stmt.executeQuery(sql);
while (results.next())
{
    // ...do something with the data returned.
}

将此与 SQL 字符串的显式构造进行对比,后者非常非常危险:

// The user we want to find.
String email = "[email protected]";
// Connect to the database.
Connection conn = DriverManager.getConnection(URL, USER, PASS);
Statement stmt = conn.createStatement();
// Bad, bad news! Don't construct the query with string concatenation.
String sql = "SELECT * FROM users WHERE email = '" + email + "'";
// I have a bad feeling about this...
ResultSet results = stmt.executeQuery(sql);
while (results.next()) {
  // ...oh look, we got hacked.
}

关键区别在于传递给executeQuery(...) 方法的数据。在第一种情况下,参数化字符串和参数分别传递给数据库,这允许驱动程序正确解释它们。在第二种情况下,完整的 SQL 语句是在调用驱动程序之前构建的,这意味着我们容易受到恶意制作的参数的攻击。

您应该始终在可用的情况下使用参数化语句,它们是防止 SQL 注入的第一保护。

您可以在下面的代码示例中看到更多不同语言的参数化语句示例。

对象关系映射

许多开发团队更喜欢使用对象关系映射 (ORM) 框架来使 SQL 结果集到代码对象的转换更加无缝。ORM 工具通常意味着开发人员很少需要在他们的代码中编写 SQL 语句——幸运的是,这些工具在后台使用了参数化语句。

最著名的 ORM 可能是 Ruby on Rails 的Active Record框架。使用 Active Record 从数据库中获取数据如下所示:

def current_user(email)
  # The 'User' object is an Active Record object, that has find methods 
  # auto-magically generated by Rails.
  User.find_by_email(email)
end

像这样的代码可以免受 SQL 注入攻击。

然而,使用 ORM 并不会自动让您免受 SQL 注入的影响。 当需要对数据库执行更复杂的操作时,许多 ORM 框架允许您构造 SQL 语句或 SQL 语句的片段。例如,以下 Ruby 代码容易受到注入攻击:

def current_user(email)
  # This code would be vulnerable to a maliciously crafted email parameter.
  User.where("email = '" + email + "'")
end

作为一般经验法则:如果您发现自己通过连接字符串来编写 SQL 语句,请仔细考虑您在做什么。

转义输入

如果您无法使用参数化语句或为您编写 SQL 的库,则下一个最佳方法是确保正确转义输入参数中的特殊字符串字符。

注入攻击通常依赖于攻击者能够制作一个输入,该输入将过早关闭它们出现在 SQL 语句中的参数字符串。(这就是为什么您经常会在尝试的 SQL 注入攻击中看到'或字符的原因。)"

编程语言有标准的方法来描述其中包含引号的字符串——SQL 在这方面没有什么不同。通常,将引号字符加倍——替换'为''——意味着 “将此引号视为字符串的一部分,而不是字符串的结尾”。

转义符号字符是防止大多数 SQL 注入攻击的简单方法,许多语言都有标准函数 来实现这一点。但是,这种方法有几个缺点:

您需要非常小心地在构建 SQL 语句的代码库中的任何地方转义字符。

并非所有注入攻击都依赖于引用字符的滥用。 例如,当 SQL 语句中需要数字 ID 时,不需要引号字符。无论您如何使用引号字符,以下代码仍然容易受到注入攻击:

def current_user(id)
  User.where("id = " + id)
end

消毒输入

清理输入是所有应用程序的好习惯。在我们的 示例 hack中,用户提供了一个密码 as ' or 1=1--,这看起来很可疑作为密码选择。

开发人员应始终努力拒绝看起来可疑的输入,同时注意不要意外惩罚合法用户。例如,您的应用程序可以通过以下方式清除GET 和POST请求中提供的参数:

检查提供的字段(如电子邮件地址)是否与正则表达式匹配。

确保数字或字母数字字段不包含符号字符。

在不合适的地方拒绝(或去除)空格和换行符。

客户端验证(即在 JavaScript 中)对于在填写表单时为用户提供即时反馈很有用,但不能防御严重的黑客。大多数黑客尝试都是使用脚本执行的,而不是浏览器本身。

提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>