19
3

绑定参数原理以及SQL注入..

Author Jessica     Category PHP     Tags , ,

假设我们的用户表中存在一行.用户名字段为username.值为aaa.密码字段为pwd.值为pwd..
下面我们来模拟一个用户登录的过程..

  1. <?php  
  2. $username = "aaa";  
  3. $pwd = "pwd";  
  4. $sql = "SELECT * FROM table WHERE username = '{$username}' AND pwd = '{$pwd}'";  
  5. echo $sql//输出  SELECT * FROM table WHERE username = 'aaa' AND pwd = 'pwd'  
  6. ?> 

这样去执行这个sql语句.显然是可以查询出来东西的.返回用户的这一列.登录成功!!
然后我改一下..把密码改一下.随便一个值.如下.我改成了ppp.

  1. <?php  
  2. $pwd = 'ppp';  
  3. $sql = "SELECT * FROM table WHERE username = '{$username}' AND pwd = '{$pwd}'";  
  4. echo $sql//输出  SELECT * FROM table WHERE username = 'aaa' AND pwd = 'ppp'  
  5. ?> 

这样很显然.如果去执行这个SQL语句..是查询不到东西的.也就是密码错误.登录失败!!
但是有的人总是不老实的.他们会想尽一切办法来进行非法的登录.所谓非法就是在他不知道用户名密码的时候进行登录.并且登录成功..
那么他们所做的原理是什么呢??其实原理都是利用SQL语句..SQL语句强大的同时也给我们带来了不少麻烦..
我来举个最简单的例子.我们要运用到的SQL关键字是or
还是上面的代码.我们只要修改一下密码即可

  1. <?php  
  2. $username = "aaa";  
  3. $pwd = "fdsafda' or '1'='1";  //前面的密码是瞎填的..后来用or关键字..意思就是无所谓密码什么都执行  
  4. $sql = "SELECT * FROM table WHERE username = '{$username}' AND pwd = '{$pwd}'";  
  5. echo $sql;  //输出  SELECT * FROM table WHERE username = 'aaa' AND pwd = 'fdsafda' or '1'='1'  
  6. ?> 

执行一下这个SQL语句..可怕的事情发生了..竟然可以查询到这一行数据..也就是登录成功了..
这是多么可怕的事情..
PHP为了解决这个问题.magic_quotes state..就是PHP会自动过滤传过来的GET.POST等等.
题外话.实践证明这个东西是畸形的..大部分程序不得不为判断此功能而耗费了很多代码..
在Java中可没有这个东西..那么Java中如何防止这种SQL注入呢??

Java的sql包中提供了一个名字叫PreparedStatement的类.
这个类就是我要说的绑定参数!
什么叫绑定参数??我继续给大家举例..(我用PHP举例)

  1. <?php  
  2. $username = "aaa";  
  3. $pwd = "pwd";  
  4. $sql = "SELECT * FROM table WHERE username = ? AND pwd = ?";  
  5. bindParam($sql, 1, $username'STRING');  //以字符串的形式.在第一个问号的地方绑定$username这个变量  
  6. bindParam($sql, 2, $pwd'STRING');       //以字符串的形式.在第二个问号的地方绑定$pwd这个变量  
  7. echo $sql;  
  8. ?> 

