SQL注⼊漏洞----1、原理篇
⽂章⽬录
⼀、SQL注⼊原理
SQL注⼊漏洞主要形成的原因是在数据交互中,前端的数据传⼊到后台处理时,没有做严格的判断,导致其传⼊的"数据"拼接到SQL语句中后,被当作SQL语句的⼀部分执⾏,从⽽导致数据库受损(被脱库、被删除、甚⾄整个服务器权限沦陷)。
⽰例如下:
//如下是利⽤⼀段登录验证时查询数据库的代码login.php:
//连接到数据库
$conn=mysql_connect("localhost","username","password");
//使⽤输⼊动态创建 SQL 语句
$query="SELECT userid FROM Users WHERE user = '$_GET["user"]' ".
"AND password = '$_GET["password"]'";
//对数据库执⾏查询
$result=mysql_query($query);
//检查从数据库返回了多少条记录
$rowcount=mysql_num_rows($result);
//如果返回⼀条记录,那么验证必定是有效的,因此将⽤户导航到 admin 页⾯
if($rowcount!=0){header("Location: admin.php");
//如果没有返回记录,那么验证必定是⽆效的
else{die('Incorrect username or password, please try again.')}
在输⼊⽤户名user和密码passwd时,login.php会动态的创建⼀条SQL语句在数据库中进⾏查询。
SELECT userid FROM Users WHERE user='user'AND password='passwd';
正常情况下,这个流程是没有问题的,数据库中存在user和passwd,页⾯登陆成功;不存在时,返回Incorrect username or password, please try again。但是在这个过程中,代码执⾏的结果始终为0或1。如果我们此时利⽤数据去破坏0或1这个查询逻辑,那么就会造成SQL注⼊。如下对password参数进⾏:
SELECT userid FROM Users WHERE user='user'AND password='passwd'or'1'='1';
这个sql查询语句由于(or 1=1),导致恒为1,所以此时⽆论⽤户名输⼊什么,这个查询语句都会返回1,导致可以直接登录。
⼆、Web应⽤的⼯作原理
数据库驱动的Web应⽤通常都包含⼀个后台数据库和很多Web页⾯,这些页⾯中包含了使⽤某种编程语⾔编写的服务器端脚本,⽽这些脚本则能够根据 Web 页⾯与⽤户的交互从数据库中提取特定的信息。
数据库驱动的 Web 应⽤通常包含三层:表⽰层(Web 浏览器或呈现引擎)、逻辑层(如 C#、ASP、.NET、PHP、JSP 等编程语⾔)和存储层(如 Microsoft SQL Server、MySQL、Oracle 等数据库)。Web 浏览器(表⽰层,如 Internet Explorer、Safari、Firefox等)向中间层(逻辑层)发送请求,中间层通过查询、更新数据库(存储层)来响应该请求。
1、三层web架构
表⽰层:是应⽤的最⾼层,它显⽰服务相关的信息,并通过将结果输出到浏览器/客户端层和⽹络上的所有其他层来与应⽤架构的其他层进⾏通信。
逻辑层:是从表⽰层剥离出来的,作为单独的⼀层,它通过执⾏细节处理来控制应⽤的功能。
数据层:包括数据库服务器,⽤于对信息进⾏存储和检索。数据层保证数据独⽴于应⽤服务器或业务逻辑。将数据作为单独的⼀层还可以提⾼程序的可扩展性和性能。
下图中,Web 浏览器(表⽰层)向中间层(逻辑层)发送请求,中间层通过查询、更新数据库(存储层)响应该请求。三层架构中⼀条最基本的规则是:表⽰层不应直接与数据层通信。在三层架构中,所有通信都必须经过中间层。从概念上看,三层架构是⼀种线性关系。
1、⽤户激活Web浏览器并连接到URL;
2、位于逻辑层的Web服务器从⽂件系统中加载脚本并将其传递给脚本引擎,脚本引擎负责解析并执⾏脚本;
3、脚本使⽤数据库连接程序打开存储层连接并对数据库执⾏SQL语句;
4、数据库将数据返回给数据库连接程序,后者将其传递给逻辑层的脚本引擎;
5、逻辑层再将Web页⾯以HTML格式返回给表⽰层的⽤户的Web 浏览器之前,执⾏相关的应⽤或业务逻辑规则;
6、⽤户的Web浏览器呈现 HTML并借助代码的图形化表⽰展现给⽤户。
所有操作都将在数秒内完成,并且对⽤户是透明的。
2、N层应⽤程序开发范式
N层架构中的应⽤服务器负责将 API(应⽤编程接⼝)提供给业务逻辑和业务流程以供程序使⽤。可以根据需要引⼊其他的 Web 服务器。此外,应⽤服务器可以与多个数据源通信,包括数据库、⼤型机以及其他旧式系统。
下图描绘了⼀种简单的 4 层架构。Web浏览器(表⽰层)向中间层(逻辑层)发送请求,后者依次调⽤由位于应⽤层的应⽤服务器提供的 API,应⽤层通过查询、更新数据库(存储层)来响应该请求。
1、⽤户激活Web浏览器并连接到URL;
2、位于逻辑层的Web服务器从⽂件系统中加载脚本并将其传递给脚本引擎,脚本引擎负责解析并执⾏脚本;
3、脚本调⽤由位于应⽤层的应⽤服务器提供的API;
4、应⽤服务器使⽤数据库连接程序打开存储层连接并对数据库执⾏SQL语句;
5、数据库将数据返回给数据库连接程序;
6、应⽤服务器在将数据返回给Web服务器之前先执⾏相关的应⽤或业务逻辑规则;
7、Web服务器在将数据以HTML格式返回给表⽰层的⽤户的Web浏览器之前先执⾏最后的有关逻辑。
8、⽤户的Web浏览器呈现HTML并借助代码的图形化表⽰展现给⽤户。
所有操作都将在数秒内完成,并且对⽤户是透明的。
分层架构的基本思想是将应⽤分解成多个逻辑块(或层),其中每⼀层都分配有通⽤或特定的⾓⾊。各个层可以部署在不同的机器上,或者部署于同⼀台机器上,但实际在概念上是彼此分离的。使⽤的层越多,每⼀层的⾓⾊就越具体。将应⽤的职责分成多个层能使应⽤更易于扩展,可以更好地为开发⼈员分配开发任务,提⾼应⽤的可读性和组件的可复⽤性。
三、SQL注⼊的产⽣原因
SQL是访问Microsoft SQL Server、Oracle、MySQL、Sybase 和 Informix(以及其他)数据库服务器的标准语⾔。⼤多数 Web 应⽤都需要与数据库进⾏交互,并且⼤多数Web应⽤编程语⾔(如ASP、C#、.NET、Java和PHP)均提供了可编程的⽅法来与数据库连接并进⾏交互。如果Web应⽤开发⼈
员⽆法保证在将从Web表单、cookie及输⼊参数等收到的值传递给SQL查询(该查询在数据库服务器上执⾏)之前已经对其进⾏过验证,那么通常会出现SQL注⼊漏洞。如果攻击者能够控制发送给SQL查询的输⼊,并且能够操纵该输⼊将其解析为代码⽽⾮数据,那么攻击者就很有可能在后台数据库执⾏该代码。
⽰例如下:
//在 PHP 中动态构造 SQL 语句的字符串
$query="SELECT * FROM table WHERE field = '$_GET["input"]'";
//在.NET 中动态构造 SQL 语句的字符串
query ="SELECT * FROM table WHERE field = '"+
如果在将输⼊传递给动态创建的语句之前,未对代码进⾏验证或者编码,那么攻击者会将sql语句作为输⼊提供给应⽤并将sql语句传递给数据库加以执⾏。
经过上述代码构造如下SQL语句:
SELECT*FROM TABLE WHERE FIELD ='input'
此过程中可能产⽣如下问题导致SQL注⼊问题:
1、转义字符处理不当
SQL 数据库将单引号字符(’)解析成代码与数据间的分界线:单引号外⾯的内容均是需要运⾏的代码,⽽⽤单引号引起来的内容均是数据。因此,只需在 URL 或 Web 页⾯(或应⽤)的字段中输⼊⼀个单引号,就能快速识别出 Web 站点是否会受到 SQL 注⼊攻击。下⾯是⼀个应⽤的源代码,它将⽤户输⼊直接传递给动态创建的 SQL 语句:
//构造动态 SQL 语句
$SQL="SELECT * FROM table WHERE field = '$_GET["input"]'";
//执⾏ SQL 语句
$result = mysql_query($SQL);
//检查从数据库返回了多少条记录
$rowcount= mysql_num_rows($result);
//迭代返回的记录集
$row=1;
while($db_field = mysql_fetch_assoc($result)) {
if($row<= $rowcount){
print $db_field[$row]."<BR>";
$row++;
}
}
如果将⼀个单引号字符作为该程序的输⼊,那么可能会出现下列错误中的⼀种。具体出现
何种错误取决于很多环境因素,⽐如编程语⾔、使⽤的数据库以及采⽤的保护和防御技术:
Warning: mysql_fetch_assoc(): supplied argument is not a valid MySQLphp远程连接mysql数据库
result resource
我们还可能会收到下列错误,通过这些错误我们可以来构造SQL语句:
You have an error in your SQL syntax; check the manual that corresponds
to your MySQL server version for the right syntax to use near ''VALUE''
出现该错误是因为单引号字符被解析成了字符串分隔符。运⾏时执⾏的 SQL 查询在语法上存在多个字符串分隔符,所以数据库抛出异常。在 SQL 注⼊攻击中,攻击者使⽤该字符 “转义”开发⼈员的查询以便构造⾃⼰的查询并加以执⾏。
单引号字符并不是唯⼀的转义字符。⽐如在 Oracle 中,空格()、双竖线(||)、逗号(,)、点
号(.)、(*/)以及双引号字符(")均具有特殊含义。例如:
1、管道字符[|]⽤于为⼀个值追加⼀个函数,函数将被执⾏,函数的结果将转换并与前⾯的值连接。
www.victim/id=1|| _host_address(local)--
2、星号后跟⼀个正斜线,⽤于结束注释或 Oracle 中的优化提⽰
www.victim/hint=*/ from dual—
⽆论是进⾏攻击还是防御,熟悉数据库的各种特性都是⾮常重要的。例如在 SAP MAX DB
3、(SAP DB)中,开始定界符是由⼀个⼩于符号和⼀个感叹号组成的:
www.victim/id=1 union select operating system from sysinfo.
version--<!
2、类型处理不当
如下脚本接收⼀个数字参数($userid)并显⽰该⽤户的信息。假定该查询的参数是整数,因此写的时候没有加单引号:
//构造动态 SQL 语句
$SQL="SELECT * FROM table WHERE field = $_GET["userid"]"
//执⾏ SQL 语句
$result = mysql_query($SQL);
//检查从数据库返回了多少条记录
$rowcount= mysql_num_rows($result);
//迭代返回的记录集
$row=1;
while($db_field = mysql_fetch_assoc($result)) {
if($row<= $rowcount) {
print $db_field[$row]."<BR>";
$row++;
}
}
MySQL 提供了⼀个名为 LOAD_FILE 的函数,它能够读取⽂件并将⽂件内容作为字符串返回。要使⽤该函数,必须保证读取的⽂件位于数据库服务器主机上,然后将⽂件的完整路径作为输⼊参数传递给函数。调⽤该函数的⽤户还必须拥有FILE权限。如果将下列语句作为输⼊,那么攻击者便会读取/etc/passwd ⽂件中的内容,该⽂件中包含系统⽤户的属性和⽤户名:
1UNION ALL SELECT LOAD_FILE('/etc/passwd')--
MySQL 还包含⼀个内置命令,可使⽤该命令来创建系统⽂件并进⾏写操作。还可使⽤下列命令向 Web 根⽬录写⼊⼀个Webshell以便安装⼀个可远程交互访问的Webshell:
1UNION SELECT"<? system($_REQUEST['cmd']); ?>"INTO OUTFILE
"/var/www/html/victim/cmd.php" –
要想执⾏ LOAD_FILE 和 SELECT INTO OUTFILE 命令,易受攻击应⽤所使⽤的 MySQL⽤户就必须拥有FILE权限(FILE 是⼀种管理员权限)。例如,root ⽤户在默认情况下拥有该权限,攻击者的输⼊直接被解析成了SQL语法,所以攻击者没必要使⽤单引号字符来转义查询。
3、查询语句组装不当
有时需要使⽤动态SQL语句对某些复杂的应⽤进⾏编码,因为在程序开发阶段可能还不知道要查询的表或字段(或者还不存在)。⽐如与⼤型数据库交互的应⽤,这些数据库在定期创建的表中存储数据。
下⾯是⼀个应⽤的源代码,它将⽤户输⼊直接传递给动态创建的 SQL 语句,脚本使⽤应⽤产⽣的值作为输⼊,输⼊是⼀个表名加三个列名,之后显⽰员⼯信息。该程序允许⽤户选择他希望返回的数据。例如,⽤户可以选择⼀个员⼯并查看其⼯作明细、⽇⼯资或当⽉的效能图。由于应⽤已经产⽣了输⼊,因⽽开发⼈员会信任该数据。不过,该数据仍可被⽤户控制,因为它是通过 GET 请求提交的。攻击者可使⽤⾃⼰的表和字段数据来替换应⽤产⽣的值。
//构造动态 SQL 语句
$SQL="SELECT". $_GET["column1"].",". $_GET["column2"].",".
$_GET["column3"]."FROM". $_GET["table"];
//执⾏ SQL 语句
$result = mysql_query($SQL);
//检查从数据库返回了多少条记录
$rowcount= mysql_num_rows($result);
//迭代返回的记录集
$row=1;
while($db_field = mysql_fetch_assoc($result)) {
if($row<= $rowcount) {
print $db_field[$row]."<BR>";
$row++;
}
}
如果攻击者操纵 HTTP 请求并使⽤值 users 替换表名,使⽤ user、password 和 Super_priv 字段替换应⽤产⽣的列名,那么他便可以显⽰系统中数据库⽤户的⽤户名和⼝令。下⾯是他在使⽤
应⽤时构造的 URL:
www.victim/user_details.php?table=users&column1=user&column2
=password&column3=Super_priv
如果注⼊成功,那么将会返回user、password、Super_priv数据⽽⾮时间安排数据。
4、错误处理不当
错误处理不当最常见的问题是将详细的内部错误消息(如数据库转储、错误代码等)显⽰给⽤户或攻击者,这些错误消息会泄露不应该显⽰的实现细节,⽽这些细节会为攻击者提供与⽹站潜在缺陷相关的重要线索。
例如,攻击者可利⽤详细的数据库错误消息来提取信息,从⽽知道如何修改或构造注⼊以避开开发⼈员的查询,并得知如何操纵数据库以便取出附加数据的信息,或者在某些情况下转储数据库(Microsoft SQL Server)中所有数据的信息。
下⾯是⼀个使⽤C#语⾔编写的ASP.NET应⽤⽰例,它使⽤Microsoft SQL Server数据库服务器作为后台(该数据库提供了⾮常详细的错误消息)。当⽤户从下拉列表中选择⼀个⽤户标识符时,脚本会动态产⽣并执⾏⼀条 SQL 语句:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论