web安全/渗透测试--21--SQL注入(上)

版权声明:本文为博主原创文章,转载本站文章请注明作者和出处,请勿用于任何商业用途。 https://blog.csdn.net/wutianxu123/article/details/82718718

1、漏洞描述

所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。造成SQL注入漏洞原因有两个:一个是没有对输入的数据进行过滤(过滤输入),还有一个是没有对发送到数据库的数据进行转义(转义输出)。

2、检测条件

1、被测网站具有交互功能模块,涉及到参数提交等等
2、例如待测目标URL,假设为http://www.exmaple.com/page.xxx
3、待测目标存在参数输入,假设为name=value

3、检测方法

1、通过web漏洞扫描工具进行对网站爬虫后得到的所有链接进行检测,或者手工判断是否存在注入点,一旦确认存在漏洞,可利用自动化工具sqlmap去尝试注入

几种常见的判断方法:

1、数字型。测试方法:

http://host/test.php?id=100 and 1=1        //返回成功
http://host/test.php?id=100 and 1=2        //返回失败

2、字符型。测试方法:

http://host/test.php?name=rainman ‘ and1’=‘1        //返回成功 
http://host/test.php?name=rainman ‘ and1’=‘2        //返回失败
http://host/test.php?name=rainman ‘ and1’=‘2 ))     //使用括号进行语句闭合

3、搜索型。搜索型注入:简单的判断搜索型注入漏洞存在不存在的办法是:

1)先搜索('),如果出错,说明90%存在这个漏洞。
2)然后搜索(%),如果正常返回,说明95%有洞了。 
3)然后再搜索一个关键字,比如(2006)吧,正常返回所有2006相关的信息。
4)再搜索(2006%'and 1=1 and '%'=')和(2006%'and 1=2 and '%'=')。

4、绕过验证(常见的为管理登陆)也称万能密码

(1) 用户名输入: ‘or 1=1 or’  密码:任意
(2) Admin’ -- (或’or 1=1 or’ --)(admin or 1=1 --) (MSSQL)(直接输入用户名,不进行密码验证)
(3) 用户名输入:admin   密码输入:’ or1’=‘1  也可以
(4) 用户名输入:admin' or 'a'='a    密码输入:任意
(5) 用户名输入:’ or 1=1 --
(6) 用户名输入:admin’ or 1=1 --  密码输入:任意
(7) 用户名输入:1'or'1'='1'or'1'='1   密码输入:任意

5、不同的SQL服务器连结字符串的语法不同,比如MS SQL Server使用符号+来连结字符串,而Oracle使用符号||来连结:

http://host/test.jsp?ProdName=Book’       //返回错误
http://host/test.jsp?ProdName=B’+’ook     //返回正常
http://host/test.jsp?ProdName=B’||’ook    //返回正常说明有SQL注入
如果应用程序已经过滤了’和+等特殊字符,我们仍然可以在输入时过把字符转换成URL编码(即字符ASCII码的16进制)来绕过检查。

2、注释:大多数数据库系统使用“/*”做为注释,Oracle使用“--”做为注释。

3、数据库指纹:

指纹一:观察应用返回的错误信息判断数据库类型。
指纹二:字符串拼接特点
Mysql:’test’ ‘ing’
SQLServer:’test’ + ‘ing’
Oracle:’test’ || ‘ing’
PostgreSQL:’test’ || ‘ing’

4、漏洞利用技术

1、联合查询SQL注入技术:UNION联合多个SQL语句。
2、SQL中逻辑判断使用技术:应用在盲注中,例如判断用户名第一个字符是不是“a”。
3、基于错误的注入技术:在SQL注入语句中加入执行函数语句。
4、外连攻击技术:在SQL注入语句中加入外连其他服务器的执行函数,使得连接到其他服务器。
5、延时攻击:注入语句中加入睡眠时间,以此根据响应时间判断猜测正确与否。

5、注释块(’/* sql */’)包含一个感叹号标记时(‘/*! sql */’),MySQL可以对其进行解析,而其他数据库系统将其作为普通注释块。

6、SQL盲注

字符串长度:length(str)
基于时间的盲注:sleep()
不用引号实现字符串:CHR(104) || CHR(101) || CHR(108) || CHR(108)    //返回字符串的ASCII码值
和以上相反:ASCII(‘r’) || ASCII(’o’) || ASCII(‘t’)

7、非关系型数据库(NoSQL):NoSQL注入攻击可以在过程语言中执行,而不是在声明式的SQL语言,所以潜在的影响要大于传统的SQL注入。

4、修复方案

推荐使用参数化查询方式进行SQL查询,可以有效防御SQL注入问题。

建议在代码中对数字类型的参数先进行数字类型变换,然后再代入到SQL查询语句中,这样任何注入行为都不能成功。并且考虑过滤一些参数,比如get参数和post参数中对于SQL语言查询的部分。

所以防范的时候需要对用户的输入进行检查。特别式一些特殊字符,比如单引号,双引号,分号,逗号,冒号,连接号等进行转换或者过滤。

需要过滤的特殊字符及字符串有:

