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

这篇是上一篇 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 选择哪一个?》

时间: 2024-12-17 06:58:11

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

Java学习笔记47(JDBC、SQL注入攻击原理以及解决)

JDBC:java的数据库连接 JDBC本质是一套API,由开发公司定义的类和接口 这里使用mysql驱动,是一套类库,实现了接口 驱动程序类库,实现接口重写方法,由驱动程序操作数据库 JDBC操作步骤: 1.注册驱动 2.获得连接 3.获得语句执行平台 4.执行sql语句 5.处理结果 6.释放资源 1.导入jar包,可以在网上下载到,这里使用的是:mysql-connector-java-5.1.37-bin.jar 注册驱动: package demo; import java.sql.D

JDBC的SQL注入漏洞分析和解决

1.1.1 SQL注入漏洞分析 1.1.2 SQL注入漏洞解决 需要采用PreparedStatement对象解决SQL注入漏洞.这个对象将SQL预先进行编译,使用?作为占位符.?所代表内容是SQL所固定.再次传入变量(包含SQL的关键字).这个时候也不会识别这些关键字. public class UserDao { ????????? ????????public boolean login(String username,String password){ ????????????????C

php之PDO (PHP DATA OBJECT)

从 PHP 5.1 开始附带了 PDO,PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口.PDO 提供了一个 数据访问 抽象层,这意味着,不管使用哪种数据库(比如mysql,oracle,mssql-),都可以用相同的函数(方法)来查询和获取数据. 1.创建PDO对象 使用PDO扩展必须在php.ini文件中打开相应的扩展,下图打开了pdo_mysql的扩展: 那怎么创建一个pdo对象呢? <?php //$dsn = "mysql:host=服务器地址/名称

如何使用PDO查询Mysql来避免SQL注入风险?ThinkPHP 3.1中的SQL注入漏洞分析!

当我们使用传统的 mysql_connect .mysql_query方法来连接查询数据库时,如果过滤不严,就有SQL注入风险,导致网站被攻击,失去控制.虽然可以用mysql_real_escape_string()函数过滤用户提交的值,但是也有缺陷.而使用PHP的PDO扩展的 prepare 方法,就可以避免 sql injection 风险. PDO(PHP Data Object) 是PHP5新加入的一个重大功能,因为在PHP 5以前的php4/php3都是一堆的数据库扩展来跟各个数据库的

PDO 学习与使用 ( 一 ) :PDO 对象、exec 方法、query 方法与防 SQL 注入

1.安装 PDO 数据库抽象层 PDO - PHP Data Object 扩展类库为 PHP 访问数据库定义了一个轻量级的.一致性的接口,它提供了一个数据访问抽象层,针对不同的数据库服务器使用特定的 PDO 驱动程序访问,如图: Windows 环境下 PHP 5.1 以上版本通过编辑 php.ini文件来安装 PDO:去掉 extension=php_pdo.dll 前面的 ; 如果使用的数据库是 MySQL ,在 php.ini 文件中加载 MySQL 的 PDO 驱动: 添加 exten

SQL注入攻与防之代码层防御SQL注入

[目录] 0x0 前言 0x1 领域驱动的安全 1.1 领域驱动的设计 1.2 领域驱动的安全示例 0x2 使用参数化查询 2.1 参数化查询 2.2 Java中的参数化语句 2.3 .NET(C#)中的参数化语句 2.4 PHP中的参数化语句 2.5 PL/SQL中的参数化语句 0X3 移动应用中的参数化语句 3.1 iOS应用程序中的参数化语句 3.2 Android应用程序中的参数化语句 3.3 HTML浏览器中存储的参数化语句 0x4 输入验证 4.1 白名单 4.2 黑名单 4.3 J

WAF的SQL注入绕过手段和防御技术

一.关于SQL注入 SQL注入是一种常见的入侵WEB应用的手法.SQL注入是利用应用系统的编程漏洞和SQL语言的语法特征,改变原始的SQL语句执行逻辑而产生的. 攻击者向Web应用发送精心构造的输入数据,这些输入中的一部分被解释成SQL指令,改变了原来的正常SQL执行逻辑,执行了攻击者发出的SQL命令,最终使攻击者获取Web应用的管理员权限或者下载了Web应用存到数据库中的敏感信息. 二.SQL注入如何实现 为了对本文进行更好的讲解,下面简单地对SQL注入的原理进行示例性说明. 如下图是某网站的

ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞

ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件根据官方文档对"防止SQL注入"的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果: $Model->where("id=%d and username='%s' and xx='%f'&quo

记录一下学习PDO技术防范SQL注入的方法

最近学习了使用PDO技术防范SQL注入的方法,在博客里当做一次笔记.若果有新的感悟在来添上一笔,毕竟也是刚开始学习.一. 什么是PDO PDO全名PHP Data Object PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口. PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据. 二.如何去使用PDO防范SQL注入?/防范sql注入这里使用quate()方法过滤特殊字符和通过预处理的一些方式以及bindPar