编码员征服安全。分享与学习--SQL注入

发表于2018年12月06日
作者:Jaap Karan Singh
案例研究

编码员征服安全。分享与学习--SQL注入

发表于2018年12月06日
作者:Jaap Karan Singh
查看资源
查看资源

简单地说,SQL(或结构化查询语言)是用于与关系型数据库沟通的语言;它是开发人员、数据库管理员和应用程序用来管理每天产生的大量数据的查询语言。

我们的数据正迅速成为世界上最有价值的商品之一......而当某样东西有价值时,坏人就会想把它弄到手,为自己谋利

攻击者正在使用SQL注入--最古老(自1998年以来!)和最棘手的数据漏洞之一--来窃取和改变全世界数百万数据库中的敏感信息。它是阴险的,如果我们要保持我们的数据安全,开发人员需要了解SQL注入(以及如何防御它)。

为此,我们将讨论SQL注入的三个关键方面。

  • 它是如何工作的
  • 为什么它如此危险
  • 如何抵御它

理解SQL注入

可以用一个词来理解SQL注入:背景。

在一个应用程序中,存在两个上下文:一个用于数据,另一个用于代码。代码上下文告诉计算机要执行什么,并将其与要处理的数据分开。

当攻击者输入的数据被SQL解释器错误地视为代码时,就会发生SQL注入。

一个例子是网站上的一个输入字段,攻击者在其中输入"''或1=1",并将其附加到一个SQL查询的结尾。当这个查询被执行时,它对数据库中的每一行都返回 "真"。这意味着被查询表的所有记录都将被返回。

SQL注入的影响可能是灾难性的。如果这发生在一个登录页面上,它可能会返回所有的用户记录,可能包括用户名和密码。如果一个简单的取出数据的查询是成功的,那么改变数据的查询也会。

让我们来看看一些有漏洞的代码,这样你就可以看到SQL注入漏洞的真面目了。

请看这个代码。

String query = "SELECT account balance FROM user_data WHERE user_name = "
+ request.getParameter("customerName");
try {
   Statement statement = connection.createStatement( ... );
   ResultSet results = statement.executeQuery( query );
}

这里的代码只是把来自客户端的参数信息附加到SQL查询的末尾,而没有进行验证。当这种情况发生时,攻击者可以在输入字段或URL参数中输入代码,并将其执行。

关键不是攻击者只能在每个SELECT查询中添加"''或1=1",而是攻击者可以操纵任何类型的SQL查询(INSERT、UPDATE、DELETE、DROP等),并用数据库支持的任何东西来扩展它。在公共领域有很好的资源和工具,可以显示出什么是可能的。

我们将很快了解如何纠正这个问题。首先,让我们了解可以造成多大的损害。

为什么SQL注入是如此危险的

这里只是三个由SQL注入引起的漏洞的例子。

  • 伊利诺伊州选举委员会网站因SQL注入漏洞而被攻破。攻击者窃取了20万美国公民的个人数据。发现的漏洞的性质意味着攻击者也可以改变数据,尽管他们没有这样做。
  • Hetzner是一家南非的网站托管公司,被入侵的客户记录达4万条。一个SQL注入漏洞导致他们数据库中的每条客户记录可能被盗。
  • 美国明尼苏达州的一家天主教金融服务提供商利用SQL注入技术被攻破。近13万名客户的账户信息,包括账户号码,被盗。

敏感数据可被用来接管账户、重设密码、偷钱或进行欺诈。

即使是不被认为是敏感或个人身份的信息也可能被用于其他攻击。地址信息或你的政府身份证号码的最后四位数可以被用来冒充你的公司,或重设你的密码。

当攻击成功时,客户会失去对公司的信任。从系统损坏或监管罚款中恢复可能需要花费数百万美元。

但对你来说,它不一定要以这种方式结束。

打败SQL注入

SQL注入可以通过清楚地标明你的应用程序的各个部分来打败,因此计算机知道某个部分是数据还是要执行的代码。这可以通过使用参数化查询来实现。

当SQL查询使用参数时,SQL解释器将只把参数作为数据使用。它不会把它作为代码执行。

例如,像"''OR 1=1 "这样的攻击将不起作用。数据库会搜索 "OR 1=1 "这个字符串,但在数据库中找不到它。它将简单地耸耸肩说:"对不起,我不能为你找到这个。"

Java中参数化查询的一个例子是这样的。

大多数开发框架提供了针对SQL注入的内置防御措施。

对象关系映射器(ORM),如.NET系列中的Entity Framework,将默认对查询进行参数化。这将在不需要你做任何努力的情况下解决SQL注入问题。

然而,你必须知道你的特定ORM是如何工作的。例如,Hibernate是Java世界中流行的ORM,如果使用不当,有可能受到SQL注入的影响。

参数化查询是第一个也是最好的防御措施,但也有其他的。存储过程也支持SQL参数,可以用来防止SQL注入。请记住,存储过程也必须正确构建,才能发挥作用。

