标题:学习一个PHP中用于检测危险函数的扩展Taint
学习一个PHP中用于检测危险函数的扩展Taint
在日常的开发中,安全性一直是我们要研究的重点内容之一。而在安全性中,最主要的一点就是我们的输入数据。所有的攻击和越权,都是从一个不经意间遗留的请求漏洞发生的。当然,现在很多框架已经为我们解决了大部分的安全性问题,但百密一疏,总会有意想不到的地方忘了加过滤或者遗漏了某些验证。今天我们要学习的这个扩展就是为我们解决这种问题而诞生的。
什么是 Taint
上篇文章中就得到过,我们还要介绍一个鸟哥的扩展工具,Taint 这个扩展就是鸟哥大神的作品之一。不过这个扩展是不推荐安装在生产环境的,它主要的战场是在我们的测试环境中使用。它的主要功能就是如果我们使用了未经处理的 \$_GET 、 $_POST 、 $_COOKIE 之类的变量,就会报出警告信息。注意,只是警告,而不是错误或者异常。一般在线上环境我们都会习惯性地关掉警告信息的报错,所以这个扩展在线上的功能有限。
扩展的安装非常简单,下载对应的扩展然后进行普通的扩展安装即可,不需要额外的其它操作系统中组件的支持。对于这个扩展的详细信息,可以参考文末第二条链接中鸟哥文章的说明。
怎么用?
php.ini 中打开扩展,然后设置 taint.enable = 1 。就正式启用这个扩展了。然后我们通过代码来测试。
$a = $_GET['a'];
$file_name = '/tmp' . $a;
$output = "Welcome, {$a} !!!";
$var = "output";
$sql = "Select * from " . $a;
echo $a, "<br/>"; // Warning: main() [echo]: Attempt to echo a string that might be tainted in /data/www/blog/taint/1.php on line 10
echo $output, "<br/>"; // Warning: main() [echo]: Attempt to echo a string that might be tainted in /data/www/blog/taint/1.php on line 12
print $$var; echo "<br/>"; // Warning: main() [print]: Attempt to print a string that might be tainted in /data/www/blog/taint/1.php on line 14
include($file_name);echo "<br/>"; // Warning: main() [include]: File path contains data that might be tainted in /data/www/blog/taint/1.php on line 16
mysqli_query(null, $sql);echo "<br/>"; // Warning: main() [mysqli_query]: SQL statement contains data that might be tainted in /data/www/blog/taint/1.php on line 18
我们使用 php -S 来调试这个测试文件,当访问这个测试文件并且带上 a 参数之后,就可以看到下面的这些操作都会报出警告信息。未经过滤的这个 $a ,不管是拼接到字符串中,还是作为可变变量,只要是通过 echo 、 print 、 include 或者是 mysqli_query() 这些函数调用后,都会马上出现报警,提示你使用的这个数据字符串是需要进行过滤的。taint 的意思是 污点 。might be tainted 也就是有污点内容的意思。
大部分输出或者操作数据库之类的函数都会报出这些警告,这些内容的具体信息可以在官方文档中查询到。
我们还可以通过一个判断函数来验证一个变量中是否包含这类未处理的数据。
var_dump(is_tainted($var)); // bool(false)
echo "<br/>";
var_dump(is_tainted($output)); // bool(true)
echo "<br/>";
怎样不报警?
怎样不让它报警?那当然就是对数据进行处理啦。
$output = "Welcome, ".htmlentities($a)." !!!";
echo $output, "<br/>";
$sql = "Select * from " . mysqli_escape_string(null, $a);
mysqli_query(null, $sql);echo "<br/>";
在输出的时候进行 html 编码一下,对应的就是 XSS 攻击的防范。在数据库操作的时候 escape 一下,对应的就是处理掉 SQL 注入的攻击。使用了这些处理函数对数据进行安全性处理之后就不会报警告信息了。
由此可以看出,这个扩展确实是我们在日常开发调试中,特别是测试环境中的好帮手。就像前面所说的,总会有遗漏和遗忘的地方,通过这个扩展让程序来自动发现这些内容,对于我们开发的安全来说就能够有非常大的提高。
检测及转换函数
最后在 Taint 扩展中,还提供了两个函数用于强制进行警告和解除警告的作用,当然,也是为了我们在测试环境中的调试方便。
$newOutput = "Welcome !!!";
echo $newOutput, "<br/>";
var_dump(taint($newOutput)); // bool(true)
echo $newOutput, "<br/>"; // // Warning: main() [echo]: Attempt to echo a string that might be tainted in /data/www/blog/taint/1.php on line 39
$newOutput = "Welcome {$a} !!!";
echo $newOutput, "<br/>"; // Warning: main() [echo]: Attempt to echo a string that might be tainted in /data/www/blog/taint/1.php on line 42
var_dump(untaint($newOutput)); // bool(true)
echo $newOutput, "<br/>";
taint() 函数可以让一个正常的语句报出警告。而 untaint() 则可以让一个本身应该报警的数据不报警。
总结
同样还是非常小众的扩展,但是学习了之后发现还真的是挺有用的,而且特别适合在我们的测试环境中向大家提供一个全面检测安全质量的报警系统。就像文中一直强调的那样,对于中大型的项目开发来说,遗漏是不可避免的,即使有完善的 code review 机制,但也总会有所有人都遗漏的漏洞存在。通过程序的方式来检验自然是最好不过的,大家可以多多尝试一下。
测试代码:
参考文档:
https://www.php.net/manual/zh/book.taint.php
https://www.laruence.com/2012/02/14/2544.html