首页 > 编程技术 > php

PHP SQL 预防注入与攻击技术实现以及办法 (1/4)

发布时间:2016-11-25 15:25

php教程 sql 预防注入与攻击技术实现以及办法
1. php 配置文件 php.ini 中的 magic_quotes_gpc 选项没有打开,被置为 off

  2. 开发者没有对数据类型进行检查和转义

  不过事实上,第二点最为重要。我认为, 对用户输入的数据类型进行检查,向 mysql教程 提交正确的数据类型,这应该是一个 web 程序员最最基本的素质。但现实中,常常有许多小白式的 web 开发者忘了这点, 从而导致后门大开。

  为什么说第二点最为重要?因为如果没有第二点的保证,magic_quotes_gpc 选项,不论为 on,还是为 off,都有可能引发 sql 注入攻击。下面来看一下技术实现:

 一. magic_quotes_gpc = off 时的注入攻击
  magic_quotes_gpc = off 是 php 中一种非常不安全的选项。新版本的 php 已经将默认的值改为了 on。但仍有相当多的服务器的选项为 off。毕竟,再古董的服务器也是有人用的。

  当magic_quotes_gpc = on 时,它会将提交的变量中所有的 '(单引号)、"(双号号)、(反斜线)、空白字符,都为在前面自动加上 。下面是 php 的官方说明:

magic_quotes_gpc boolean

sets the magic_quotes state for gpc (get/post/cookie) operations. when magic_quotes are on, all ' (single-quote), " (double quote), (backslash) and nul's are escaped with a backslash automatically

. magic_quotes_gpc = off 时的注入攻击
  magic_quotes_gpc = off 是 php教程 中一种非常不安全的选项。新版本的 php 已经将默认的值改为了 on。但仍有相当多的服务器的选项为 off。毕竟,再古董的服务器也是有人用的。
  当magic_quotes_gpc = on 时,它会将提交的变量中所有的 '(单引号)、"(双号号)、(反斜线)、空白字符,都为在前面自动加上 。下面是 php 的官方说明:


 代码如下:

magic_quotes_gpc boolean
sets the magic_quotes state for gpc (get/post/cookie) operations. when magic_quotes are on, all ' (single-quote), " (double quote), (backslash) and nul's are escaped with a backslash automatically

如果没有转义,即 off 情况下,就会让攻击者有机可乘。以下列测试脚本为例:
 代码如下:

<?
if ( isset($_post["f_login"] ) )
{
// 连接数据库教程...
// ...代码略...

// 检查用户是否存在
$t_struname = $_post["f_uname"];
$t_strpwd = $_post["f_pwd"];
$t_strsql = "select * from tbl_users where username='$t_struname' and password = '$t_strpwd' limit 0,1";

if ( $t_hres = mysql教程_query($t_strsql) )
{
// 成功查询之后的处理. 略...
}
}
?>
<html><head><title>sample test</title></head>
<body>
<form method=post action="">
username: <input type="text" name="f_uname" size=30><br>
password: <input type=text name="f_pwd" size=30><br>

<input type="submit" name="f_login" value="登录">
</form>
</body>

在这个脚本中,当用户输入正常的用户名和密码,假设值分别为 zhang3、abc123,则提交的 sql 语句如下:
 代码如下:

select * from tbl_users
where username='zhang3' and password = 'abc123' limit 0,1

如果攻击者在 username 字段中输入:zhang3' or 1=1 #,在 password 输入 abc123,则提交的 sql 语句变成如下:
 代码如下:

select * from tbl_users
where username='zhang3' or 1=1 #' and password = 'abc123' limit 0,1

由于 # 是 mysql中的注释符, #之后的语句不被执行,实现上这行语句就成了:
 代码如下:

select * from tbl_users
where username='zhang3' or 1=1

这样攻击者就可以绕过认证了。如果攻击者知道数据库结构,那么它构建一个 union select,那就更危险了:
  假设在 username 中输入:zhang3 ' or 1 =1 union select cola, colb,cold from tbl_b #
  在password 输入: abc123,
  则提交的 sql 语句变成:
 代码如下:

select * from tbl_users
where username='zhang3 '
or 1 =1 union select cola, colb,cold from tbl_b #' and password = 'abc123' limit 0,1

由于php教程和mysql教程本身得原因,php+mysql的注射要比asp教程困难,尤其是注射时语句的构造方面更是个难点,本文主要是借对okphp bbs v1.3一些文件得简单分析,来谈谈php+mysql注射语句构造方式,希望本文对你有点帮助。
  声明:文章所有提到的“漏洞”,都没有经过测试,可能根本不存在,其实有没有漏洞并不重要,重要的是分析思路和语句构造。
二.“漏洞”分析:
  1.admin/login.php注射导致绕过身份验证漏洞:
  代码:
  
代码

  $conn=sql_connect($dbhost, $dbuser, $dbps教程wd, $dbname);  $password = md5($password);  $q = "select id,group_id from $user_table where username='$username' and password='$password'";  $res = sql_query($q,$conn);  $row = sql_fetch_row($res);  $q = "select id,group_id from $user_table where username='$username' and password='$password'
 

  中
  $username 和 $password 没过滤,很容易就绕过。(php100中文网)
  对于select * from $user_table where username='$username' and password='$password'这样的语句改造的方法有:
  构造1(利用逻辑运算):$username=' or 'a'='a $password=' or 'a'='a

  相当于sql语句:

