PHP安全:变量的前世今生
字数 1469 2025-08-15 21:31:50

PHP变量安全全面指南

变量生命周期与安全风险

PHP变量的生命周期可分为四个阶段,每个阶段都存在特定的安全风险:

  1. 传入参数阶段
  2. 变量生成阶段
  3. 变量处理阶段
  4. 变量储存阶段

Part1: 传入参数安全

1. 畸形HTTP方法绕过

  • WAF通常只检查标准HTTP方法(POST/GET)
  • 可使用任意非保留字作为HTTP方法:
    ABCDEFG /lab_value/get.php?num_value=hhh HTTP/1.1
    
    等效于:
    GET /lab_value/get.php?num_value=hhh HTTP/1.1
    

2. URL-WAF绕过技术

HPP参数污染

  • PHP中间件会以最后一个重复参数为准
  • 示例:
    /?password=admin&&pasword=' order by 1--+
    

截断绕过

  • 长度截断:WAF可能只检查前N个字符
  • 终止符截断:使用%00截断检查

数据分裂绕过

  • 分块编码传输(Transfer-Encoding: chunked)

    • 消息体由多个块组成,每个块包含:
      • 数据字节数(十六进制)
      • CRLF
      • 数据本身
      • 块CRLF结束
    • 最后一块为0字节大小
  • Pipeline绕过(Connection: keep-alive)

    • 保持连接不中断,合并多次请求

3. 参数数据类型绕过

PHP接受参数时的特殊解析规则:

