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 选择哪一个?》
PDO(PHP Data Object),Mysqli,以及对sql注入等问题的解决的更多相关文章
- PDO(PHP Data Object)数据访问抽象层
1.可以访问其它数据库2.具有事务功能3.带有预处理语句功能(防止SQL注入攻击) 访问数据库 PDO::__construct ( string $dsn [, string $username [ ...
- Java学习笔记47(JDBC、SQL注入攻击原理以及解决)
JDBC:java的数据库连接 JDBC本质是一套API,由开发公司定义的类和接口 这里使用mysql驱动,是一套类库,实现了接口 驱动程序类库,实现接口重写方法,由驱动程序操作数据库 JDBC操作步 ...
- 关于SQL注入的问题以及解决方法
1.关于SQL注入 什么是SQL注入: 由于jdbc程序在执行的过程中sql语句在拼装时使用了由页面传入参数,如果用户恶意传入一些sql中的特殊关键字,会导致sql语句意义发生变化,这种攻击方式就叫做 ...
- SQL注入实验,PHP连接数据库,Mysql查看binlog,PreparedStatement,mysqli, PDO
看到有人说了判断能否sql注入的方法: 简单的在参数后边加一个单引号,就可以快速判断是否可以进行SQL注入,这个百试百灵,如果有漏洞的话,一般会报错. 下面内容参考了这两篇文章 http://blog ...
- PDO 学习与使用 ( 一 ) :PDO 对象、exec 方法、query 方法与防 SQL 注入
1.安装 PDO 数据库抽象层 PDO - PHP Data Object 扩展类库为 PHP 访问数据库定义了一个轻量级的.一致性的接口,它提供了一个数据访问抽象层,针对不同的数据库服务器使用特定的 ...
- 如何使用PDO查询Mysql来避免SQL注入风险?ThinkPHP 3.1中的SQL注入漏洞分析!
当我们使用传统的 mysql_connect .mysql_query方法来连接查询数据库时,如果过滤不严,就有SQL注入风险,导致网站被攻击,失去控制.虽然可以用mysql_real_escape_ ...
- SQL注入之代码层防御
[目录] 0x0 前言 0x1 领域驱动的安全 1.1 领域驱动的设计 1.2 领域驱动的安全示例 0x2 使用参数化查询 2.1 参数化查询 2.2 Java中的参数化语句 2.3 .NET(C#) ...
- sql注入实例分析
什么是SQL注入攻击?引用百度百科的解释: sql注入_百度百科: 所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令.具 ...
- jdbc操作数据库以及防止sql注入
public class pr { public static void main(String[] args) { Connection conn = null; Statement st = nu ...
随机推荐
- application/x-www-form-urlencoded multipart/form-data text/plain 的区别和作用
我们知道在通过POST方式向服务器发送AJAX请求时最好要通过设置请求头来指定为application/x-www-form-urlencoded编码类型.知道通过表单上传文件时必须指定编码类型为&q ...
- register_globals
register_globals参数为On的时候很危险 这里记录一下各版本register_globals的情况 PHP5.2版本register_globals默认为On PHP5.3 PHP5.3 ...
- 有关npm rum的3个简洁技巧
[编者按]本文作者为来自 MongoDB 的 NodeJS 工程师 Valeri Karpov.Valeri 专注于维护常见的 Mongoose ODM,是<Professional Angul ...
- HDU 4632 Palindrome subsequence(区间dp,回文串,字符处理)
题目 参考自博客:http://blog.csdn.net/u011498819/article/details/38356675 题意:查找这样的子回文字符串(未必连续,但是有从左向右的顺序)个数. ...
- Eclipse环境下配置spket中ExtJS提示
使用eclipse编写extjs时,一定会用到spket这个插件,spket可以单独当作ide使用,也可以当作eclipse插件使用,我这里是当作eclipse的插件使用的,下面来一步步图解说明如何配 ...
- EF框架批量更新
var customers = db.Customers.Where(c => c.name=='小明'); foreach (var customer in customers) { cust ...
- Tomcat目录结构
首先来了解一下Tomcat5.5的目录结构: /bin:存放windows或Linux平台上启动和关闭Tomcat的脚本文件 /conf:存放Tomcat服务器的各种全局配置文件,其中包括server ...
- [转载]Jmeter那点事·ForEach和If控制器
如果我们要实现一个循环,如果城市是北京,则返回首都:否则,返回城市. 一.新建用户自定义变量 添加-配置元件-用户自定义变量, 定义变量注意命名格式:变量名 加 下划线 加 数字(从1开始计数) ...
- 关于HTTP协议的学习
HTTP(HyperTextTransferProtocol)是超文本传输协议的缩写,它用于传送WWW方式的数据,关于HTTP 协议的详细内容请参考RFC2616.HTTP协议采用了请求/响应模型.客 ...
- java web线程池
线程池 要知道在计算机中任何资源的创建,包括线程,都需要消耗系统资源的.在WEB服务中,对于web服 务器的响应速度必须要尽可能的快,这就容不得每次在用户提交请求按钮后,再创建线程提供服务 .为了减少 ...