soarli

防止注入的一些PHP转义函数
本文转自互联网,已在文末注明来源。。互联网中一切的输入都不可信,有用户可以自由输入的地方就可能存在着安全漏洞。转义...
扫描右侧二维码阅读全文
25
2021/06

防止注入的一些PHP转义函数

本文转自互联网,已在文末注明来源。。
互联网中一切的输入都不可信,有用户可以自由输入的地方就可能存在着安全漏洞。转义函数的使用就是为了提高系统的安全性,防止潜在的攻击,如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."分析,可获得下列结果:
img
(1)为原输入输出,单引号并没有被转义。经实验,通过GET获得的数据也不会被转义;
(2)对所有a进行转义,变为“a”;
(3)对H进行转义,区分大小写;
(4)对空格进行转义;
(5)对单引号进行转义,当然该语句也可以写作:

echo "<h3>".addcslashes($str,"'")."</h3><br>";

(6)对范围内的每个字符均进行转义,a…z表示从a到z的所有字母;
以上的语句均是对一般字符的使用,下面考虑一些特殊字符:
img
按顺序分析:
(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)连接。数据库内容相应的有所变化:
img
浏览器中输入:http://localhost/SQLInjection.php?id=1&password=1234,有如下结果:
img
对于数字型的输入,加不加引号都行,http://localhost/SQLInjection.php?id=‘1’&password=‘1234’,也是对的。但是含有字母则必须带引号。由于没有任何的过滤措施,存在注入风险。再次强调,一定要遵循 数据与代码分离原则!,浏览器输入:http://localhost/SQLInjection.phpid=1&password=’ 'or 1
img
可以发现,数据库所有内容都被显示出来。

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 ,单引号的存在会产生语法错误:
img
使用函数转义可以解决这一问题:
img
查询数据库可以看到数据已经插入:
img

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 - 不编码任何引号。
//输出结果为&lt;script&gt;alert(&#039;123&#039;)&lt;/script&gt;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>");
?>

img
参考资料:

  1. mysql_real_escape_string()函数官方文档
  2. mysqli_real_escape_string()函数官方文档
  3. mysql与mysqli的区别
  4. PHP 7.4 与mysql(mariaDB)连接

原文地址:

https://my.oschina.net/u/4347613/blog/4668987

https://blog.csdn.net/chihouzi/article/details/107689320

最后修改:2021 年 06 月 25 日 08 : 49 PM

发表评论