SQL注入是什么意思?我无法理解这个词。SQL注入可能会导致哪些问题?
什么是 SQL 注入?
SQL 注入最常发生在程序员通过使用用户提供的输入将字符串附加在一起(或插入)来构建 SQL 命令时。
例如,想象一下从一个虚构的 Web 应用程序中提取的一段易受攻击的用户身份验证(登录)伪代码。
username = getPostData( "username" );
password = getPostData( "password" );
sql = "select id, username from users'
+ ' where username='" + username + "' and password='" + password +"'";
result = executeQuery( sql );
if (result[ 0 ]) {
loginUser( result[ 0 ][ 'id' ] );
print "You are logged in as " + encodeAsHtml( result[ 0 ][ 'username' ] );
}
乍一看你可能认为这看起来很明智,但问题是它没有区分用户提供的数据和 SQL 代码;数据可以视为代码。这意味着恶意用户可以更改 SQL 语句的逻辑。
如果恶意用户可以更改 SQL 命令的逻辑以生成保证始终返回至少一行的答案,则他可以完全绕过登录保护。
例如,如果他输入了一个真实的用户名bob,但输入密码为:
' or 1=1 --
然后,这将授予他访问其他人帐户的权限。这是因为生成的 SQL 如下所示:
select id, username
from users
where username='bob' and password='' or 1=1 --'
请注意,逻辑表达式的1=1计算结果始终为真。另请注意,注入向量以两个连字符结尾,将行的其余部分标记为注释。因此 SQL 在逻辑上与
select id, username
from users
where (username='bob' and password='') or true
这在逻辑上与
select id, username
from users
where true
这在逻辑上与
select id, username
from users
因此,将返回数据库中的所有用户,并且他将作为列表中的第一个登录 - 通常是管理员。
SQL注入也可用于从数据库中读取所有数据。按如下方式输入用户名(SQL Server 语法)将列出用户定义的表名
' union select -1, name, from sysobjects where xtype = 'U' order by id --
因为这会产生
select id, username
from users
where username = ''
union
select -1, name
from sysobjects
where xtype = 'U'
order by id asc
因为我们注入的数据id是 -1 并且我们按 id 对数据进行排序,所以从数据库返回的第一行将是我们在sysobjects表中的选择。所以我们显示的“ username”现在将是数据库中第一个用户创建的表的名称。可以重复类似的技术来读取每个可访问表的每一行的每一列的所有数据。请注意,即使被攻击的功能根本不产生任何输出,这仍然可以完成!
编程语言数据库和 DBMS 的一些组合也允许查询堆叠。这是一种在末尾附加一个全新的 SQL 命令的技术。然后数据库将执行这两个查询。用户名:
'; delete from users --
生产
select id, username
from users
where username='';
delete from users
现在您的应用程序没有任何用户(并且需要 SQL 注入才能登录)。请参阅强制性 XKCD 漫画。
如果您对攻击者和漏洞测试人员常用的更多技术感兴趣,请参阅此SQLi 备忘单。
那么我该如何避免这种情况呢?
实际上,在许多常见的场景中,这很容易。Prepared statements将数据与代码分开,并且不允许将参数视为 SQL 代码。只需重新编码查询以使用准备好的语句并将各个参数绑定到占位符。
在伪代码中:
username = getPostData( "username" );
password = getPostData( "password" );
sql = "select id, username from users where username=? and password=?";
query = prepareStatement( sql );
query.setParameter( 0, username );
query.setParameter( 1, password );
result = executePreparedStatement( query );
一如既往,这不是故事的全部……
不要忘记深入防御并始终进行输入验证,因为您总是(应该)这样做。WHERE 子句需要额外注意,因为%可能不需要特殊字符。将用户数据作为参数传递给数据库函数时要特别小心,并注意它们如何被滥用。如果您有生成动态查询的存储过程,您可能需要在过程本身内进一步保护。
SQL 注入是一种使用有效的 SQL 命令来篡改、删除或将数据直接注入后端数据库的技术,通过验证代码输入到调用该数据库的 Web 应用程序中的弱点来直接将数据注入后端数据库。
它是OWASP 十大最常用的攻击路线之一,因为它很容易被利用。
它可用于破坏客户数据、信用卡数据、财务记录等的整个数据库,或获取此数据的副本。一般影响比较大!
好消息是通过输入验证很容易缓解 - 大多数框架都提供模块来执行此操作。