PDO::quote讲解_php基础_脚本之家

PDO::quote

PDO::quote — 为SQL语句中的字符串添加引号。(PHP 5 >= 5.1.0, PECL pdo
>= 0.2.1)

前言

0x00:php内置过滤函数

说明

本文章主要以后端PHP和MySQL数据库为例,参考了多篇文章后的集合性文章,欢迎大家提出个人见解,互促成长。

php有内置的函数用来防御攻击,简单的介绍几个函数。

语法

图片 1

魔术引号

public string PDO::quote ( string $string [, int $parameter_type = PDO::PARAM_STR ] )

一、 PHP几种防御姿势

当打开时,所有的 ‘(单引号),”(双引号),(反斜线)和 NULL
字符都会被自动加上一个反斜线进行转义。这和 addslashes() 作用完全相同。

PDO::quote()为SQL语句中的字符串添加引号或者转义特殊字符串。

1. 关闭错误提示

一共有三个魔术引号指令:

参数

说明:

magic_quotes_gpc 影响到 HTTP 请求数据(GET,POST 和
COOKIE)。不能在运行时改变。在 PHP 中默认值为 on。 参见
get_magic_quotes_gpc()。

parameter_type

PHP配置文件php.ini中的display_errors=Off,这样就关闭了错误提示。

magic_quotes_runtime
如果打开的话,大部份从外部来源取得数据并返回的函数,包括从数据库和文本文件,所返回的数据都会被反斜线转义。该选项可在运行的时改变,在
PHP 中的默认值为 off。 参见 set_magic_quotes_runtime() 和
get_magic_quotes_runtime()。

为驱动程序提供数据类型。

2. 魔术引号

magic_quotes_sybase
如果打开的话,将会使用单引号对单引号进行转义而非反斜线。此选项会完全覆盖
magic_quotes_gpc。如果同时打开两个选项的话,单引号将会被转义成
”。而双引号、反斜线 和 NULL 字符将不会进行转义。 如何取得其值参见
ini_get()。

返回值

说明:

mysql_real_escape_string

返回一个带引号的字符串,理论上可以安全的传递到SQL语句中并执行。如果该驱动程序不支持则返回FALSE。

当php.ini里的magic_quotes_gpc=On时。提交的变量中所有的单引号(‘)、双引号(“)、反斜线()与
NUL(NULL 字符)会自动转为含有反斜线的转义字符。

转义sql语句中使用的字符串中的特殊字符:x00、n、r、、’、”、x1a

实例

魔术引号(Magic Quote)是一个自动将进入 PHP
脚本的数据进行转义的过程。(对所有的 GET、POST 和 COOKIE
数据自动运行转义)

addslashes()

为普通字符串添加引号

PHP 5.4 之前 PHP 指令 magic_quotes_gpc 默认是 on。

返回在预定义字符之前添加反斜杠的字符串,预定义字符:’、”、、NULL

quote . "n";?>

本特性已自PHP 5.3.0 起废弃并将自 PHP 5.4.0 起移除,在PHP 5.4.O
起将始终返回 FALSE。

看了很多php网站在防sql注入上还在使用ddslashes和str_replace,百度一下”PHP防注入”也同样在使用他们,实践发现就连mysql_real_escape_string也有黑客可以绕过的办法,如果你的系统仍在用上面三个方法,建议更好。

以上输出结果为:

参考:

用str_replace以及各种php字符替换函数来防注入已经不用我说了,这种“黑名单”式的防御已经被证明是经不起时间考验的。

Unquoted string: NiceQuoted string: ‘Nice’

《magic_quotes_gpc相关说明》:

下面给出绕过addslasher和mysql_real_escape_string的方法(Trick)。

转义特殊字符串

如果你不确定你的系统是否有SQL注入的风险,请将下面的下面的DEMO部署到你的服务器,如果运行结果相同,那么请参考最后的完美的解决方案。

quote . "n";?>

3. addslashes

mysql:

以上例程会输出:

说明:

