污点标记如何传播

污点标记是存储于字符串本身上的一个比特位,而不是存储于持有它的 变量上。对被污染的字符串进行赋值、传参或其它形式的共享,标记都会 保留。字符串拼接和插值同样会传播标记:

会传播污点标记的运算符
=(赋值,包括 list() / 数组解构
.(拼接)
.=(拼接赋值)
"{$var}"(字符串插值,包括 ROPE 快速路径)

此外,taint 还理解一组固定的字符串函数:只要相关的字符串参数被污染, 返回的字符串也会被标记为已污染。常规调用和 PHP 8.4+ 的 frameless 快速路径调用都在覆盖范围内。

会传播污点标记的函数
trim(), rtrim(), ltrim()
substr(), strstr()
str_replace(), str_ireplace()
str_pad(), strtolower(), strtoupper(), strval()
explode()(结果数组中的每一个元素)
implode()/join()(分隔符被污染时,结果同样会被污染)
sprintf(), vsprintf()(只有 %s 说明符会携带标记;sprintf("%d", $t) 返回的是干净字符串)
dirname(), basename(), pathinfo()

任何 taint 没有显式理解的函数都会返回一个新的、不带标记的字符串 —— 包括 htmlspecialchars()htmlentities()mysqli_real_escape_string() 这类转义函数。 这是有意为之:taint 宁可多报,也不会去判断某个值在特定输出场景下 是否安全。对于已经自行校验过的值,请用 untaint() 清除标记。