1、安全开发-原生PHP-弱类型脆弱
2、安全开发-原生PHP-函数&数据类型
3、安全开发-原生PHP-代码审计案例
1、== 和 ===
两个等号==是弱比较,使用==进行对比的时候,php解析器就会做隐式类型转换,如果两个值的类型不相等就会把两个值的类型转为同一类型进行对比。
==:弱比较运算符,进行比较时,PHP会尝试将两个值的类型进行隐式转换为相同的类型。
===:强比较运算符,要求类型和值都相等,不进行任何隐式转换。
在弱比较下,某些值之间可能因为隐式类型转换导致不符合预期的结果。例如:
if ("123abc" == 123) {echo "True"; // 输出 "True",因为 "123abc" 被转换为数字 123 进行比较
}
建议与修复:
总是优先使用 === 进行比较,避免隐式类型转换。
如果必须使用弱比较,明确了解隐式转换规则,并确保输入类型符合预期。
if ("123abc" === 123) {echo "True"; // 不会输出任何结果
}
2、MD5对比缺陷
进行hash加密出来的字符串如存在0e开头进行弱比较的话会直接判定为true
QNKCDZO与0e830400451993494058024219903391
md5(QNKCDZO,32) = 0e830400451993494058024219903391
240610708与0e462097431906509019562988736854
md5(240610708,32) = 0e462097431906509019562988736854
s878926199a与0e545993274517709034328855841020
md5(s878926199a,32) = 0e545993274517709034328855841020
MD5 哈希值以 0e
开头时,PHP 的弱比较会将其解释为科学计数法的数字 0
。例如:
if (md5('QNKCDZO') == md5('240610708')) {echo "True"; // 输出 "True",因为两个哈希值都以 `0e` 开头,被解析为 0
}
安全隐患:这种比较方式会导致哈希碰撞,攻击者可以利用特定输入生成以 0e
开头的 MD5 值,从而绕过验证。
建议与修复:
不要使用弱比较 (==) 进行哈希值验证,应使用强比较 (===)。
使用更安全的哈希算法,如 hash_hmac 或 password_hash。
if (md5('QNKCDZO') === md5('240610708')) {echo "True"; // 不会输出任何结果
}
3 函数strcmp类型比较缺陷
低版本的strcmp比较的是字符串类型,如果强行传入其他类型参数,会出错,出错后返回值0,正是利用这点进行绕过。
在 PHP 的低版本中,strcmp()
函数只能用于比较字符串。如果传入非字符串参数,会返回 0
,因为出错后 PHP 内部会返回相等的结果。
if (strcmp([], "string") == 0) {echo "True"; // 输出 "True",因为出错后返回 0
}
安全隐患:攻击者可以通过传入特殊类型的参数(如数组、对象)绕过逻辑判断。
建议与修复:
确保传入参数的类型始终是字符串。
使用显式类型检查或类型强制转换:
if (is_string($param1) && is_string($param2) && strcmp($param1, $param2) === 0) {echo "Strings are equal.";
}
4、函数Bool类型比较缺陷
在使用 json_decode() 函数或 unserialize() 函数时,部分结构被解释成 bool 类型,也会造成缺陷,运行结果超出研发人员的预期
使用 json_decode()
解析 JSON 字符串或 unserialize()
反序列化数据时,如果数据的结构意外被解析为布尔值,可能会引发逻辑错误。例如:
$json = 'false';
if (json_decode($json)) {echo "True"; // 不输出任何结果,但逻辑可能被绕过
}
安全隐患:攻击者可以构造特定的 JSON 数据或序列化数据,导致解析结果超出预期。
建议与修复:
显式检查解析结果的类型和结构:
$data = json_decode($json, true);
if (is_array($data) && isset($data['key'])) {// 进一步逻辑处理
}
5、函数switch 类型比较缺陷
当在switch中使用case判断数字时,switch会将参数转换为int类型计算
switch
语句中,PHP 会将 case
参数转换为整数类型进行比较。如果传入字符串类型的参数,可能会意外被转换为数字:
switch ("123abc") {case 123:echo "Matched"; // 输出 "Matched",因为 "123abc" 被转换为 123break;
}
安全隐患:攻击者可以通过构造特定输入绕过逻辑判断。
建议与修复:
避免在 switch 中混用不同类型的数据。
使用 === 替代 switch 语句中的隐式比较
$value = "123abc";
if ($value === 123) {echo "Matched";
}
6、函数in_array数组比较缺陷
当使用in_array()或array_search()函数时,如果第三个参数没有设置为true,则in_array()或array_search()将使用松散比较来判断
in_array()
和 array_search()
默认使用弱比较(==
)。如果未设置第三个参数为 true
,可能会导致意外的比较结果:
$array = ["123", 123];
if (in_array("123abc", $array)) {echo "True"; // 输出 "True",因为 "123abc" 被转换为数字 123
}
安全隐患:攻击者可以构造与数组中已有值相等的不同类型数据,绕过验证。
建议与修复:
始终设置第三个参数为 true,启用严格比较:
if (in_array("123abc", $array, true)) {echo "True"; // 不会输出任何结果
}
7、===数组比较缺陷
注意此时遇到的是 “===” ,不过也不是代表无从下手。在md5()函数传入数组时会报错返回NULL,当变量都导致报错返回NULL时就能使使得条件成立。
在 PHP 中,md5()
函数不支持数组作为参数,会抛出错误并返回 NULL
。如果多个变量导致函数返回 NULL
,可能使条件成立:
$a = md5([]);
$b = md5([]);
if ($a === $b) {echo "True"; // 输出 "True",因为两次调用均返回 NULL
}
安全隐患:攻击者可以利用此特性通过错误处理来绕过逻辑。
建议与修复:
确保函数参数的类型符合预期:
if (is_string($input) && md5($input) === $knownHash) {echo "Valid";
}
使用显式类型验证,避免直接比较可能返回错误的结果。
案例:
CTF题目:
矛盾 - Bugku CTF平台
MD5 - Bugku CTF平台
代码审CMS:
某Info CMS代码审计