首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP Cookie 名稱含點號會被自動轉為底線的機制與安全啟示

     編輯:PHP 相關知識

設定 $_COOKIE['my.name'] = 1 後,實際讀取卻必須用 $_COOKIE['my_name']。這不是 Bug,是 PHP 為了相容舊版 register_globals 特意設計的「自動轉換」行為。本文深入解析原因、影響與現代最佳實踐。

實測行為

<?php
setcookie('user.name', 'John', time()+3600);
// 瀏覽器發送 Cookie: user.name=John

// PHP 端接收
var_dump($_COOKIE['user.name']); // NULL ❌
var_dump($_COOKIE['user_name']); // 'John' ✅

// $_REQUEST、$_GET、$_POST 同理:鍵名中 .、空格、[ ] 等皆會轉為 _
// 例如  → $_POST['a_b']

歷史根源:register_globals 的惡夢

PHP 4.2 以前預設開啟 register_globals = On,會將 EGPCS(Environment、Get、Post、Cookie、Server)變數直接註冊為全域變數:

// URL: ?user.name=John
// PHP 內部自動建立 $user_name = 'John';  // 合法變數名
// 若保留點號 → $user.name 會導致語法錯誤

為了讓「自動全域變數」能正常運作,PHP 強制將所有超全域陣列鍵名中的 非字母數字底線字元統一轉為底線。雖然 register_globals 已於 PHP 5.4 移除,但相容性行為保留至今。

安全啟示:為何 register_globals 是災難

<?php
// 假設開啟 register_globals
$isAdmin = false;
// 攻擊者請求 ?isAdmin=1
// → $isAdmin 變成 true,繞過權限檢查!

這類「變數汙染」漏洞極難追蹤,現代框架(Laravel、Symfony)皆在啟動期強制 ini_set('register_globals', 'Off') 並清理 $GLOBALS。

現代開發建議

  1. Cookie/表單鍵名僅使用 [a-zA-Z0-9_],避免點號、連字號、空格、中括號。
  2. 讀取時統一用轉換後的鍵名,或封裝 getCookie('user.name') 內部自動 str_replace('.', '_', $key)。
  3. 檢查 php.ini:request_order = "GP"(忽略 Cookie 覆蓋 POST/GET),variables_order = "GPCS"。
  4. 安全標頭:Set-Cookie: ...; HttpOnly; Secure; SameSite=Lax 降低 XSS/CSRF 風險。

快速對照表

原始鍵名PHP 實際鍵名建議寫法
user.nameuser_nameuser_name
data[0]data_0_data_0
my-keymy_keymy_key
a ba_ba_b

結論:了解歷史包袱,乾淨命名,才能避免莫名其妙的「讀不到 Cookie」除錯浪費時間。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved