### 介绍下 PHP 的变量覆盖

有几个 PHP 函数在不安全地使用时，极易引发变量覆盖漏洞

**1. `extract()`**

`extract()`函数从一个数组中导入变量到当前的符号表。它会**根据数组的键名创建同名的变量**，并将键值赋给这些新变量

- **漏洞示例：**

  ```php
  <?php
  $username = 'guest';
  $password = '123456';
  
  // 从 $_GET 中导入变量，但没有做任何过滤
  extract($_GET); 
  
  if ($username === 'admin' && $password === 'mypassword') {
      echo 'Login successful as admin!';
  } else {
      echo 'Login failed.';
  }
  ?>
  ```

  在这个例子中，攻击者可以通过URL `?username=admin&password=mypassword` 来覆盖 `$username` 和 `$password` 这两个变量，从而绕过身份验证

- **安全建议：** 使用 `extract()` 时，务必指定第二个参数 `$flags` 为 `EXTR_SKIP` 或 `EXTR_PREFIX_ALL`，以防止覆盖现有变量。例如：`extract($_GET, EXTR_SKIP);`

**2. `parse_str()`**

`parse_str()`函数用于解析URL参数字符串，并将其作为变量导入到当前作用域

- **漏洞示例：**

  ```php
  <?php
  $username = 'guest';
  
  // 将请求的参数字符串解析为变量
  parse_str($_SERVER['QUERY_STRING']); 
  
  if ($username === 'admin') {
      echo 'Hello admin!';
  }
  ?>
  ```

  攻击者可以通过 `?username=admin` 来覆盖 `$username` 变量

- **安全建议：** 始终将 `parse_str()` 的第二个参数设置为一个数组变量，这样解析的结果会存入该数组，而不是直接创建全局变量。例如：`parse_str($_SERVER['QUERY_STRING'], $query_data);`

**3. `import_request_variables()`**

这个函数在PHP 5.4.0 版本后被移除。它的功能是把 `$_GET`、`$_POST` 或 `$_COOKIE` 中的变量导入到全局作用域。由于其固有的安全风险，**不应再使用**

**4. `$$` （双重美元符）**

双重美元符是一种特殊的变量语法，它会将一个变量的值作为另一个变量的名称

- **漏洞示例：**

  ```php
  <?php
  $name = 'default';
  
  foreach ($_GET as $key => $value) {
      // 动态地创建变量名
      $$key = $value;
  }
  
  echo "Hello, " . $name;
  ?>
  ```

  如果URL为 `?name=hacker`，`$key` 的值为 `name`，`$value` 的值为 `hacker`。那么 `$$key` 实际上就是 `$name`，它的值被设置为 `hacker`。攻击者可以通过这种方式覆盖 `$name` 变量

- **安全建议：** 避免在没有严格过滤的情况下使用双重美元符来动态创建变量