《OWASP代码审计》学习——SQL注入漏洞审计

一、注入的概念

注入攻击允许恶意用户向应用程序添加或注入内容和命令,以修改其行为。这些类型的攻击是常见且广泛的,黑客很容易测试网站是否易受攻击,攻击者也很容易利用这些攻击。如今,它们在尚未更新的遗留应用程序中非常常见。

二、SQL注入漏洞

最常见的注入漏洞是 SQL 注入,也很容易修复和防范。注入漏洞涵盖了 SQL、LDAP、Xpath、OS 命令、XML 解析器

1.漏洞导致的后果

敏感信息泄露

数据完整性受损(SQL注入可修改数据,添加新的数据或删除数据)

权限提升

进入后台

SQL命令不受不可信输入保护,SQL解析器无法区分代码和数据

字符串custQuery=从客户端选择客户名称、地址1,其中客户标识码=' " 请求.GetParameter("id")+" "

在开发人员不考虑安全性的遗留应用程序中,使用字符串连接来生成SQL语句是非常常见的。问题是这种编码技术不能告诉解析器语句的哪一部分是代码,哪一部分是数据,在用户输入被连接到SQL语句的情况下,攻击者可以通过向输入数据添加SQL代码来修改SQL语句。

2.防御方法

(1)HtmlEncode 所有用户输入。

(2)使用静态分析工具。静态的语言分析对.Net,Java,python 都比较准确。然而,当注入来自 JavaScript 和 CSS 时,静态分析可能会成为一个问题。

(3)参数化 SQL 查询。使用编程语言或框架提供的参数化语句的 SQL 方法,以便 SQL 解析器能够区分代码和数据。

(4)使用存储过程。存储过程通常有助于 SQL 解析器区分代码和数据。然而,存储过程可以用来构建动态的 SQL 语句,允许代码和数据混合在一起,导致它容易被注入。

(5)为开发人员提供安全编码最佳实践的培训。

三、盲注

通常,SQL 查询会返回呈现给用户的搜索结果。然而,在某些情况下,SQL 查询是在幕后进行的,这影响了页面的呈现方式。不过,攻击者仍然可以从各种用户界面元素的错误响应中收集信息。SQL 盲注攻击是一种向数据库询问真假问题并根据应用程序的响应来确定答案的攻击。

实际上,攻击者使用 SQL 查询来确定为有效的 SQL 返回哪些错误响应,以及为无效的SQL 返 回 哪 些 响 应 。 然 后 攻 击 者 就 可 以 探 查 真 实 的 数 据 。 例 如 , 审 计 名 为“user_password_table”的表是否存在。一旦他们获得了这些信息,他们就可以使用类似上述的攻击来恶意删除表,或者试图从表中返回信息(用户名“john”是否存在?盲目的 SQL注入也可以使用计时来代替错误消息。例如,如果无效的 SQL 需要 2 秒钟来响应,但是有效的 SQL 在 0.5 秒内返回,那么攻击者可以使用这些信息推断正确的拼接方式

四、参数化的SQL查询

参数化的 SQL 查询(有时称为预编译的语句)允许定义 SQL 查询字符串。以这样一种方式,客户端输入不会被视为 SQL 语法的一部分。例如:

string query = "select id,firstname,lastname from authors where forename = ?";
if(lastname!= NULL && lastname·length != 0)
{
query += "and surname ?";
}
query += ";";
​
PreparedStatement pstmt = connection.PreparedStatement pstmt(query);
pstmt.setString(1,firtsname);
​
if(lastname!=NULL && lastname.length !=0)
{
pstmt·setString(2,lastname);
​
}

这里没有使用lastname的值,不过仍然增加条件判断是否存在,然而,当SQL语句更大并且创建它设计更复杂的业务时,仍然存在风险。以下面的例子为例,该函数将根据名字或姓氏进行搜索

String query = "select id, firstname, lastname FROM authors",
​
if((firstname!=NULL&&firstname.length!=O)&&(lastname!=NULL&&lastname.length!=O))
{
query +=“WHERE forename =?AND surname =?”;
}
else if(firstname!=NULL&&firstname.length!=O)
{
query += “WHERE forename = ?";
}
else if(lastname!=NULL&&lastname.length!=O)
{
 query += "WHERE surname =?”;
}
​
query += “;";
​
PreparedStatement pstmt = connection.prepareStatement( query)

当给定名字或姓氏时,这种逻辑将是正确的,但是如果两者都没有给定,那么 SQL 状态将没有任何 WHERE 子句,并且将返回整个表。这不是 SQL 注入(攻击者除了没有传递两个值之外,没有做任何事情来导致这种情况),但是最终结果是相同的,尽管使用了参数化 查询,信息还是从数据库中泄露了。 因此,建议避免使用字符串连接来创建 SQL 查询字符串,即使是在使用参数化查询时。尤其是注意当连接涉及在 where 子句中构建任何项时。

五、使用灵活的参数化语句

功能需求通常需要基于用户输入灵活地执行 SQL 查询。

例如,如果最终用户为他们的交易搜索指定了一个时间跨度,那么应该使用这个时间跨度,或者他们可能希望基于姓氏或名字,或者基于两者进行查询。

在这种情况下,可以使用上面的安全字符串连接,但是从维护的角度来看,这可能会让未来的程序员误解安全连接和不安全版本(直接使用输入字符串值)之间的区别。

灵活的参数化语句的一个选项是使用“if”语句根据提供的输入值选择正确的查询,例如:

String query;
PreparedStatement pstmt;
if((firstname!=NULL && firstname.length!=O) && lastname!=NULL &&lastname.length !=O))
{
query = "Select id, firstname, lastname FRoM authors WHERE forename =? and surname=?"
pstmt = connection.prepareStatement( query );
pstmt.setString( 1, firstname );
pstmt.setString( 2, lastname );
}
else if (firstname !=NULL && firstname.length !=O){
query ="Select id, firstname, lastname FROM authors WHERE forename =?";
pstmt =connection.prepareStatement( query );
pstmt.setString( 7, firstname );
}
else if (lastname !=NULL && lastname.length !=O){
query = "Select id, firstname,lastname FROM authors WHeRE surname= ?",
pstmt =connection.prepareStatement( query );
pstmt.setString( 1, lastname);
}
else{
throw NameNotSpecifiedException(); }