select * from $user_table where username='' or 'a'='a' and password='' or 'a'='a'


 

  构造2(利用mysql里的注释语句# ,/* 把$password注释掉):$username=admin'#(或admin'/*)

  即: 

select * from $user_table where username='admin'#' and password='$password'
  相当于:

select * from $user_table where username='admin'


 

  在admin/login.php中$q语句中的$password在查询前进行了md5加密所以不可以用构造1中的语句绕过。这里我们用构造2:

  select id,group_id from $user_table where username='admin'#' and password='$password'"

  相当于: 

select id,group_id from $user_table where username='admin'


 

首先我们推荐filter_sanitize_string ,filter_sanitize_string 过滤器去除或编码不需要的字符。

这个过滤器删除那些对应用程序有潜在危害的数据。它用于去除标签以及删除或编码不需要的字符。

name: "string"
id-number: 513
可能的选项或标志:

filter_flag_no_encode_quotes - 该标志不编码引号
filter_flag_strip_low - 去除 ascii 值在 32 以下的字符
filter_flag_strip_high - 去除 ascii 值在 32 以上的字符
filter_flag_encode_low - 编码 ascii 值在 32 以下的字符
filter_flag_encode_high - 编码 ascii 值在 32 以上的字符
filter_flag_encode_amp - 把 & 字符编码为 &amp;

*/

$var="<b>bill gates<b>";

var_dump(filter_var($var, filter_sanitize_string));

/*
第二个函数strip_tags
strip_tags() 函数剥去 html、xml 以及 php教程 的标签。

语法
strip_tags(string,allow)
*/

echo strip_tags("hello <b>world!</b>");

//hello world!

function uh($str)
{
    $farr = array(
        "/s+/",                                                                    
                       //过滤多余的空白
        "/<(/?)(script|i?frame|style|html|body|title|link|meta|?|%)([^>]*?)>/isu",
  //过滤 <script 等可能引入恶意内容或恶意改变显示布局的代码,如果不需要插入flash等,还可
以加入<object的过滤
        "/(<[^>]*)on[a-za-z]+s*=([^>]*>)/isu",                                     
//过滤网页特效的on事件
     
   );
   $tarr = array(
        " ",
        "<123>",           //如果要直接清除不安全的标签,这里可以留空
        "12",
   );

  $str = preg_replace( $farr,$tarr,$str);
   return $str;
}

更多详细内容请查看:http://www.111cn.net/phper/19/70dd2a905e74cefc9be9c0f17268dadc.htm
?>

1.如果动态构造的sql语句中包含参数,请必须对参数做如下操作
a.将'(单引号)替换成''(两个单引号)
b.将--(注释符)替换掉
c.将参数加入语句时,一定要在前后各加上引号,如:'select * from table where id='''+@id+''''这样的加法
2.如果动态构造的sql语句中包含表参数,请勿必给表加上[](中括号),如:'select * from ['+@tab+']'这样的做法

3..避免动态sql语句:尤其是从ie客户端获取查询、修改、删除条件的字段最容易被注入,例如上述从客户端获取personid,为了开发方便,直接把从客户端获取的persongid作为sql语句的条件,却没有对personid作必要的检查,所以在开发时执行sql语句时最好使用preparedstatement类。

 

4.  验证数据:在客户端ie使用网页特效验证用户输入数据的合法性作用其实不是很大,一定要在获取客户端数据之后,对数据进行严格的验证,开发人员不要假想用户只会输入合法的数据。确保在应用程序中检查分号、引号、括号、sql关键字等。可以使用正则表达式来进行复杂的模式匹配,运用它可以达到良好的效果。


×××网站地址薄查看程序需要传递一个personid,personid可以通过url参数传递,由于地址本查看程序直接获取personid,没有做任何数据合法性验证,而且personid是字符串变量,获取personid的代码如下:

if (getparameter(req,"personid")!=null){

personid=getparameter(req,"personid").trim();

}else{

personid="";

}

该程序中组合成的动态sql语句如下:

personsql="select * from 表名 where userid="+long.tostring(userid)+" and addrcontactid="+personid;

 

由于程序没有检查personid是否是整数,所以攻击者随便给personid赋一个值,即可继续运行后续的程序逻辑,如果攻击者输入如下网址:

http://www.----------------------?personid=6414 or 2=2

组合成的sql语句如下:

select * from 表名where userid=1433620 and addrcontactid=6414 or 2=2

防范方法

  sql注入漏洞可谓是“千里之堤,溃于蚁穴”,这种漏洞在网上极为普遍,通常是由于程序员对注入不了解,或者程序过滤不严格,或者某个参数忘记检查导致。在这里,我给大家一个函数,代替asp教程中的request函数,可以对一切的sql注入say no,函数如下:

function saferequest(paraname,paratype)
 '--- 传入参数 ---
 'paraname:参数名称-字符型
 'paratype:参数类型-数字型(1表示以上参数是数字,0表示以上参数为字符)

 dim paravalue
 paravalue=request(paraname)
 if paratype=1 then
  if not isnumeric(paravalue) then
   response.write "参数" & paraname & "必须为数字型!"
   response.end
  end if
 else
  paravalue=replace(paravalue,"'","''")
 end if
 saferequest=paravalue
end function

上面函数应用

对于int型的参数,如文章的id等,可以先判断是不是整数。

id =trim(request("id"))
if id<>"" then
  if not isnumeric(id) then
    response.write"请提供数字型参数"
    response.end
  end if
  id = clng(id)
else
  response.write"请输入参数id"
  response.end
end if

标签:[!--infotagslink--]

您可能感兴趣的文章: