您好,欢迎访问广州市赏金女王试玩家政有限公司!

全国服务热线:+86 0000 88888

赏金女王(中国)官方网站 - Queen of Bounty

联系我们

赏金女王(中国)官方网站 - Queen of Bounty
联系人:陈经理
手 机:13988888888
电 话:+86 0000 88888
地 址:广东省广州市番禺经济开发区

新闻动态

您的位置: 主页 > 新闻动态

PHP弱类型问题详解:Zval结构如何导致安全风险?

发布时间:2025-12-30 02:21人气:

PHP里头的弱类型特性给开发者带去了便利,不过也埋下了安全风险的种子,这般设计源自其底层实现,去理解以及警惕其机制对于编写安全代码来讲是至关重要的。

 
#!c
typedef struct _zval_struct zval;  
struct _zval_struct {  
    /* Variable information */  
    zvalue_value value;     /* value */  
    zend_uint refcount__gc;  
    zend_uchar type;    /* active type */  
    zend_uchar is_ref__gc;  
};  
typedef union _zvalue_value {  
    long lval;  /* long value */  
    double dval;    /* double value */  
    struct {  
        char *val;  
        int len;  
    } str;  
    HashTable *ht;  /* hash table value */  
    zend_object_value obj;  
} zvalue_value;

zval结构体与变量存储

在PHP里,所有变量借助zval结构体于底层引擎予以表示,此结构体涵盖两个关键部分,其一为用于标识变量类型的type字段,另一则是实际存储值那般而存在的value联合体,变量的具体内容,不管是整数,还是字符串,又或者是数组,均被封装于这个统一的容器当中。

存在这样一种设计,其优势在于达成了弱类型,对于那种类型开发者不必去显式声明便可使用变量,比如,你能够直接把字符串“123”运用到算术运算之中,然而,这种便利是以运行时额外的类型判断以及转换开销作为代价的,所有类型检查与转换的逻辑都被延迟到了代码执行的那个时刻。

 
#!php
var_dump(0 == '0'); // true
var_dump(0 == 'abcdefg'); // true  
var_dump(0 === 'abcdefg'); // false
var_dump(1 == '1abcdef'); // true 

类型判断与自动转换

PHP凭借zval.type字段来对变量当下类型予以判断,在开展运算或者比较之际,一旦类型不相匹配,引擎就会试着去进行自动转换,比如在表达式$a = "10"; $b = $a + 5;里,字符串"10"会先被转变成整数10,而后再开展计算。

 
#!php
var_dump(intval('3389a'));//输出3389

 
#!php
if($a>1000){
    mysql_query('update ... .... set value=$a')
}

有一种转换,偶尔会与开发者的直觉相违背,对于字符串“10abc”,在对其转换成整数之际,会从起始部位去解析数字,最终得到10,然而对于“abc10”,却会被转变成0,此项基于内容的隐式转换,是诸多逻辑错误的根源所在。

松散比较的潜在风险

 

#!php

在PHP当中,存在着两种比较运算符,“==”这个运算符所进行的是松散比较,“===”则是进行严格比较,进行松散比较的时候,在比较之前会先开展类型转换,比如说,0 == "abc"得到结果是真的情形,原因在于在比较期间字符串"abc"被转化成了整数 0。

处于安全敏感的相关情境里,像是判定用户输入与某个预先设定的密码能否等同,运用“==”这种方式有可能致使被绕过。要是预先设定的密码为整数0 ,那么任意不能转变为有效数字的字符串输入(像是"password" )都会被认定为相等。

 
#!php
var_dump(in_array("abc", $array));

数学运算中的类型劫持

在PHP里,当字符串参与数学运算之时,PHP会试着把它转换为数字,其规则是,转换从字符串起始的地方开始,一直到碰到非数字字符才停止,所以,"123abc" 2 的运算结果是246,然而"abc123" 2 的运算结果是0 。

这种特性存在被恶意加以利用的可能性,假定有一段代码,其运用intval($_GET[‘id‘])的方式来防范SQL注入这一情况,然而要是开发者出现错误,直接运用$_GET[‘id‘]去展开运算,当攻击者传入像"1 UNION SELECT..."此类的字符串时,在运算期间它会被当作数字1来进行处理,如此一来就有可能使得安全检查被成功绕过。

 
#!php
var_dump(in_array("abc", $array1));
var_dump(in_array("1bc", $array2));

数组的类型转换行为

数组于参与类型转换之际的行为颇为特殊,当把它转换为整数或者浮点数之时,其结果乃是其元素的个数,在转换为布尔值的时候,空数组呈现为false,而非空数组呈现为true,举例而言,(int)[1,2,3] 所产生的结果是3 。

当涉及in_array()等函数之际,要是未将第三个参数设定为true来开展严格检查,那么该函数会运用松散比较。这表明,in_array(0, ['abc'])会返回true,缘由在于字符串‘abc’在比较之时被转化成了0,此与目标值相等。

函数内部转换与安全绕过

 
#!php
$a = 'asdfgh';//字符串类型的a
echo $a[2]; //根据php的offset 会输出'd'
echo $a[x]; //根据php的预测,这里应该是int型,那么输入string,就会被intval成为0 也就是输出'a'

某些字符串处理或者比较函数的内部同样存在着类型转换,比如而言,strcmp()函数是用来用于比较两个字符串的时候,要是传入进去的是一个数组而非字符串的话,那么它将会返回NULL,在PHP的松散比较这个情况之下,NULL == 0 的这个结果是true。

要是一个登录验证逻辑,错误地运用了if (strcmp($_POST[‘password‘], $real_pwd) == 0),而攻击者借着传入一个数组当作password参数,那么就有可能致使strcmp返回NULL,进而使得条件成立,从而绕过身份验证。

倘若身为开发者,你究竟是更偏向于借助严格类型声明以及严格比较去规避风险呢,还是觉得在已经熟知规则的状况之下,弱类型的灵活性所带来的益处要大于弊端呢?欢迎于评论区交流分享你的看法以及实践经验。

 
#!php
if(!strcmp($c[1],$d) && $c[1]!==$d){
...
}

推荐资讯

在线客服
服务热线

服务热线

+86 0000 88888

微信咨询
赏金女王(中国)官方网站 - Queen of Bounty
返回顶部