六、PHP相关SQL注入

SQL注入攻击包括通过web应用程序中的客户端接口向后端数据库系统注入SQL查询部分。成功利用 SQL 注入的后果各不相同,从仅仅读取数据到修改数据或执行系统命令。PHP 中的 SQL 注入仍然是头号攻击方法,也是数据泄露的头号原因,例如:

在 PHP 中防止 SQL Injection 最常见的方法是使用诸如 addslashes()和 mysql_ real_escape_string()之类的函数,但是在某些情况下,这些函数也是会导致 SQL注入

(1)添加斜线

只有在用引号将查询字符串括起来的情况下,才可以避免使用 addslashes()进行 Sql注入。下面的例子仍然是脆弱的。

$id = addslashes($_GET['id'])
$query = 'select title from books where id = '.$id;

(2)mysql_real_escape_string()函数

mysql_real_escape_string()比 addslashes()稍微强大一点,因为它调用 mysql 的库函数 mysql_real_escape_string,该库函数在下列字符前添加反斜杠:\x00,\n,\r,','和\x1a。 与 addslashes()一样,mysql_real_escape_string()只有在查询字符串用引号括起来时才有效。

七、JAVA相关SQL注入

当 web 应用程序的输入在执行到后端数据库之前没有得到控制或清理时,就会发生SQL 注入。攻击者试图通过在其输入中传递 SQL 命令来利用此漏洞,因此会从数据库中创建不希望的响应,例如提供绕过网络应用程序中编程的授权和身份验证的信息。下列显示一个易受攻击的JAVA程序

HttpServeltRequest request = ...,
String userName = request.getParameter("name")
    Connection con = ...
    String query = "select * from users where name = '" + userName + "'";
con.execute(query)

输入参数“name”被传递给字符串查询,而没有任何适当的验证或确认。“SELECT* FROM users where name”等于字符串“name”的查询很容易被误用,以绕过不同于“name”的内容。

1..NET SQL注入

框架 1.0 和 2.0 可能比. NET 的更高版本更容易受到 SQL 注入的攻击。由于设计模式的正确实现和使用已经嵌入在 ASP.NET,如 MVC(也取决于版本),可以创建没有 SQL 注入的应用程序。但是,有时开发人员可能更喜欢直接在代码中使用 SQL 代码。

例子:开发人员创建了一个包含 3 个字段和提交按钮的网页,在“姓名”、“姓氏”和“身份证”字段中搜索员工,开发人员在代码中实现一个字符串连接的 SQL 语句或存储过程,

SqlDataAdapter thisCommand =new SqlDataAdapter("SELECT name, lastname FROM employees WHERE ei_id = "" + idNumber.Text + "*", thisConnection);

这段代码相当于下例中执行的 SQL 语句。

SqlDataAdapter thisCommand =new SqlDataAdapter("SearchEmployeeSP ‘" + idNumber.Text + ""”, thisConnection);

黑客然后可以通过网络界面“123’;DROP TABLE pubs --”插入以下标识:

select name,lastname from authors where ei_id = '123';drop table pubs --'

分号“;”为 sql 提供一个信号,表明它已经到达 SQL 语句的末尾,但是,黑客用这种恶意的 SQL 代码继续语句:DROP TABLE pubs

2.审计者操作

代码审计者需要确保 HQL 查询中使用的任何数据都使用 HQL 参数化查询,以便将其 用作数据而不是代码

3.参数集合

参数集合(如 SqlParameterCollection)提供类型审计和长度验证。如果使用参数集合,输入将被视为文字值,而 SQL Server 不会将其视为可执行代码,因此无法注入有效负载。使用参数集合可以强制执行类型和长度审计。超出该范围的值会触发例外。请确保您正确处理了异常。SQL 参数集合示例:Hibernate 查询语言(HQL)

using(SqlConnection conn = new SqlConnection(connectionString)){
DataSet dataObj= new DataSet();
SqlDataAdapter sqlAdapter = new SqlDataAdapter( "StoredProc",conn); sqIAdapter.SelectCommand.
CommandType =
CommandType.StoredProcedure;
sqlAdapter.SelectCommand.Parameters.Add("@usrld",SqlDbType.VarChar,15);
sqlAdapter.SelectCommand.Parameters["@usrld "].Value = UID.Text,;

Hibernate 通过对象/关系映射(ORM)方便了 Java 域对象的存储和检索。一个非常普遍的误解是 ORM 解决方案,像 hibernate 一样,是 SQL 注入证明。Hibernate 允许使用“原生 SQL”,并定义了一种专有的查询语言,叫做 HQL(Hibernate Query Language);前者倾向于 SQL 注入,后者倾向于 HQL 注入。

你可能感兴趣的:(渗透测试与安全攻防,代码审计,web安全,渗透测试,网络安全,sql注入,owasp,安全)