污点标记是存储于字符串本身上的一个比特位,而不是存储于持有它的 变量上。对被污染的字符串进行赋值、传参或其它形式的共享,标记都会 保留。字符串拼接和插值同样会传播标记:
=(赋值,包括 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() 清除标记。