mysql> select version();
+---------------------+
| version()           |
+---------------------+
| 5.0.45-community-ny |
+---------------------+
1 row in set (0.00 sec)
mysql> create database test default charset GBK;
Query OK, 1 row affected (0.00 sec)
mysql> use test;
Database changed
mysql> CREATE TABLE users (
    username VARCHAR(32) CHARACTER SET GBK,
    password VARCHAR(32) CHARACTER SET GBK,
    PRIMARY KEY (username)
);
Query OK, 0 rows affected (0.02 sec)
mysql> insert into users SET username='ewrfg', password='wer44';
Query OK, 1 row affected (0.01 sec)
mysql> insert into users SET username='ewrfg2', password='wer443';
Query OK, 1 row affected (0.01 sec)
mysql> insert into users SET username='ewrfg4', password='wer4434';
Query OK, 1 row affected (0.01 sec)=

Unquoted string: Naughty ‘ stringQuoted string: ‘Naughty ” string’

addslashes函数,它会在指定的预定义字符前添加反斜杠转义,这些预定义的字符是:单引号(‘)、双引号(“)、反斜线()与
NUL(NULL 字符)。

php:

总结

这个函数的作用和magic_quotes_gpc一样。所以一般用addslashes前会检查是否开了magic_quotes_gpc。

<?php
echo "PHP version: ".PHP_VERSION."n";

mysql_connect('servername','username','password');
mysql_select_db("test");
mysql_query("SET NAMES GBK");

$_POST['username'] = chr(0xbf).chr(0x27).' OR username = username /*';
$_POST['password'] = 'guess';

$username = addslashes($_POST['username']);
$password = addslashes($_POST['password']);
$sql = "SELECT * FROM  users WHERE  username = '$username' AND password = '$password'";
$result = mysql_query($sql) or trigger_error(mysql_error().$sql);

var_dump(mysql_num_rows($result));
var_dump(mysql_client_encoding());

$username = mysql_real_escape_string($_POST['username']);
$password = mysql_real_escape_string($_POST['password']);
$sql = "SELECT * FROM  users WHERE  username = '$username' AND password = '$password'";
$result = mysql_query($sql) or trigger_error(mysql_error().$sql);

var_dump(mysql_num_rows($result));
var_dump(mysql_client_encoding());

mysql_set_charset("GBK");
$username = mysql_real_escape_string($_POST['username']);
$password = mysql_real_escape_string($_POST['password']);
$sql = "SELECT * FROM  users WHERE  username = '$username' AND password = '$password'";
$result = mysql_query($sql) or trigger_error(mysql_error().$sql);

var_dump(mysql_num_rows($result));
var_dump(mysql_client_encoding());

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。如果你想了解更多相关内容请查看下面相关链接

图片 2

结果:

magic_quotes_gpc与addslashes的区别用法:

PHP version: 5.5.44
int(3)
string(6) "latin1"
int(3)
string(6) "latin1"
int(0)
string(3) "gbk"

1)对于magic_quotes_gpc=on的情况

可以看出来不论是使用addslashes还是mysql_real_escape_string,我都可以利用编码的漏洞来实现输入任意密码就能登录服务器的注入攻击!!!!

我们可以不对输入和输出数据库的字符串数据作addslashes()和stripslashes()的操作,数据也会正常显示。

0x01:宽字节注入

如果此时你对输入的数据作了addslashes()处理,那么在输出的时候就必须使用stripslashes()去掉多余的反斜杠。

 
尽管现在呼吁所有的程序都使用unicode编码,所有的网站都使用utf-8编码,来一个统一的国际规范。但仍然有很多,包括国内及国外(特别是非英语国家)的一些cms,仍然使用着自己国家的一套编码,比如gbk,作为自己默认的编码类型。也有一些cms为了考虑老用户,所以出了gbk和utf-8两个版本。

2)对于magic_quotes_gpc=off 的情况

我们就以gbk字符编码为示范,拉开帷幕。gbk是一种多字符编码,有一个地方尤其要注意:

必须使用addslashes()对输入数据进行处理,但并不需要使用stripslashes()格式化输出,

通常来说,一个gbk编码汉字,占用2个字节。一个utf-8编码的汉字,占用3个字节。在php中,我们可以通过输出

