转自维基百科:
SQL注入是一种代码注入技术,用于攻击数据驱动的应用程序,在这种应用程序中,恶意的SQL语句被插入输入字段中执行(例如将数据库内容转储给攻击者)。[1] SQL注入必须利用应用程序软件中的安全漏洞,例如,当用户输入被错误地过滤为嵌入在SQL语句中的字符串文字 转义字符,或者用户输入没有强类型和意外执行时。SQL注入通常被称为网站的攻击媒介,但可以用来攻击任何类型的SQL数据库。
SQL注入攻击允许攻击者欺骗身份,篡改现有数据,导致拒绝问题,如排除交易或更改余额,允许完整披露系统上的所有数据,破坏数据或使其不可用,并成为数据库服务器
在2012年的一项研究中,观察到平均每个月的网络应用程序收到4次攻击活动,零售商受到的攻击是其他行业的两倍。
SQL注入(SQLI)被Open Web应用程序安全项目认为是2007年和2010年排名前10的Web应用程序漏洞之一。[5] 2013年,SQLI被评为OWASP前十名的头号攻击。[6] SQL注入有四个主要的子类:
- 经典的SQLI
- 盲或推理SQL注入
- 数据库管理系统 - 特定的SQLI
- 复杂的SQLI
这个分类代表了SQLI的状态,尊重它的发展到2010年 - 进一步的改进正在进行。[12]
技术实现[ 编辑]
错误地过滤了转义字符[ 编辑]
当用户输入不是针对转义字符进行筛选,然后传递给SQL语句时,会发生这种SQL注入形式。这导致了应用程序的最终用户对数据库执行的语句的潜在操纵。
以下代码行说明了此漏洞:
statement =“ ”+ userName +“ ”SELECT * FROM users WHERE name = '
';
此SQL代码旨在从其用户表中提取指定用户名的记录。但是,如果“userName”变量是由恶意用户以特定方式制作的,那么SQL语句可能比代码作者所期望的要多。例如,将“userName”变量设置为:
'或'1'='1
或者使用注释甚至阻塞查询的其余部分(有三种类型的SQL注释[13])。所有三条线在最后都有一个空格:
'OR'1'='1' - '或'1'='1'({ '或'1'='1'/ *
以父语言呈现下列SQL语句之一:
SELECT * FROM users WHERE name = '' OR'1 ' = '1' ;
SELECT * FROM users WHERE name = '' OR'1 ' = '1' - ';
如果在验证过程中使用此代码,则可以使用此示例强制从所有用户中选择每个数据字段(*),而不是从编码人员希望的一个特定用户名中选择,因为评估“1” =“1”始终为真(短路评估)。
下面的语句“username”的下列值将导致“用户”表中删除,以及从“用户信息”表中的所有数据的选择(本质上揭示了每个用户的信息),其使用API是允许多个语句:
一个';DROP TABLE users; SELECT * FROM userinfo WHERE 't' = 't
这个输入呈现如下并指定的最终SQL语句:
SELECT * FROM users WHERE name = 'a' ; DROP TABLE 用户; SELECT * FROM userinfo的 WHERE 'T' = 'T' ;
尽管大多数SQL服务器实现允许以这种方式一次调用多个语句,但是由于安全原因,一些SQL API(如PHP的mysql_query()
函数)不允许这样做。这可以防止攻击者注入完全独立的查询,但不会阻止他们修改查询。
类型处理不正确[ 编辑]
当用户提供的字段没有强类型或未检查类型约束时,就会发生这种SQL注入形式。当在SQL语句中使用数字字段时,可能会发生这种情况,但是程序员不进行检查来验证用户提供的输入是否为数字。例如:
声明:=“ ”+ a_variable +“;”
SELECT * FROM userinfo WHERE id =
从这个陈述中可以清楚地看到,作者希望变量是一个与“id”字段相关的数字。但是,如果它实际上是一个字符串,那么最终用户可以按照他们的选择操作语句,从而绕过了对转义字符的需要。例如,设置a_variable为
1; DROP TABLE用户
将从数据库中删除(删除)“users”表,因为SQL变成:
SELECT * FROM userinfo WHERE id = 1 ; DROP TABLE 用户;
盲目SQL注入[ 编辑]
当Web应用程序容易受到SQL注入的攻击,但注入的结果对攻击者不可见时,将使用Blind SQL Injection。带有此漏洞的页面可能不是显示数据的页面,而是根据注入到为该页面调用的合法SQL语句中的逻辑语句的结果显示不同。这种类型的攻击传统上被认为是时间密集型的,因为需要为恢复的每一位创建新的语句,并且根据其结构,攻击可能包含许多不成功的请求。最近的进步已经允许每个请求恢复多个位,没有不成功的请求,允许更一致和有效的提取。[14]一旦漏洞的位置和目标信息已经建立,有几种工具可以自动执行这些攻击。[15]
有条件的回应[ 编辑]
一种类型的盲注入强制数据库在普通应用程序屏幕上评估逻辑语句。作为示例,书评网站使用查询字符串来确定要显示的书评。所以URL http://books.example.com/showReview.php?ID=5
会导致服务器运行查询
SELECT * FROM bookreviews WHERE ID = 'Value(ID)' ;
从其中将填充评论页面,其中来自具有ID 5 的评论的数据存储在表格书籍视图中。查询完全发生在服务器上; 用户不知道数据库,表或字段的名称,用户也不知道查询字符串。用户只能看到上面的URL返回书评。甲黑客可以加载的URL 和,这可能导致在查询http://books.example.com/showReview.php?ID=5 OR 1=1
http://books.example.com/showReview.php?ID=5 AND 1=2
SELECT * FROM bookreviews WHERE ID = '5' 或 '1' = '1' ;
SELECT * FROM bookreviews WHERE ID = '5' 和 '1' = '2' ;
分别。如果使用“1 = 1”URL加载原始评论,并且从“1 = 2”URL返回空白或错误页面,并且尚未创建返回的页面以提醒用户输入无效,或者其他单词已被输入测试脚本捕获,该网站可能容易受到SQL注入攻击,因为在这两种情况下,查询可能已成功通过。黑客可能会继续使用这个查询字符串来显示在服务器上运行的MySQL的版本号,它将在运行MySQL 4的服务器上显示书评,否则将显示一个空白或错误页面。黑客可以继续使用查询字符串中的代码来从服务器收集更多信息,直到发现另一个攻击途径或达到他或她的目标。
[17]http://books.example.com/showReview.php?ID=5 AND substring(@@version, 1, INSTR(@@version, '.') - 1)=4
二阶SQL注入[ 编辑]
当提交的值包含存储而不是立即执行的恶意命令时,会发生二次SQL注入。在某些情况下,应用程序可能会正确编码SQL语句并将其存储为有效的SQL。然后,该应用程序的另一部分没有控制,以防止SQL注入可能会执行存储的SQL语句。这种攻击需要更多的关于如何使用提交的值的知识。自动化Web应用程序安全扫描程序不会轻易检测到这种类型的SQL注入,并且可能需要手动指示在哪里检查它正在尝试的证据。
缓解[ 编辑]
SQL注入是众所周知的攻击,可以通过简单的措施轻松防止。在2015 年Talktalk发生明显的SQL注入攻击后,英国广播公司(BBC)报道说,安全专家惊呆了,这样一家大公司会受到影响。[18]
参数化语句[ 编辑]
对于大多数开发平台,可以使用参数化的参数化语句(有时称为占位符或绑定变量),而不是在语句中嵌入用户输入。占位符只能存储给定类型的值,而不是任意的SQL片段。因此,SQL注入将被简单地视为一个奇怪的(可能是无效的)参数值。
在很多情况下,SQL语句是固定的,每个参数是一个标量,而不是一个表。用户输入被分配(绑定)到一个参数。[19]
在编码层面执行[ 编辑]
使用对象关系映射库避免了编写SQL代码的需要。实际上,ORM库将从面向对象的代码生成参数化的SQL语句。
转义[ 编辑]
一个简单的,虽然容易出错的防止注入的方法是转义SQL中具有特殊含义的字符。SQL DBMS手册解释了哪些字符具有特殊含义,可以创建需要翻译的字符的全面黑名单。例如,参数中每个出现的单引号('
)都必须被两个单引号(''
)替换,形成一个有效的SQL字符串文字。例如,在PHP中,通常mysqli_real_escape_string();
在发送SQL查询之前使用函数转义参数:
$ mysqli = new mysqli ('hostname' , 'db_username' , 'db_password' , 'db_name' );
$ query = sprintf (“SELECT * FROM`Users` WHERE UserName ='%s'AND Password ='%s'” ,
$ mysqli - > real_escape_string ($ username ),
$ mysqli - > real_escape_string ($ password ));
$ mysqli - > query ($ query );
此功能前添加反斜杠以下字符:x00
,
,
,,
'
,"
和x1a
。这个函数通常用于在向MySQL发送查询之前使数据安全。[20]
有在PHP许多数据库类型,如pg_escape_string()用于其它功能的PostgreSQL。该函数addslashes(string $str)
用于转义字符,特别用于在PHP中查询没有逃逸函数的数据库。它返回一个反斜杠的字符串需要在数据库查询被引用,等等。这些字符是单引号('),双引号(“),反斜线()和NUL(空字节)字符之前。[21]
常规地将转义字符串传递给SQL是很容易出错的,因为很容易忘记转义给定的字符串。创建透明图层来保护输入可以减少这种容易出错的情况,如果不能完全消除的话。[22]
模式检查[ 编辑]
整型,浮点型或布尔型,如果字符串参数的值是给定类型的有效表示形式,则可以检查它们。如果它们符合这种模式,则必须检查必须遵循一些严格模式(日期,UUID,仅字母数字等)的字符串。
数据库权限[ 编辑]
将Web应用程序使用的数据库登录权限限制为仅需要的权限可能有助于降低任何利用Web应用程序中的任何错误的SQL注入攻击的有效性。
例如,在Microsoft SQL Server上,可能会限制数据库登录在某些系统表上进行选择,这将限制尝试将JavaScript插入到数据库的所有文本列中的漏洞利用。
拒绝在sys上选择。系统对象到webdatabaselogon ; 拒绝在sys上选择。对象到webdatabaselogon ; 拒绝在sys上选择。表到webdatabaselogon ; 拒绝在sys上选择。对webdatabaselogon的看法; 拒绝在sys上选择。打包到webdatabaselogon ;