// This should REALLY be validated too
String custname = request.getParameter("customerName");
// perform input validation to detect attacks
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";

PreparedStatement pstmt = connection.preparedStatement( query );
pstmt.setString(1, custname);
ResultSet results = pstmt.executeQuery( );

始终对你的输入进行验证和消毒。由于一些字符,如 "OR 1=1 "不会被你的应用程序的合法用户输入,所以没有必要允许它们。你可以向用户显示一个错误信息,或者在处理输入之前将它们从你的输入中剥离。

说到这里,不要仅仅依靠验证和消毒来保护你。聪明的人类已经找到了绕过它的方法。它们是很好的深度防御(DiD)策略,但参数化是覆盖所有基础的可靠方法。

另一个好的DiD策略是在数据库中使用 "最小权限 "和白名单输入。执行最小权限意味着你的应用程序在数据库中没有无限的权力。如果一个攻击者获得了访问权,他们所能造成的损害是有限的。

OWASP有一个很好的SQL注入小抄,展示了如何在几种语言和平台上处理这个漏洞......但如果你想做得更好,你现在就可以在我们的平台上用你喜欢的语言玩一个SQL注入挑战;这里有一些比较流行的语言,可以开始。

C#中的SQL注入

Node.js中的SQL注入

Python Django中的SQL注入

Java Spring中的SQL注入

旅程开始

你在理解SQL注入方面取得了一些重大进展,以及修复它所需的步骤。真棒!

我们已经讨论过SQL注入是如何发生的;通常是攻击者利用输入控制你的数据库查询,达到他们自己的邪恶目的。

我们也看到了利用SQL注入漏洞所造成的损失。账户可能被破坏,数百万美元的损失......这是一个噩梦,而且是一个昂贵的噩梦。

我们已经看到如何防止SQL注入。

  • 参数化查询
  • 使用对象关系映射器和存储过程
  • 验证和白名单用户输入

现在,就看你了。练习是不断学习和掌握的最好方法,所以为什么不看看我们的 学习资源的学习资源,然后试试我们的 免费演示的平台?你将会在成为一个Secure Code Warrior 。

查看资源
查看资源

作者

Jaap Karan Singh

想要更多吗?

在博客上深入了解我们最新的安全编码见解。

我们广泛的资源库旨在增强人类对安全编码技术提升的方法。

查看博客
想要更多吗?

获取关于开发者驱动的安全的最新研究

我们广泛的资源库充满了有用的资源,从白皮书到网络研讨会,让你开始使用开发者驱动的安全编码。现在就去探索它。

资源中心

编码员征服安全。分享与学习--SQL注入

发表于2018年12月06日
作者:Jaap Karan Singh

简单地说,SQL(或结构化查询语言)是用于与关系型数据库沟通的语言;它是开发人员、数据库管理员和应用程序用来管理每天产生的大量数据的查询语言。

我们的数据正迅速成为世界上最有价值的商品之一......而当某样东西有价值时,坏人就会想把它弄到手,为自己谋利

攻击者正在使用SQL注入--最古老(自1998年以来!)和最棘手的数据漏洞之一--来窃取和改变全世界数百万数据库中的敏感信息。它是阴险的,如果我们要保持我们的数据安全,开发人员需要了解SQL注入(以及如何防御它)。

为此,我们将讨论SQL注入的三个关键方面。

  • 它是如何工作的
  • 为什么它如此危险
  • 如何抵御它

理解SQL注入

可以用一个词来理解SQL注入:背景。

在一个应用程序中,存在两个上下文:一个用于数据,另一个用于代码。代码上下文告诉计算机要执行什么,并将其与要处理的数据分开。

当攻击者输入的数据被SQL解释器错误地视为代码时,就会发生SQL注入。

一个例子是网站上的一个输入字段,攻击者在其中输入"''或1=1",并将其附加到一个SQL查询的结尾。当这个查询被执行时,它对数据库中的每一行都返回 "真"。这意味着被查询表的所有记录都将被返回。

SQL注入的影响可能是灾难性的。如果这发生在一个登录页面上,它可能会返回所有的用户记录,可能包括用户名和密码。如果一个简单的取出数据的查询是成功的,那么改变数据的查询也会。

让我们来看看一些有漏洞的代码,这样你就可以看到SQL注入漏洞的真面目了。

请看这个代码。

String query = "SELECT account balance FROM user_data WHERE user_name = "
+ request.getParameter("customerName");
try {
   Statement statement = connection.createStatement( ... );
   ResultSet results = statement.executeQuery( query );
}

这里的代码只是把来自客户端的参数信息附加到SQL查询的末尾,而没有进行验证。当这种情况发生时,攻击者可以在输入字段或URL参数中输入代码,并将其执行。