因为addslashes()并未将反斜杠一起写入数据库,只是帮助mysql完成了sql语句的执行。

echo strlen(“和”);

参考:

来测试。当将页面编码保存为gbk时输出2,utf-8时输出3。

《addslashes函数说明》:

除了gbk以外,所有ANSI编码都是2个字节。ansi只是一个标准,在不用的电脑上它代表的编码可能不相同,比如简体中文系统中ANSI就代表是GBK。

如上,想绕过魔术引号等限制,有两种方式:

《对于magic_quotes_gpc的一点认识》:

1.将前面再加一个(或单数个即可),变成\’,这样被转义了,’逃出了限制

2.将去掉。

4. mysql_real_escape_string

我们这里的宽字节注入是利用mysql的一个特性,mysql在使用GBK编码的时候,会认为两个字符是一个汉字(前一个ascii码要大于128,才到汉字的范围)。

说明:

这就是mysql的特性,因为gbk是多字节编码,他认为两个字节代表一个汉字,所以%df和后面的也就是%5c变成了一个汉字“運”,而’逃逸了出来。再尝试“%df%df%27”,就不报错了。因为%df%df是一个汉字,%5c%27不是汉字,仍然是’。

mysql_real_escape_string()函数转义 SQL
语句中使用的字符串中的特殊字符。

那么mysql怎么判断一个字符是不是汉字,根据gbk编码,第一个字节ascii码大于128,基本上就可以了。比如我们不用%df,用%a1也可以,%a1%5c他可能不是汉字,但一定会被mysql认为是一个宽字符,就能够让后面的%27逃逸了出来。

下列字符受影响:

但需要注意的是

x00 n r  ' " x1a 

gb2312和gbk应该都是宽字节家族的一员,却不能注入,这归结于gb2312编码的取值范围。它的高位范围是0xA1~0xF7,低位范围是0xA1~0xFE,而是0x5c,是不在低位范围中的。所以,0x5c根本不是gb2312中的编码,所以自然也是不会被吃掉的。

如果成功,则该函数返回被转义的字符串。如果失败,则返回 false。

所以,把这个思路扩展到世界上所有多字节编码,我们可以这样认为:只要低位的范围中含有0x5c的编码,就可以进行宽字符注入。

本扩展自 PHP5.5.0 起已废弃,并在自 PHP 7.0.0 开始被移除。

0x02:宽字符注入的修复

因为完全性问题,建议使用拥有Prepared
Statement机制的PDO和MYSQLi来代替mysql_query,使用的是mysqli_real_escape_string

先调用mysql_set_charset函数设置连接所使用的字符集为gbk,再调用mysql_real_escape_string来过滤用户输入。

参考:

这个方式是可行的,但有部分老的cms,在多处使用addslashes来过滤字符串,我们不可能去一个一个把addslashes都修改成mysql_real_escape_string。我们第二个解决方案就是,将character_set_client设置为binary(二进制)。

《 PHP防SQL注入不要再用addslashes和mysql_real_escape_string了》:

只需在所有sql语句前指定一下连接的形式是二进制:

mysql_query(“SET character_set_connection=gbk,
character_set_results=gbk,character_set_client=binary”, $conn); 

《PDO防注入原理分析以及使用PDO的注意事项》:

这几个变量是什么意思?

当我们的mysql接受到客户端的数据后,会认为他的编码是character_set_client,然后会将之将换成character_set_connection的编码,然后进入具体表和字段后,再转换成字段对应的编码。

5. htmlspecialchars()

然后,当查询结果产生后,会从表和字段的编码,转换成character_set_results编码,返回给客户端。

说明:

所以,我们将character_set_client设置成binary,就不存在宽字节或多字节的问题了,所有数据以二进制的形式传递,就能有效避免宽字符注入。

htmlspecialchars()函数把预定义的字符转换为 HTML实体。

0x03:PDO和MYSQLI

预定义的字符是:

完美解决方案就是使用拥有Prepared
Statement机制的PDO和MYSQLi来代替mysql_query(注:mysql_query自 PHP
5.5.0 起已废弃,并在将来会被移除):

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website