Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 604|回复: 0

PDO(PHP Data Object),Mysqli,以及对sql注入等问题的解决

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-7-15 13:16:19 | 显示全部楼层 |阅读模式

    这篇是上一篇 http://www.cnblogs.com/charlesblc/p/5987951.html 的续集。

    看有的文章提到mysqli和PDO都支持多重查询,所以下面的url会造成表数据被删。

    http://localhost:8080/test.php?id=3;delete%20from%20users

    可是我在mysql版本的函数,上面的sql都不能执行。是不是不支持多重查询了?

     

    这篇文章 http://www.runoob.com/php/php-mysql-connect.html 对mysqli, PDO的方式有一些介绍,不详细。

    主要用的这篇文章:http://blog.csdn.net/yipiankongbai/article/details/17277477

    三种连接方式:

    // PDO  
    $pdo = new PDO("mysql:host=localhost;dbname=database", 'username', 'password');  
       
    // mysqli, procedural way  
    $mysqli = mysqli_connect('localhost','username','password','database');  
       
    // mysqli, object oriented way  
    $mysqli = new mysqli('localhost','username','password','database');  

     

    先看mysqli过程型:

    <?php
    header('Content-Type: text/html; charset=utf-8');
    echo "PHP version:" . PHP_VERSION . "<br/>";
    
    $con = mysqli_connect('10.117.146.21:8306', 'root', '[password]');
    mysqli_select_db($con, 'springdemo');
    
    $input_id = trim($_GET['id']);
    $sql = 'select nickname from user where id = ' . $input_id;
    print_r('SQL is:' . $sql . '<br/>');
    $result = mysqli_query($con, $sql);
    
    if ($result != null) {
      print_r('rows:' . mysqli_num_rows($result) . '<br/>');
      while ($row = mysqli_fetch_array($result)) {
        print_r($row['nickname'] . '<br/>');
      }
    }
    
    mysqli_close($con);
    ?>

    测试:

    http://localhost:8080/test.php?id=3
    
    PHP version:5.5.30
    SQL is:select nickname from user where id = 3
    rows:1
    micro
    
    http://localhost:8080/test.php?id=3%20or%201=1
    
    PHP version:5.5.30
    SQL is:select nickname from user where id = 3 or 1=1
    rows:4
    abc
    micro
    helloworld
    你好

    加上real_escape函数:

    ?php
    header('Content-Type: text/html; charset=utf-8');
    echo "PHP version:" . PHP_VERSION . "<br/>";
    
    $con = mysqli_connect('10.117.146.21:8306', 'root', '[password]');
    mysqli_select_db($con, 'springdemo');
    
    $input_id = mysqli_real_escape_string($con, $_GET['id']);
    $sql = 'select nickname from user where id = ' . $input_id;
    print_r('SQL is:' . $sql . '<br/>');
    $result = mysqli_query($con, $sql);
    
    if ($result != null) {
      print_r('rows:' . mysqli_num_rows($result) . '<br/>');
      while ($row = mysqli_fetch_array($result)) {
        print_r($row['nickname'] . '<br/>');
      }
    }
    
    mysqli_close($con);
    ?>

    测试:

    http://localhost:8080/test.php?id=3%20or%201=1
    
    PHP version:5.5.30
    SQL is:select nickname from user where id = 3 or 1=1
    rows:4
    abc
    micro
    helloworld
    你好
    
    注:仍然有问题,因为没有在url里面加引号!

    采用推荐的mysqli的PreparedStatement方式:

    ?php
    header('Content-Type: text/html; charset=utf-8');
    echo "PHP version:" . PHP_VERSION . "<br/>";
    
    $con = new mysqli('10.117.146.21:8306', 'root', '[password]', 'springdemo');
    //mysqli_select_db($con, 'springdemo');
    
    $query = $con->prepare('SELECT nickname FROM user WHERE id = ?');
    $query->bind_param('s', $_GET['id']);
    $query->execute();
    
    $result = $query->get_result();
    if ($result != null) {
      print_r('rows:' . mysqli_num_rows($result) . '<br/>');
      while ($row = mysqli_fetch_array($result)) {
        print_r($row['nickname'] . '<br/>');
      }
    }
    
    mysqli_close($con);
    ?>

    测试:

    http://localhost:8080/test.php?id=3
    
    PHP version:5.5.30
    rows:1
    micro
    
    http://localhost:8080/test.php?id=3%20or%201=1
    
    PHP version:5.5.30
    rows:1
    micro

     

    PDO与mysqli的对比:

    性能
    PDO和MySQLi都有非常好的性能。在非prepared statements的基准测试下,MySQLi略快2.5%,而prepared statements下是6.5%,可以说对于性能无关紧要。

     

      PDO MySQLi
    Database support 12 different drivers MySQL only
    API OOP OOP + procedural
    Connection Easy Easy
    Named parameters Yes No
    Object mapping Yes Yes
    Prepared statements 
    (client side)
    Yes No
    Performance Fast Fast
    Stored procedures Yes Yes

     PDO方式:

    <?php
    header('Content-Type: text/html; charset=utf-8');
    echo "PHP version:" . PHP_VERSION . "<br/>";
    
    $pdo = new PDO("mysql:host=10.117.146.21:8306;dbname=springdemo", 'root', '[password]');
    
    class Name {
       public $nickname;
    
       public function info()
       {
          return '#'.$this->nickname;
       }
    }
    
    $input_id = $_GET['id'];
    $sql = 'select nickname from user where id = ' . $input_id;
    print_r('SQL is:' . $sql . '<br/>');
    $result = $pdo->query($sql);
    $result->setFetchMode(PDO::FETCH_CLASS, 'Name');
    
    if ($result != null) {
      while ($row = $result->fetch()) {
        print_r($row->info() . '<br/>');
      }
    }
    
    $pdo=null;
    ?>

    测试:

    http://localhost:8080/test.php?id=3
    
    PHP version:5.5.30
    SQL is:select nickname from user where id = 3
    #micro
    
    http://localhost:8080/test.php?id=3%20or%201=1
    
    PHP version:5.5.30
    SQL is:select nickname from user where id = 3 or 1=1
    #abc
    #micro
    #helloworld
    #你好

    加上转码:

    $input_id = $pdo->quote($_GET['id']);

    测试:

    http://localhost:8080/test.php?id=3
    
    PHP version:5.5.30
    SQL is:select nickname from user where id = '3'
    #micro
    
    http://localhost:8080/test.php?id=3%20or%201=1
    
    PHP version:5.5.30
    SQL is:select nickname from user where id = '3 or 1=1'
    #micro

    注意,pdo的quote自动加了引号,解决了这个问题。

    http://localhost:8080/test.php?id=3%27%20or%201=%271
    
    PHP version:5.5.30
    SQL is:select nickname from user where id = '3\' or 1=\'1'
    #micro

    并且,尝试自己加引号去做侵入也没有用的。引号被转码了,所以成功防住攻击。

     

    PDO的prepared statement:

    <?php
    header('Content-Type: text/html; charset=utf-8');
    echo "PHP version:" . PHP_VERSION . "<br/>";
    
    $pdo = new PDO("mysql:host=10.117.146.21:8306;dbname=springdemo", 'root', '[password]');
    
    $prepared = $pdo->prepare('select nickname from user where id = :id');
    
    $prepared->execute(array(':id' => $_GET['id']));
    
    while ($results = $prepared->fetch(PDO::FETCH_ASSOC)) {
        print_r($results['nickname'] . '<br/>');
    }
    
    $pdo=null;
    ?>

    实验:

    http://localhost:8080/test.php?id=3
    
    PHP version:5.5.30
    micro
    
    http://localhost:8080/test.php?id=3%20or%201=1
    
    PHP version:5.5.30
    micro

    都不再出现sql注入的威胁。

    PDO里面多次用到fetch:

    说明
    PDO::FETCH_ASSOC 关联数组形式。
    PDO::FETCH_NUM 数字索引数组形式。
    PDO::FETCH_BOTH 两者数组形式都有,这是默认的。
    PDO::FETCH_OBJ 按照对象的形式,类似于以前的mysql_fetch_object()函数。
    PDO::FETCH_BOUND 以布尔值的形式返回结果,同时将获取的列值赋给bindParam()方法中指定的变量。
    PDO::FETCH_LAZY 以关联数组、数字索引数组和对象3种形式返回结果。

    把上面程序给prepared statement传参数的过程改了一下:

    <?php
    header('Content-Type: text/html; charset=utf-8');
    echo "PHP version:" . PHP_VERSION . "<br/>";
    
    $pdo = new PDO("mysql:host=10.117.146.21:8306;dbname=springdemo", 'root', '[password]');
    
    $prepared = $pdo->prepare('select nickname from user where id = :id');
    
    $prepared->bindParam(':id', $_GET['id']);
    $prepared->execute();
    
    while ($results = $prepared->fetch(PDO::FETCH_ASSOC)) {
        print_r($results['nickname'] . '<br/>');
    }
    
    $pdo=null;
    ?>

    实验之后,结果对于上面哪些url,都能得到正确的结果。

    性能方面:

    PDO和MySQLi都有非常好的性能。在非prepared statements的基准测试下,MySQLi略快2.5%,而prepared statements下是6.5%,可以说对于性能无关紧要。
    如果你真的非常介意这一点点性能的话,而自带的MySQL扩展比两者都快,你可以考虑下它。

     

    上面部分来自这篇:http://blog.csdn.net/yipiankongbai/article/details/17277477 《PDO vs. MySQLi 选择哪一个?》

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-22 13:41 , Processed in 0.060170 second(s), 30 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表