当然.到此.你肯定不知道会输出什么..更无法知道绑定参数有什么好处!这样做的优势是什么.更不知道bindParam这个函数到底做了什么.
下面我简单的写一下这个函数..只是一个模拟的过程..表达一个意思..代码幼稚还望包涵..

  1. <?php  
  2. /**
  3.  * 模拟简单的绑定参数过程  
  4.  *  
  5.  * @param string $sql    SQL语句  
  6.  * @param int $location  问号位置  
  7.  * @param mixed $var     替换的变量  
  8.  * @param string $type   替换的类型  
  9.  */ 
  10. $times = 0;  
  11. function bindParam(&$sql$location$var$type) {  
  12.     global $times;  
  13.     //确定类型  
  14.     switch ($type) {  
  15.         //字符串  
  16.         default:                    //默认使用字符串类型  
  17.         case 'STRING' :  
  18.             $var = addslashes($var);  //转义  
  19.             $var = "'".$var."'";      //加上单引号.SQL语句中字符串插入必须加单引号  
  20.             break;  
  21.         case 'INTEGER' :  
  22.         case 'INT' :  
  23.             $var = (int)$var;         //强制转换成int  
  24.         //还可以增加更多类型..  
  25.     }  
  26.     //寻找问号的位置  
  27.     for ($i=1, $pos = 0; $i<= $location$i++) {  
  28.         $pos = strpos($sql'?'$pos+1);  
  29.     }  
  30.     //替换问号  
  31.     $sql = substr($sql, 0, $pos) . $var . substr($sql$pos + 1);  
  32. }  
  33. ?> 

注:由于得知道去除问号的次数..所以我用了一个global来解决.如果放到类中就非常容易了.弄个私有属性既可..我这只是个模拟..

通过上面的这个函数.我们知道了..绑定参数的防注入方式其实也是通过转义进行的..只不过是对于变量而言的..
我们来做一个实验

  1. <?php  
  2. $times = 0;  
  3. $username = "aaaa";  
  4. $pwd = "123";  
  5. $sql = "SELECT * FROM table WHERE username = ? AND pwd = ?";  
  6. bindParam($sql, 1, $username'STRING');  //以字符串的形式.在第一个问号的地方绑定$username这个变量  
  7. bindParam($sql, 2, $pwd'INT');       //以字符串的形式.在第二个问号的地方绑定$pwd这个变量  
  8. echo $sql;  //输出  SELECT * FROM table WHERE username = 'aaaa' AND pwd = 123  
  9. ?> 

可以看到.生成了非常正规的SQL语句.那么好.我们现在来试下刚才被注入的那种情况

  1. <?php  
  2. $times = 0;  
  3. $username = "aaa";  
  4. $pwd = "fdsafda' or '1'='1";  
  5. $sql = "SELECT * FROM table WHERE username = ? AND pwd = ?";  
  6. bindParam($sql, 1, $username'STRING');  //以字符串的形式.在第一个问号的地方绑定$username这个变量  
  7. bindParam($sql, 2, $pwd'STRING');       //以字符串的形式.在第二个问号的地方绑定$pwd这个变量  
  8. echo $sql//输出  SELECT * FROM table WHERE username = 'aaa' AND pwd = 'fdsafda\' or \'1\'=\'1'  
  9. ?> 

可以看到.pwd内部的注入已经被转义.当成一个完整的字符串了..这样的话.就不可能被注入了.

在PHP6中.PHP打算取消魔术过滤..而打规模的普及使用PDO..PDO中的bindParam()就如我上面描述的那样.已经在防注入中起到了关键作用.

所以为了迎接PHP6的到来.更为了使大家的程序严谨安全..强烈推荐大家使用PDO来做程序的DB类..( 可惜现在很少空间支持:( )

好了.我的废话就说到这里..希望大家对绑定参数已经有了一个比较有深度的理解:)

3 Comments to “ 绑定参数原理以及SQL注入.. ”

  • 淡水 2009年03月20日 于 12:31

    密码md5就没有问题了
    现在框架也比较多了,而且主流都提供了比较安全的过滤方式

  • 游客 2009年04月1日 于 14:47

    看完了…学习了…但觉得有点麻烦啊

  • 游客 2009年06月29日 于 17:03

    推荐使用pdo

Post comment

分类目录

最近文章

近期评论

文章归档

标签

.net AJAX button Comet CSS Discuz! DIV+CSS Flash Form Google HTML编辑器 IE8 Java JavaScript jQuery JSP md5 MySQLReback OAuth Oracle PHP php-fpm PNG Punny SkiyoTabs tab TagCloud Vista Web2.0 Windows7 上传 加密 图标 本站原创 模板 模板引擎 源码 登录 短网址 石家庄 算法 编译 面向对象 魔术方法

链接表