net user
xp_cmdshell
add
exec master.dbo.xp_cmdshell
net localgroup administrators
select
count
Asc
char
mid
'
:
"
insert
delete from
drop table
update
truncate
from
%

常见的几种web语言修复方案如下:

1、如果网站使用的语言为asp或者aspx,则可通过如下几种方式进行修复:

Replace过滤字符:

解决方法:查找login.asp下的
username=request.Form("name")
pass=request.Form("pass")

修改为:
username=Replace(request.Form("name"), "'", "''")
pass=Replace(request.Form("pass"), "'", "''")

语法是屏蔽'和''字符来达到效果。

在conn.asp 内加入:

注:(前提:登陆页面有)
把以下代码保存为safe.asp

<%
    Dim Query_Badword,Form_Badword,i,Err_Message,Err_Web,name
    Err_Message = 3
    Err_Web = "safe.htm"
    //出错时转向的页面

    Query_Badword="‘|and|select|update|chr|delete|%20from|;|insert|mid|master.|set|chr(37)|="
    //在这部份定义get非法参数,使用"|"号间隔
    Form_Badword="‘|(|)|;|="
    //在这部份定义post非法参数,使用"|"号间隔
    On Error Resume Next
    if request.QueryString<>"" then
        Chk_badword=split(Query_Badword,"|")
        FOR EACH Query_Name IN Request.QueryString
            for i=0 to ubound(Chk_badword)
                If Instr(LCase(request.QueryString(Query_Name)),Chk_badword(i))<>0 Then
                    Select Case Err_Message
                        Case "1"
                        Response.Write " 
                        Case "2"
                        Response.Write " 
                        Case "3"
                        Response.Write " 
                    End Select
                    Response.End
                End If
            NEXT
        NEXT
    End if

    if request.form<>"" then
        Chk_badword=split(Form_Badword,"|")
        FOR EACH name IN Request.Form
            for i=0 to ubound(Chk_badword)
                If Instr(LCase(request.form(name)),Chk_badword(i))<>0 Then
                    Select Case Err_Message
                        Case "1"
                        Response.Write " 
                        Case "2"
                        Response.Write " 
                        Case "3"
                        Response.Write " 
                    End Select
                    Response.End
                End If
            NEXT
        NEXT
    end if
%>

ASP一般编程上可参考以下代码编程思路,过滤GET/POST请求模块代码:

dim SQL_injdata 
SQL_injdata = "'|and|exec|insert|select|delete|update|count|*|% |chr|mid|master|truncate|char|declare" 
SQL_inj = split(SQL_Injdata,"|") 

If Request.QueryString<>"" Then 
    For Each SQL_Get In Request.QueryString 
        For SQL_Data=0 To Ubound(SQL_inj) 
            if instr(Request.QueryString(SQL_Get),SQL_Inj(SQL_DATA))>0 Then 
                Response.Write "参数中包含非法字符" 
                Response.end 
            end if 
        next 
    Next
end if

2、对于PHP语言编写的网站,大都是和mysql数据库结合的,可通过如下几种方法结合起来防范SQL注入的漏洞:

修改php中默认配置文件php.ini中的配置,来降低sql注入的风险:

参考路径:/usr/local/apache2/conf/php.ini,不同中间件可能位置不一样

修改如下几项:
safe_mode = on             //开启安全模式
magic_quotes_gpc = On      //开启过滤函数
display_errors = Off       //禁止错误信息提示

注:把magic_quotes_gpc选项打开,在这种情况下所有的客户端GET和POST的数据都会自动进行addslashes处理,
所以此时对字符串值的SQL注入是不可行的,但要防止对数字值的SQL注入,如用intval()等函数进行处理。但如果你
编写的是通用软件,则需要读取服务器的magic_quotes_gpc后进行相应处理

在GET提交的数据中进行过滤select、update、delete、insert等其他语句。使用正则就构建如下函数:

