PHP 超全局变量污染怎么解

wen PHP项目 2

本文目录导读:

PHP 超全局变量污染怎么解

  1. 输入过滤与验证(白名单验证)
  2. 转义输出(针对 XSS 攻击)
  3. 参数化查询(针对 SQL 注入)
  4. 配置层面防护
  5. 框架层面的抽象(最佳实践)
  6. 临时解决已污染的变量(魔术方法)
  7. 总结优先级

在 PHP 中,超全局变量(如 $_GET$_POST$_COOKIE$_REQUEST$_SERVER 等)的污染问题通常是指不可信数据被直接用于危险操作(如 SQL 注入、XSS 攻击、命令执行等)。

要“解”这个问题,核心原则是:永远不要信任外部输入,以下是系统的解决方案:

输入过滤与验证(白名单验证)

这是最根本的解法,不要先接收再“清理”,而是先验证“是否符合预期”。

推荐做法:

  • 类型强转$id = (int) $_GET['id'];,如果不是数字,会变成 01,杜绝注入。
  • 正则校验(白名单):
    // 只允许字母数字和下划线
    if (preg_match('/^[a-zA-Z0-9_]+$/', $_GET['username'])) {
        $username = $_GET['username'];
    } else {
        // 拒绝访问或使用默认值
        $username = 'guest';
    }
  • 过滤扩展:使用 filter_var()filter_input()
    $email = filter_input(INPUT_GET, 'email', FILTER_VALIDATE_EMAIL);
    $ip = filter_input(INPUT_SERVER, 'REMOTE_ADDR', FILTER_VALIDATE_IP);

转义输出(针对 XSS 攻击)

无论数据怎么过滤,输出到 HTML 时必须转义。

// 标准 HTML 实体转义
$safe_html = htmlspecialchars($_GET['message'], ENT_QUOTES, 'UTF-8');
echo $safe_html;

注意: 如果数据会输出到 JS、URL、CSS 等不同上下文,需要不同的编码函数(如 json_encodeurlencoderawurlencode)。

参数化查询(针对 SQL 注入)

永远不要拼接 SQL 字符串,使用预处理语句。

使用 PDO(推荐):

$pdo = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->bindParam(':id', $_GET['id'], PDO::PARAM_INT);
$stmt->execute();

或 MySQLi:

$stmt = $mysqli->prepare('SELECT * FROM users WHERE id = ?');
$stmt->bind_param('i', $_GET['id']);
$stmt->execute();

关键: 此时输入的 $_GET 字符串被当作字面量传输,数据库端拼装,绝对安全。

配置层面防护

修改 php.ini 或使用 ini_set() 来降低风险。

  • 关闭 register_globals(PHP < 5.4 老版本漏洞):将变量注册为全局变量。
    register_globals = Off
  • 设置 variables_order:控制超全局变量的注册顺序。
    variables_order = "GPCS"
  • 谨慎使用 $_REQUEST:它合并了 GETPOSTCOOKIE,极易导致逻辑混乱。建议禁用或仅用于调试
    request_order = "GP"

框架层面的抽象(最佳实践)

使用现代 PHP 框架(Laravel、Symfony、ThinkPHP 等)内置的请求对象。

// Laravel 示例
public function store(Request $request) {
    $validated = $request->validate([
        'title' => 'required|max:255',
        'body' => 'required',
    ]);
    // 业务逻辑...
}

框架会自动处理过滤、验证和上下文转义,开发者无需直接触碰丑陋的 $_GET

临时解决已污染的变量(魔术方法)

如果项目已经存在大量裸露的超全局变量,且不方便立刻重构,可以使用一个安全封装函数过渡:

function get_safe($key, $default = '') {
    if (isset($_GET[$key])) {
        // 先转义,再返回,但注意后续拼接仍需注意上下文
        return htmlspecialchars(trim($_GET[$key]), ENT_QUOTES, 'UTF-8');
    }
    return $default;
}

总结优先级

  1. 最安全:白名单验证 + 参数化查询 + 输出转义(三管齐下)。
  2. 中等安全:只用 filter_input + 类型转换。
  3. 最脆弱:直接使用 $_GET / $_REQUEST 进行 SQL 拼接或 echo

核心认知: 数据本身没有“脏”或“干净”,关键是在哪个环节、用哪种方式处理,所有超全局变量默认都应视为“恶意字符串”,只有在进入特定“执行上下文”(如 SQL、HTML、Shell)时,才针对性转化。

抱歉,评论功能暂时关闭!