• 转:php防止sql注入的一点心得


    转:http://blog.csdn.net/sky_zhe/article/details/9702489

    转:http://zhangxugg-163-com.iteye.com/blog/1835721

     

    如何才能禁止PHP本地转义而交由MySQL Server转义呢?

    PDO有一项参数,名为PDO::ATTR_EMULATE_PREPARES ,表示是否使用PHP本地模拟prepare,此项参数默认值未知。而且根据我们刚刚抓包分析结果来看,php 5.3.6+默认还是使用本地变量转,拼接成SQL发送给MySQL Server的,我们将这项值设置为false, 试试效果,如以下代码:

    <?php

    $pdo = new PDO("mysql:host=192.168.0.1;dbname=test;","root");

    $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

    $st = $pdo->prepare("select * from info where id =? and name = ?");

    $id = 21;

    $name = 'zhangsan';

     

    $st->bindParam(1,$id);

    $st->bindParam(2,$name);

    $st->execute();

    $st->fetchAll();

    ?>

     

    红色行是我们刚加入的内容,运行以下程序,使用wireshark抓包分析,得出的结果如下:

     



     

           看到了吗?这就是神奇之处,可见这次PHP是将SQL模板和变量是分两次发送给MySQL的,由MySQL完成变量的转义处理,既然变量和SQL模板是分两次发送的,那么就不存在SQL注入的问题了,但需要在DSN中指定charset属性,如:$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'root');如此,即可从根本上杜绝SQL注入的问题。

    使用PDO的注意事项

    1. php升级到5.3.6+,生产环境强烈建议升级到php 5.3.9+ php 5.4+,php 5.3.8存在致命的hash碰撞漏洞。
    2. 若使用php 5.3.6+, 请在在PDO的DSN中指定charset属性
    3. 如果使用了PHP 5.3.6及以前版本,设置PDO::ATTR_EMULATE_PREPARES参数为false(即由MySQL进行变量处理).
        php 5.3.6以上版本已经处理了这个问题,无论是使用本地模拟prepare还是调用mysql server的prepare均可。在DSN中指定charset是无效的,同时set names <charset>的执行是必不可少的。
    4. 如果使用了PHP 5.3.6及以前版本, 因Yii框架默认并未设置ATTR_EMULATE_PREPARES的值,请在数据库配置文件中指定emulatePrepare的值为false。那么,有个问题,如果在DSN中指定了charset, 是否还需要执行set names <charset>呢?是的,不能省。set names <charset>其实有两个作用:
    A.  告诉mysql server, 客户端(PHP程序)提交给它的编码是什么
    B.  告诉mysql server, 客户端需要的结果的编码是什么
    也就是说,如果数据表使用gbk字符集,而PHP程序使用UTF-8编码,我们在执行查询前运行set names utf8, 告诉mysql server正确编码即可,无须在程序中编码转换。这样我们以utf-8编码提交查询到mysql server, 得到的结果也会是utf-8编码。省却了程序中的转换编码问题,不要有疑问,这样做不会产生乱码。那么在DSN中指定charset的作用是什么? 只是告诉PDO, 本地驱动转义时使用指定的字符集(并不是设定mysql server通信字符集)。


    针对php 5.3.6以前版本,以下代码仍然可能造成SQL注入问题:

    $pdo->query('SET NAMES GBK'); 
    $var = chr(0xbf) . chr(0x27) . " OR 1=1 /*"; 
    $query = "SELECT * FROM info WHERE name = ?"; 
    $stmt = $pdo->prepare($query);
    $stmt->execute(array($var)); 

    MySQL在5.5.3之后增加了这个utf8mb4的编码,mb4就是most bytes 4的意思,专门用来兼容四字节的unicode。好在utf8mb4是utf8的超集,除了将编码改为utf8mb4外不需要做其他转换。当然,为了节省空间,一般情况下使用utf8也就够了。

    注意当使用PDO访问MySQL数据库真正的预备义语句并不是默认使用的(<=php5.3.6)!为了解决这个问题,你必须禁用仿真准备好的语句。使用PDO创建连接的例子如下:
    复制代码 代码如下:
    $dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
    $dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    在上面例子中错误模式ERRMODE不是严格必须的,但是建议添加它。当运行出错产生致命错误时,这种方法脚本不会停止。并给开发人员捕捉任何错误的机会(当抛出PDOException异常时)。setAttribute()那一行是强制性的,它告诉PDO禁用仿真预备义语句,使用真正的预备义语句。这可以确保语句和值在发送给MySQL数据库服务器前不被PHP解析(攻击者没有机会注入恶意的SQL).

  • 相关阅读:
    慕课网-安卓工程师初养成-3-2 Java中的算术运算符
    慕课网-安卓工程师初养成-3-1 什么是运算符
    慕课网-安卓工程师初养成-2-13 练习题
    慕课网-安卓工程师初养成-2-12 如何在Java中使用注释
    慕课网-安卓工程师初养成-2-11 Java常量
    慕课网-安卓工程师初养成-2-10 Java中的强制类型转换
    试把一个正整数n拆分为若干个
    求解两个给定正整数m、n的最大公约数(m、n)
    统计n!尾部零
    横竖折对称方阵
  • 原文地址:https://www.cnblogs.com/studyskill/p/6524141.html
Copyright © 2020-2023  润新知