<?php          
    function inject_check($sql_str)     
    {     
        return eregi('select|insert|update|delete|'|)
        function verify_id($id=null)     
        {     
            if (!$id) { exit('没有提交参数!'); 
        }                                                           //是否为空判断     
        elseif (inject_check($id)) { exit('提交的参数非法!'); }      //注射判断     
        elseif (!is_numeric($id)) { exit('提交的参数非法!'); }      //数字判断     
        $id = intval($id); // 整型化         
        return $id;     
    }     
 ?>

然后进行对某个参数的过滤:

 <?php     
    if (inject_check($_GET['id']))     
    {     
        exit('你提交的数据非法,请检查后重新提交!');     
    }     
    else     
    {     
        $id = verify_id($_GET['id']); // 这里引用了我们的过滤函数,对$id进行过滤     
        echo '提交的数据合法,请继续!';     
    }     
?>

在POST提交的数据中,使用函数addslashes()是最终的比较好的方法,构建如下函数:

<?php        
    function str_check( $str )     
    {     
        if (!get_magic_quotes_gpc())              //判断magic_quotes_gpc是否打开     
        {     
            $str = addslashes($str);              //进行过滤     
        }     
        $str = str_replace("_", "\_", $str);      //把 '_'过滤掉     
        $str = str_replace("%", "\%", $str);      //把' % '过滤掉     
        return $str;     
    }     
?>

对于大批量的数据,修改为如下:

<?php      
    function post_check($post)     
    {     
        if (!get_magic_quotes_gpc())                  //判断magic_quotes_gpc是否为打开     
        {     
            $post = addslashes($post);                //进行magic_quotes_gpc没有打开的情况对提交数据的过滤     
        }     
        $post = str_replace("_", "\_", $post);        //把 '_'过滤掉     
        $post = str_replace("%", "\%", $post);        //把' % '过滤掉     
        $post = nl2br($post);                         //回车转换     
        $post= htmlspecialchars($post);               //html标记转换        
        return $post;     
    }     
?>

对于MySQL用户,可以使用函数mysql_real_escape_string( ):

<?php $clean = array(); $mysql = array(); $clean['last_name'] = "O'Reilly"; $mysql['last_name'] = mysql_real_escape_string($clean['last_name']); $sql = "INSERT INTO user (last_name) VALUES ('{$mysql['last_name']}')"; ?>

使用支持参数化查询语句和占位符的数据库操作类(如PEAR::DB, PDO等),如使用PEAR::DB的例子:

<?php $sql = 'INSERT INTO user (last_name) VALUES (?)'; $dbh->query($sql, array($clean['last_name'])); ?>

以上方法结合使用,则可有效的防止在PHP语言网站的SQL注入。

3、对于jsp语言类型的网站,建议采用如下方法进行修复:

通过参数化查询方式进行SQL注入攻击防护,参考代码:

using (SqlConnection conn = new SqlConnection(connectionString))
{
    conn.Open();
    SqlCommand comm = new SqlCommand();
    comm.Connection = conn;
    //为每一条数据添加一个参数
    comm.CommandText = "select COUNT(*) from Users where Password = @Password and UserName = @UserName";
    comm.Parameters.AddRange(new SqlParameter[]
    {
        new SqlParameter("@Password", SqlDbType.VarChar) { Value = password};
        new SqlParameter("@UserName", SqlDbType.VarChar) { Value = userName};
    }
    comm.ExecuteNonQuery();
}

//以“?”等位符进行参数化查询
PreparedStatement pstmt = con.prepareStatement("select * from table where name = ?");
pstmt.setString(1, para);
ResultSet rs = pstmt.executeQuery();

使用MyBatis技术,通过Mapper.xml文件定义SQL语句进行SQL注入攻击防护,参考代码:

<mapper namespace="TestUser">                  //命名空间
    <select id="getById" parameterType="java.lang.String" resultMap="TestFlowResult">
        select
        <include refid="TestFlowColumns" />
        <![CDATA[ from TEST_TABLE where INSPECT_ID = #{id} ]]>
    </select>
</mapper>
注:在编写mybatis的映射语句时,尽量采用“#{xxx}”这样的格式。若不得不使用“${xxx}”这样的参数,要手工地做好过滤工作,来防止sql注入攻击。

使用特殊字符过滤程序防护SQL注入攻击,参考代码:

public static bool SqlCheck(string OldString) {
    bool Checkvalue = false;
    string NewString = OldString.ToLower();
    string Replace = "'|and|exec|insert|select|delete|update|count|*|;|%|union|chr|mid|master|truncate|char|declare|asc|cast|set|fetch|varchar|sysobjects|drop|alert|script|<|>";
    string[] arrReplace = Replace.Split('|');
    for (int i = 0; i < arrReplace.Length; i++)  {
        if (NewString.IndexOf(arrReplace[i].ToString()) >= 0)  {
            bolvalue = true;
            break;
        }
    }
    return Checkvalue;
}

4、除此之外,还可以进行对数据库方面进行加固,来防止sql注入的产生:

不要以sysadmin的身份连接数据库。而是使用特定的数据库用户,只具有读取,写入和更新数据库中适当数据的适当特权。此帐户定期检查,确定它所具有的特权。

以安全的方式创建SQL。让数据库来完成创建SQL的工作,而不是在代码中完成。使用参数化SQL语句,同时也能提高查询的效率。

保证数据库用户连接信息非明文保存。

5.除此之外,还可以进行对管理方面进行加固,来防止sql注入的产生:

加强编程人员良好的安全编码意识,系统地学习安全编码的知识,减少源代码泄露的风险。
建立起良好的代码审核、审查体系。由专人负责代码的审计,增加安全监督环节。

5、SQL防护外篇

1、使用存储过程

String custname = request.getParameter(“customerName”);
try {
    CallableStatement cs = connection.prepareCall(“call sp_getAccountBalance(?)}”);
    cs.setString(1,custname);
    Result results = cs.executeQuery();
} catch(SQLException se) {
    //error handling
}

2、MyBatis的SQL注入防护—模糊查询

MySQL:     select * from table where name like concat(‘%’,#{name},’%’)
Oracle:    select * from table where name like ‘%’ || #{name} || ‘%’
SQL Server:select * from table where name like ‘%’+#{name}+’%’
DB2:       select * from table where name like concat(‘%’,#{name},’%’)

猜你喜欢

转载自blog.csdn.net/wutianxu123/article/details/82718718