输入内容 PHP解析结果
空格num_value num_value
num[value num_value
num.value num_value
Num_value 报错(大小写敏感)
num value num_value
num_value num_value
/?num_value[]=xxx 传入数组

特殊技巧:

  • 传入数组可绕过md5检查:md5(aaa[]) === md5(bbb[])

4. 编码问题

  • 双重URL编码:%27%2527
  • URL解码自动过滤%:sel%ectselect
  • Base64解码要求字符数为3的倍数

Part2: 变量生成安全

1. REQUEST变量获取

  • $_REQUEST同时获取GET和POST参数
  • 可同时发送GET和POST请求绕过部分WAF

2. extract()函数风险

  • 将数组键值对转换为变量
  • 可能导致变量覆盖,常用于CTF中覆盖白名单

3. 反序列化安全

  • unserialize()处理参数实例化为对象
  • PHP特殊性质:十六进制字符串等价
    var_dump("\x66\x6c\x61\x67" == "flag"); // true
    
  • 生成十六进制字符串脚本:
    <?php
    $string = 'flag';
    $arr = str_split(bin2hex($string), 2);
    foreach ($arr as $value) {
        print('\x'.$value);
    }
    // 输出: \x66\x6c\x61\x67
    ?>
    

4. md5二进制输出

  • md5(xxx, true)输出16位二进制数据
  • 特殊值ffifdyop会被解码为类似' or 1=1的结构

Part3: 变量处理安全

1. 弱类型比较问题

PHP弱类型比较(==)的典型问题:

var_dump("abcd" == 0);        // true
var_dump("1abcd" == 1);       // true
var_dump("abcd1" == 1);       // false
var_dump(abdc1 == 0);         // true (报错)
var_dump(False == 0);         // true
var_dump("abcd1" == 0);       // true
var_dump("0e123456" == "0e888888"); // true (科学计数法)

2. 正则匹配绕过

异或绕过

  • PHP允许字符串按ASCII编码异或
  • 异或规则:
    • 值不同 → 1
    • 值相同 → 0
  • 示例:
    3 xor 2 == 1
    2 xor 2 == 0
    

PCRE回溯次数绕过

  • 带有通配符(*或?)的正则可能回溯
  • 当回溯次数超过限制(默认100万)返回false
  • 使用===比较可避免绕过

Part4: 变量储存安全

1. 命名空间利用

  • 在回调函数前加\可绕过多数WAF
  • 示例:
    \system($_GET['cmd']);
    

2. 自定义函数绕过

  • 通过函数拼接、动态调用绕过静态检查
  • 示例:
    function x($a,$b){
        call_user_func_array($a,$b);
    }
    x('assert',array($_POST['a']));
    
    // 或拼接函数名
    $y = 'a' . 'ssert';
    

防御建议

  1. 始终使用===进行严格比较
  2. 禁用危险函数如extract()assert()
  3. 对用户输入进行严格过滤和类型检查
  4. 使用最新版PHP并保持更新
  5. 避免直接反序列化用户输入
  6. 对正则表达式进行性能优化,防止回溯攻击
  7. 使用命名空间时注意权限控制
  8. 对文件操作函数进行路径检查和过滤
PHP变量安全全面指南 变量生命周期与安全风险 PHP变量的生命周期可分为四个阶段,每个阶段都存在特定的安全风险: 传入参数阶段 变量生成阶段 变量处理阶段 变量储存阶段 Part1: 传入参数安全 1. 畸形HTTP方法绕过 WAF通常只检查标准HTTP方法(POST/GET) 可使用任意非保留字作为HTTP方法: 等效于: 2. URL-WAF绕过技术 HPP参数污染 PHP中间件会以最后一个重复参数为准 示例: 截断绕过 长度截断:WAF可能只检查前N个字符 终止符截断:使用 %00 截断检查 数据分裂绕过 分块编码传输(Transfer-Encoding: chunked) 消息体由多个块组成,每个块包含: 数据字节数(十六进制) CRLF 数据本身 块CRLF结束 最后一块为0字节大小 Pipeline绕过(Connection: keep-alive) 保持连接不中断,合并多次请求 3. 参数数据类型绕过 PHP接受参数时的特殊解析规则: | 输入内容 | PHP解析结果 | |---------|------------| | 空格num_ value | num_ value | | num [ value | num_ value | | num.value | num_ value | | Num_ value | 报错(大小写敏感) | | num value | num_ value | | num_ value | num_ value | | /?num_ value[ ]=xxx | 传入数组 | 特殊技巧: 传入数组可绕过md5检查: md5(aaa[]) === md5(bbb[]) 4. 编码问题 双重URL编码: %27 → %2527 URL解码自动过滤%: sel%ect → select Base64解码要求字符数为3的倍数 Part2: 变量生成安全 1. REQUEST变量获取 $_REQUEST 同时获取GET和POST参数 可同时发送GET和POST请求绕过部分WAF 2. extract()函数风险 将数组键值对转换为变量 可能导致变量覆盖,常用于CTF中覆盖白名单 3. 反序列化安全 unserialize() 处理参数实例化为对象 PHP特殊性质:十六进制字符串等价 生成十六进制字符串脚本: 4. md5二进制输出 md5(xxx, true) 输出16位二进制数据 特殊值 ffifdyop 会被解码为类似 ' or 1=1 的结构 Part3: 变量处理安全 1. 弱类型比较问题 PHP弱类型比较( == )的典型问题: 2. 正则匹配绕过 异或绕过 PHP允许字符串按ASCII编码异或 异或规则: 值不同 → 1 值相同 → 0 示例: PCRE回溯次数绕过 带有通配符(* 或?)的正则可能回溯 当回溯次数超过限制(默认100万)返回false 使用 === 比较可避免绕过 Part4: 变量储存安全 1. 命名空间利用 在回调函数前加 \ 可绕过多数WAF 示例: 2. 自定义函数绕过 通过函数拼接、动态调用绕过静态检查 示例: 防御建议 始终使用 === 进行严格比较 禁用危险函数如 extract() 、 assert() 对用户输入进行严格过滤和类型检查 使用最新版PHP并保持更新 避免直接反序列化用户输入 对正则表达式进行性能优化,防止回溯攻击 使用命名空间时注意权限控制 对文件操作函数进行路径检查和过滤