关键不是攻击者只能在每个SELECT查询中添加"''或1=1",而是攻击者可以操纵任何类型的SQL查询(INSERT、UPDATE、DELETE、DROP等),并用数据库支持的任何东西来扩展它。在公共领域有很好的资源和工具,可以显示出什么是可能的。

我们将很快了解如何纠正这个问题。首先,让我们了解可以造成多大的损害。

为什么SQL注入是如此危险的

这里只是三个由SQL注入引起的漏洞的例子。

  • 伊利诺伊州选举委员会网站因SQL注入漏洞而被攻破。攻击者窃取了20万美国公民的个人数据。发现的漏洞的性质意味着攻击者也可以改变数据,尽管他们没有这样做。
  • Hetzner是一家南非的网站托管公司,被入侵的客户记录达4万条。一个SQL注入漏洞导致他们数据库中的每条客户记录可能被盗。
  • 美国明尼苏达州的一家天主教金融服务提供商利用SQL注入技术被攻破。近13万名客户的账户信息,包括账户号码,被盗。

敏感数据可被用来接管账户、重设密码、偷钱或进行欺诈。

即使是不被认为是敏感或个人身份的信息也可能被用于其他攻击。地址信息或你的政府身份证号码的最后四位数可以被用来冒充你的公司,或重设你的密码。

当攻击成功时,客户会失去对公司的信任。从系统损坏或监管罚款中恢复可能需要花费数百万美元。

但对你来说,它不一定要以这种方式结束。

打败SQL注入

SQL注入可以通过清楚地标明你的应用程序的各个部分来打败,因此计算机知道某个部分是数据还是要执行的代码。这可以通过使用参数化查询来实现。

当SQL查询使用参数时,SQL解释器将只把参数作为数据使用。它不会把它作为代码执行。

例如,像"''OR 1=1 "这样的攻击将不起作用。数据库会搜索 "OR 1=1 "这个字符串,但在数据库中找不到它。它将简单地耸耸肩说:"对不起,我不能为你找到这个。"

Java中参数化查询的一个例子是这样的。

大多数开发框架提供了针对SQL注入的内置防御措施。

对象关系映射器(ORM),如.NET系列中的Entity Framework,将默认对查询进行参数化。这将在不需要你做任何努力的情况下解决SQL注入问题。

然而,你必须知道你的特定ORM是如何工作的。例如,Hibernate是Java世界中流行的ORM,如果使用不当,有可能受到SQL注入的影响。

参数化查询是第一个也是最好的防御措施,但也有其他的。存储过程也支持SQL参数,可以用来防止SQL注入。请记住,存储过程也必须正确构建,才能发挥作用。

// This should REALLY be validated too
String custname = request.getParameter("customerName");
// perform input validation to detect attacks
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";

PreparedStatement pstmt = connection.preparedStatement( query );
pstmt.setString(1, custname);
ResultSet results = pstmt.executeQuery( );

始终对你的输入进行验证和消毒。由于一些字符,如 "OR 1=1 "不会被你的应用程序的合法用户输入,所以没有必要允许它们。你可以向用户显示一个错误信息,或者在处理输入之前将它们从你的输入中剥离。

说到这里,不要仅仅依靠验证和消毒来保护你。聪明的人类已经找到了绕过它的方法。它们是很好的深度防御(DiD)策略,但参数化是覆盖所有基础的可靠方法。

另一个好的DiD策略是在数据库中使用 "最小权限 "和白名单输入。执行最小权限意味着你的应用程序在数据库中没有无限的权力。如果一个攻击者获得了访问权,他们所能造成的损害是有限的。

OWASP有一个很好的SQL注入小抄,展示了如何在几种语言和平台上处理这个漏洞......但如果你想做得更好,你现在就可以在我们的平台上用你喜欢的语言玩一个SQL注入挑战;这里有一些比较流行的语言,可以开始。

C#中的SQL注入

Node.js中的SQL注入

Python Django中的SQL注入

Java Spring中的SQL注入

旅程开始

你在理解SQL注入方面取得了一些重大进展,以及修复它所需的步骤。真棒!

我们已经讨论过SQL注入是如何发生的;通常是攻击者利用输入控制你的数据库查询,达到他们自己的邪恶目的。

我们也看到了利用SQL注入漏洞所造成的损失。账户可能被破坏,数百万美元的损失......这是一个噩梦,而且是一个昂贵的噩梦。

我们已经看到如何防止SQL注入。

  • 参数化查询
  • 使用对象关系映射器和存储过程
  • 验证和白名单用户输入

现在,就看你了。练习是不断学习和掌握的最好方法,所以为什么不看看我们的 学习资源的学习资源,然后试试我们的 免费演示的平台?你将会在成为一个Secure Code Warrior 。

我们希望得到您的许可,向您发送有关我们产品和/或相关安全编码主题的信息。我们将始终以最谨慎的态度对待您的个人资料,绝不会将其出售给其他公司用于营销目的。

要提交表格,请启用 "分析 "cookies。完成后,请随时再次禁用它们。