一、php 的 sql 注入攻击
1.1、什么是 sql 注入攻击
用户提交一段数据库查询代码,根据返回的结果,获得某些他想得到的数据。
比如 :查询某个管理员是否存在,一般程序员会这么写$sql = "select * from user where name='luluyii' and password='****'";
if (查询到) {
header("admin.php");
}else {
header("login.php");
}
这样写,容易被人通过 sql 注入攻击进入你的 admin.php 页面。
1.2、万能密码和万能用户名
(1)方式一
① 万能密码$sql = "select * from user where name='**' and password='***' or 1='1'";
即万能密码是:**' or 1='1
② 万能用户名$sql = "select * from user where name='**' union select * form user/* and password='***';
/*表示不执行后面的语句,即万能用户名是:**' union select * from user/*
(二)方式二$sql = 去掉 '$name' 和 '$password'的单引号;
这种写法,没有' ',mysql数据库会把你的输入当数字对待
① 使用万能密码:数字 union select * form user
② 使用万能用户名:数字 union select * form user/*
1.3、防止用户登录注入
(1)在php.ini 中开启 magic_quotes_gpc = On,但是这个特性在 php 5.3.0 中已经废弃,并且在 php 5.4.0 中已经移除。
若配置了,方式一中的万能用户名和万能密码将失效,但是方式二仍然有效。
原因是:当改为 on 之后,Apache 服务器会对 ' 加入 \ 转义,如name = 'luluyii',当数据库执行时,变成 name = \'luluyii\'
(2)密码对比法
① 基本思想:改变验证数据库用户逻辑。
首先通过用户输入的用户名去查询数据库,如果查询到这个用户对应的密码,和用户提交的密码对比,相同则说明该用户合法,否则不合法。$sql = "select password form user where name='luluyii'";
if(从数据库查询到的密码 == 用户输入的密码){
header("admin.php");
}else{
header("login.php");
}
分析:这样写,用户无法通过 password = 注入攻击,因为 if( == ) 是在php中验证的。
② 使用 pdo 的预编译来解决 sql 注入
首先在 php,ini 中启用 pdo:extension = php_pdo_mysql.dll$mypdo = new PDO("mysql:localhost;port=3306;dbname=luluyii","root","root");
$pdoStatment = $mypdo->prepare($sql); //预编译
$pdoStatment->execute(array($name,$password)); //接收
$pdoStatment->fetch(); //取出结果
1.4、php 搜索引擎中 sql 注入问题
(1)一般使用 _ _ 和 % 攻击,获取所有数据
(2)防止查询 sql 攻击$keyWord = addslashes($keyWord); //使用反斜杠引用字符串
$keyWord = str_replace("%","\%",$keyWord); //将 % 替换为 \%
$keyWord = str_replace("_","\_",$keyWord); //将 _ 替换为 \_
1.5、总结
防止 SQL 注射漏洞一般用什么函数?addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。
$str = addslashes('Shanghai is the "biggest" city in China.');
echo($str);
//输出 Shanghai is the \"biggest\" city in China.
sql 注入的方式还有其它很多形式,我们要写出健壮安全的代码,就要不断提高编写安全代码的意识,让我们的代码更符合
商业要求。
二、php 数据库编程 mysqli、pdo
2.1、mysqli
2.1.1、mysql 和 mysqli 说明
(1)msyqli 是 mysql 扩展库的增强版
(2)mysql 和 mysqli的比较
① mysqli 的稳定性、安全性、效率都有所提升
② mysqli 支持面向对象编程,同时考虑到 php 老程序员,提供面向过程的编程风格
2.1.2、案例$conn = mysqli_connect("localhost",'root','root');
if (!$conn){
die("数据库连接失败".mysqli_error());
}
mysqli_select_db($conn,"luluyii");
mysqli_query($conn,"set names utf8");
$sql = "select * from lulu_user";
$res = mysqli_query($conn,$sql);
while($row = mysqli_fetch_row($res)){
foreach ($row as $key=>$val){
echo "$val--";
}
echo "
";
}
mysqli_free_result($res);
mysqli_close($conn);
2.1.3、细节说明
(1)关闭连接和释放资源
mysqli_close($conn); //关闭连接,是把 ① 断开;
mysqli_free_result($res); //释放资源,是把 ② 断开。
(2)从 $res 获取行数据的四个方法① mysqli_fetch_row 返回一个索引数组
② mysqli_fetch_assoc 返回一个关联数组
③ mysqli_fetch_array 返回索引和关联数组
④ mysqli_fetch_object 把一行数据当做对象返回
(3)函数mysqli_insert_id($conn) 取得上一步 Insert 操纵产生的 ID
$field_info = mysqli_fetch_field($res) 返回包含字段信息的对象,如$field_info->name
mysqli_affected_rows($conn) 取得前一次mysql操作所影响的记录行数
(4)三种释放 $res 结果集的方法
① $res->free(); ② $res->close(); ③ $res->free_result();
2.1.4、批量执行sql 语句
ddl 数据定义语句:CREATE TABLE
dml 数据操作语句:update、insert、delete
dql 数据查询语句:select
dcl 数据事务语句:rollback、commit
(1)批量执行 dml 语句$sqls = "sql1;sql2;...";
$mysqli->multi_query($sqls);
(2)批量执行 dql 语句$mysqli->store_result(); //从 mysqli 连接取出一个结果集
$mysqli->fetch_row();
$mysqli->more_results(); //用于判断是否有新的结果集
$mysqli->next_result(); //用于指向下一个结果集,但它不会判断下一个结果集是否存在,故需使用 $mysqli->more_results()
2.2、事务控制
2.2.1、概念
事务用于保证数据的一致性,它由一组相关的 dml 语句组成,该组的 dml 语句要么全部成功,要么全部失败。
如:网上转账就是典型的要用事务来处理,用以保证数据的一致性。
2.2.2、事务的 ACID 性质
① Atomicity 原子性:操作不可分割,要么都发生,要么都不发生
② Consistency 一致性:是一个数据库从一个一致性状态到另一个一致性状态
③ Isolation 隔离性:一旦开始事务,别的操作无法使用你正在使用的数据库
④ Durability 持久性:一旦提交,数据库的状态不再发生变化
2.2.3、在 mysqli 控制台可以使用事务来操作
① start transaction 开启一个事务
② savepoint a 保存点
③ 操作
④ 可回滚,可提交:若无问题 —— commit 提交,若有问题 —— rollback to a 回滚到 a
2.3、mysqli 扩展库的预编译处理技术
$sql = "insert into user (name,password,email,age) values(?,?,?,?)";
这里的 ? 是个占位符,告诉数据库无需编译,只是数据的变化。
优点:效率高,执行速度快;安全性高,防止 sql 注入。
2.4、PDO —— PHP Data Object
2.4.1、基本介绍
① 该扩展在 PHP 5 中加入
② PHP 6 中默认使用 PDO 连接数据库
2.4.2、什么是 PDO
PDO 相当于是一个数据库抽象层,不同数据库使用相同的方法名,解决数据库连接不统一的问题。