本文转自互联网,已在文末注明来源。。
互联网中一切的输入都不可信,有用户可以自由输入的地方就可能存在着安全漏洞。转义函数的使用就是为了提高系统的安全性,防止潜在的攻击,如SQL注入,XSS攻击等。本文介绍六个函数,分别是:
addcslashes();
addslashes();
mysql_real_escape_string();(mysqli_real_escape_string();)
htmlspecialchars();
htmlentities();
strip_tags();
1.addcslashes()函数及addslashes()函数
addcslashes() 函数返回在指定字符前添加反斜杠的字符串,且addcslashes() 函数对大小写敏感。
需要注意:对以下字符应用 addcslashes() 时请小心:0(NULL), r(回车), n(换行), f 换页)、t(制表符)以及 v(垂直制表符)。在 PHP 中,0, r, n, t, f 以及 v 是预定义的转义序列。 (实验说明,PHP7.4不再处理这些内容)
addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。预定义字符是:
单引号(’)双引号(")反斜杠()NULL
默认地,PHP 对所有的 GET、POST 和 COOKIE 数据自动运行 addslashes()。所以您不应对已转义过的字符串使用 addslashes(),因为这样会导致双层转义(就目前实验来看,本人PHP版本为7.4,PHP5.4版本以上已经不会默认对特殊字符转义,特殊字符的处理已经完全交给用户自己处理了)
可实验如下,创建index.php文件:
<?php
$str = "He's a young student, and has many interests.";
echo "<h3>".$str."</h3><br>";
echo "<h3>".addcslashes($str,'a')."</h3><br>";
echo "<h3>".addcslashes($str,'H')."</h3><br>";
echo "<h3>".addcslashes($str,' ')."</h3><br>";
echo "<h3>".addcslashes($str,'\'')."</h3><br>";
echo "<h3>".addcslashes($str,'a..z')."</h3><br>";
$s = '"There Are Heroisms All Round Us "\n.
Mr. Hungerton, her father, really was the most tactless person upon earth,—a fluffy, feathery, untidy cockatoo of a man, perfectly good-natured, but absolutely centered upon his own silly self. If anything could have driven me from Gladys, it would have been the thought of such a father-in-law. \t
---Doyle,Arthur Conan. (The Lost World) \r';
echo "<h3>".$s."</h3><br>";
echo "<h3>".addcslashes($s,'\n')."</h3><br>";
echo "<h3>".addcslashes($s,'\\n')."</h3><br>";
echo "<h3>".addcslashes($s,'n')."</h3><br>";
echo "<h3>".addslashes($s)."</h3><br>";
?>
开启apache后,浏览器中输入地址:https://127.0.0.1/index.php,首先对$str= "He’s a young student, and has many interests."分析,可获得下列结果:
(1)为原输入输出,单引号并没有被转义。经实验,通过GET获得的数据也不会被转义;
(2)对所有a进行转义,变为“a”;
(3)对H进行转义,区分大小写;
(4)对空格进行转义;
(5)对单引号进行转义,当然该语句也可以写作:
echo "<h3>".addcslashes($str,"'")."</h3><br>";
(6)对范围内的每个字符均进行转义,a…z表示从a到z的所有字母;
以上的语句均是对一般字符的使用,下面考虑一些特殊字符:
按顺序分析:
(1)仅打印出原输入,作为对比;
(2)对字符串“n”进行转义,这里千万不要将其看做c语言中的换行符,它就是单斜杠“”和字符n,就是对字符串中的单斜杠“”和字符n分别进行转义;
(3)这里对字符“n”进行转义,结果和(2)一样。这里重复了一个单斜杠,并不影响结果,仍旧对单斜杠和字母n进行转义;
(4)正常转义,仅对字母n进行转义;
(5)所使用的是addslashes()函数,对预定义符号进行转义;
总的来说,由于SQL注入中一般需要闭合单引号(除了数字型的注入,极少使用),使用addslashes()即可对单引号转义,只能说从一定程度上减小注入的风险,并不能真正避免。对于addcslashes()函数,可以自定义转义哪些字符,使用不当容易出错。对于XSS攻击,可以对"<",">"
进行转义,但基本没用,可以通过编码的方式绕过。
2.mysql_real_escape_string()函数(PHP7中已移除,不推荐)
该函数于PHP 4.3.0,引入,在PHP 5.5.0开始废弃,PHP 7.0.0 开始被移除。可以使用MYSQLi函数mysqli_real_escape_string()替换,二者功能上没有区别,但是在参数位置顺序上有所不同。关于mysql与mysqli的区别见参考资料3:mysql与mysqli的区别,请不要使用此函数,PHP7已经不支持此库。
该部分由于已舍弃,这里仅作记录,实际中请使用 mysqli_real_escape_string(),mysqli_real_escape_string()函数参数顺序与此相反!
mysql_real_escape_string () 转义 SQL 语句中使用的字符串中的特殊字符,并考虑到连接的当前字符集。它会调用mysql库的函数 mysql_real_escape_string, 在以下字符前添加反斜杠: x00, n, r, , ', " 和 x1a。为了安全起见,在向MySQL传送查询前,必须调用这个函数(除了少数例外情况)。
格式:
mysql_real_escape_string ( string $unescaped_string [, resource $link_identifier = NULL ] ) : string
参数说明:
$unescaped_string | 必须存在的参数,规定要转义的字符串。 |
---|---|
$link_identifier | 可选的参数,MySQL 连接。如不指定连接标识,则使用由 mysql_connect() 最近打开的连接。如果没有找到该连接,会尝试不带参数调用 mysql_connect() 来创建。如没有找到连接或无法建立连接,则会生成 E_WARNING 级别的错误。 |
返回值 | 转义后的字符串,或者错误信息。 |
由于此函数已舍弃,这里给出一个不使用转义函数可能导致注入风险的例子:
在文件夹/var/www/html/下建立文件 SQLIjection.php,内容如下:
<?php
$serve = 'localhost:3306';
$user = 'lee';
$psd = '123';
$dbname = 'kali';
$link = mysqli_connect($serve,$user,$psd,$dbname);
// 检测连接
if (!$link) {
die("Connection failed: " . mysqli_connect_error());
}
$query = 'select * from users where id = '.$_GET['id'].' and password = '.$_GET['password'];
//$query = 'select * from users where id = 1';
echo 'THE query is :'. $query;
echo "<br>";
mysqli_set_charset($link,'UTF-8'); // 设置数据库字符集
$result = mysqli_query($link,$query);
$data = mysqli_fetch_all($result); // 从结果集中获取所有数据
print_r($data);
?>
关于建立PHP与mysql交互过程的具体细节,见另一篇文章:PHP 7.4 与mysql(mariaDB)连接。数据库内容相应的有所变化:
浏览器中输入:http://localhost/SQLInjection.php?id=1&password=1234,有如下结果:
对于数字型的输入,加不加引号都行,http://localhost/SQLInjection.php?id=‘1’&password=‘1234’,也是对的。但是含有字母则必须带引号。由于没有任何的过滤措施,存在注入风险。再次强调,一定要遵循 数据与代码分离原则!,浏览器输入:http://localhost/SQLInjection.phpid=1&password=’ 'or 1
可以发现,数据库所有内容都被显示出来。
3.mysqli_real_escape_string()函数
mysqli库提供了面向对象和面向过程两种书写方式,根据个人习惯自由选择。所以该函数也可以写作:mysqli::real_escape_string;这里本人采用面向过程的方式。
过程化风格 | mysqli_real_escape_string ( mysqli link , stringlink,stringescapestr ) : string |
---|---|
用来对字符串中的特殊字符进行转义, 以使得这个字符串是一个合法的 SQL 语句。 传入的字符串会根据当前连接的字符集进行转义,得到一个编码后的合法的 SQL 语句。 | |
$link | 仅以过程化样式:由mysqli_connect() 或 mysqli_init() 返回的链接标识。 |
$escapestr | 需要进行转义的字符串。会被进行转义的字符包括: NUL (ASCII 0),n,r,,’," 和 Control-Z. |
该函数用来转义输入的字符,可以简单验证如下:文件夹下创建mres.php文件,
<?php
$serve = 'localhost:3306';
$user = 'lee';
$psd = '123';
$dbname = 'kali';
$link = mysqli_connect($serve,$user,$psd,$dbname);
// 检测连接
if (!$link) {
die("Connection failed: " . mysqli_connect_error());
}
mysqli_query($link, "CREATE TABLE Users LIKE users");
$username = "'lee's";
// 由于未对 $username 进行转义,此次查询会失败
if (!mysqli_query($link, "INSERT into Users (username) VALUES ('$username')")) {
printf("Error: %s\n", mysqli_sqlstate($link));
}
/*
$username = mysqli_real_escape_string($link, $username);
// 对 $username 进行转义之后,查询可以正常执行
if (mysqli_query($link, "INSERT into Users (username) VALUES ('$username')")) {
printf("%d Row inserted.\n", mysqli_affected_rows($link));
}
*/
mysqli_close($link);
?>
由于$username = “'lee’s”;输入为 'lee’s ,单引号的存在会产生语法错误:
使用函数转义可以解决这一问题:
查询数据库可以看到数据已经插入:
4.html string函数
除了Mysqli库函数之外,PHP也自带了一些字符串处理函数:htmlspecialchars(); htmlentities(); strip_tags();这些函数主要针对XSS攻击。
htmlspecialchars()函数
htmlspecialchars() 函数把预定义的字符转换为 HTML 实体。
预定义的字符是:
& (和号)成为 &
" (双引号)成为 "
’ (单引号)成为 '
< (小于)成为 <
> (大于)成为 >
语法 | htmlspecialchars(string,flags,character-set,double_encode) |
---|---|
string | 必需。规定要转换的字符串。 |
flags | 可选。规定如何处理引号、无效的编码以及使用哪种文档类型。可用的引号类型:ENT_COMPAT - 默认。仅编码双引号。ENT_QUOTES - 编码双引号和单引号。ENT_NOQUOTES - 不编码任何引号。 |
character-set | 可选。一个规定了要使用的字符集的字符串。 |
double_encode | 可选。布尔值,规定了是否编码已存在的 HTML 实体。TRUE - 默认。将对每个实体进行转换。FALSE - 不会对已存在的 HTML 实体进行编码。 |
htmlentities()函数
htmlentities转换所有的html标记,htmlspecialchars只格式化& 、’、"、 <、> 这几个特殊符号。
使用htmlentities不指定编码的话遇到中文会乱码(指定htmlentities为UTF-8编码,可以正常转义)。
其参数格式与htmlspecialchars()函数一样。
<?php
$str="<script>alert('123')</script>";
echo htmlentities($str, ENT_QUOTES);
//ENT_COMPAT - 默认。仅编码双引号。
//ENT_QUOTES - 编码双引号和单引号。
//ENT_NOQUOTES - 不编码任何引号。
//输出结果为<script>alert('123')</script>gt;
//页面展示: <script>alert('123')</script>
strip_tags()函数
strip_tags() 函数剥去字符串中的 HTML、XML 以及 PHP 的标签。该函数始终会剥离 HTML 注释。这点无法通过 allow 参数改变。该函数是二进制安全的。
语法 | strip_tags(string,allow) |
---|---|
string | 必需。规定要检查的字符串。 |
allow | 可选。规定允许的标签。这些标签不会被删除。 |
<?php
echo strip_tags("Hello <b><i>world!</i></b>","<b>");
?>
参考资料:
- mysql_real_escape_string()函数官方文档
- mysqli_real_escape_string()函数官方文档
- mysql与mysqli的区别
- PHP 7.4 与mysql(mariaDB)连接
原文地址:
https://my.oschina.net/u/4347613/blog/4668987
https://blog.csdn.net/chihouzi/article/details/107689320
版权属于:soarli
本文链接:https://blog.soarli.top/archives/521.html
转载时须注明出处及本声明。