PHP 程式設計/會話
會話 允許 PHP 指令碼在 Web 伺服器上儲存資料,這些資料可以在以後使用,即使是在對不同 PHP 頁面請求之間也是如此。每個會話都有一個不同的識別符號,該識別符號作為 cookie 或 $_GET 變數傳送到客戶端的瀏覽器。會話在使用者關閉瀏覽器或 Web 伺服器刪除會話資訊或程式設計師顯式銷燬會話時結束。在 PHP 中,它通常被稱為 **PHPSESSID**。會話對於保護使用者無法讀取或寫入的資料非常有用,尤其是當 PHP 開發人員不想在 cookie 中提供資訊時,因為 cookie 非常容易讀取。會話可以透過 $_SESSION 超全域性變數來控制。儲存在此陣列中的資料在整個會話中都是持久的。它是一個簡單的陣列。會話比 cookie 更容易使用,這為 PHP 開發人員提供了很大幫助。大多數情況下,會話用於使用者登入、購物車和其他保持瀏覽順暢所需的附加功能。PHP 指令碼可以輕鬆控制正在傳送的會話的 cookie,並控制整個會話資料。會話始終儲存在一個唯一的檔名中,要麼在臨時資料夾中,要麼在特定資料夾中(如果指令碼指示這樣做)。
在每個將成為當前會話一部分的 PHP 指令碼的頂部,必須有函式 session_start()。它必須在第一個輸出(echo 或其他)之前,否則將導致錯誤“標頭已傳送”。
session_start();
此函式將執行以下操作
- 它將檢查
_COOKIE或_GET資料,如果已給出 - 如果會話檔案不存在於
session.save_path位置,它將- 生成一個新的唯一識別符號,並且
- 根據該識別符號建立一個新檔案,並且
- 向客戶端的瀏覽器傳送一個 cookie
- 如果存在,PHP 指令碼將嘗試將檔案的資料儲存到
_SESSION變數中以供進一步使用
現在,您可以簡單地透過兩種不同的方式設定變數,預設方法
$_SESSION['example'] = "Test";
或棄用方法
$example="Test";
session_register($example);
以上兩個語句都將註冊會話變數 $_SESSION['example'] 為“Test”。棄用方法不應該使用,它只是列出,因為您仍然可以在由不知道新方法的程式設計師編寫的指令碼中看到它。預設方法是首選方法。
PHP 會話易於控制,並且可以透過一些小的因素使其更安全或更不安全。以下是一些可以使用 php_ini() 函式輕鬆更改的執行時選項
| 名稱 | 預設值 | 可更改 |
session.save_path |
"/tmp" |
PHP_INI_ALL
|
session.name |
"PHPSESSID" |
PHP_INI_ALL
|
session.save_handler |
"files" |
PHP_INI_ALL
|
session.auto_start |
"0" |
PHP_INI_ALL
|
session.gc_probability |
"1" |
PHP_INI_ALL
|
session.gc_divisor |
"100" |
PHP_INI_ALL
|
session.gc_maxlifetime |
"1440" |
PHP_INI_ALL
|
session.serialize_handler |
"php" |
PHP_INI_ALL
|
session.cookie_lifetime |
"0" |
PHP_INI_ALL
|
session.cookie_path |
"/" |
PHP_INI_ALL
|
session.cookie_domain |
"" |
PHP_INI_ALL
|
session.cookie_secure |
"" |
PHP_INI_ALL
|
session.use_cookies |
"1" |
PHP_INI_ALL
|
session.use_only_cookies |
"0" |
PHP_INI_ALL
|
session.referer_check |
"" |
PHP_INI_ALL
|
session.entropy_file |
"" |
PHP_INI_ALL
|
session.entropy_length |
"0" |
PHP_INI_ALL
|
session.cache_limiter |
"nocache" |
PHP_INI_ALL
|
session.cache_expire |
"180" |
PHP_INI_ALL
|
session.use_trans_sid |
"0" |
PHP_INI_SYSTEM/PHP_INI_PERDIR
|
session.bug_compat_42 |
"1" |
PHP_INI_ALL
|
session.bug_compat_warn |
"1" |
PHP_INI_ALL
|
session.hash_function |
"0" |
PHP_INI_ALL
|
session.hash_bits_per_character |
"4" |
PHP_INI_ALL
|
url_rewriter.tags |
"a=href,area=href,frame=src,input=src,form=fakeentry" |
PHP_INI_ALL
|
此使用的簡單示例是此程式碼
//Setting The Session Saving path to "sessions", '''must be protected from reading'''
session_save_path("sessions"); // This function is an alternative to ini_set("session.save_path","sessions");
//Session Cookie's Lifetime ( not effective, but use! )
ini_set("session.cookie_lifetime",time()+60*60*24*500);
//Change the Session Name from PHPSESSID to SessionID
session_name("SessionID");
//Start The session
session_start();
//Set a session cookie ( Required for some browsers, as settings that had been done before are not very effective
setcookie(session_name(), session_id(), time()+3600*24*365, "/");
此示例只是為下一年設定 cookie。
當用戶單擊“登出”或“退出”時,您通常希望銷燬所有登入資料,以便任何人都無法再訪問它。會話檔案將被簡單地刪除,以及透過以下方式取消設定的 cookie
session_destroy();
諸如整數、字串和陣列之類的簡單資料可以輕鬆地儲存在 $_SESSION 超全域性陣列中,並從一個頁面傳遞到另一個頁面。但是,嘗試透過賦值儲存物件的狀態時會出現問題。物件狀態可以透過使用 serialize() 函式儲存在會話中。serialize() 將把物件資料寫入一個數組,然後可以將其儲存在 $_SESSION 超全域性變數中。unserialize() 可用於在嘗試訪問當前會話一部分的頁面中的物件之前還原物件的狀態。如果物件要在會話期間跨多個頁面訪問使用,則必須在呼叫 unserialize() 之前定義物件定義。在序列化和反序列化物件時,可能會出現其他問題。
會話固定描述了一種攻擊方式,其中惡意第三方設定(即固定)使用者的會話識別符號(SID),因此能夠訪問該使用者的會話。在會話的基礎級實現中,如上所述,這是一個非常真實的漏洞,每個使用會話進行任何敏感操作的 PHP 程式都應採取措施來解決它。以下是按適用範圍排序的,用於防止會話固定的措施
- 不要使用 GET 或 POST 變數來儲存會話 ID(在大多數 PHP 配置中,cookie 用於儲存 SID,因此程式設計師無需執行任何操作即可實現此功能);
- 在每個使用者請求時重新生成 SID(在會話開始時使用
session_regenerate_id()); - 使用會話超時:對於每個使用者請求,儲存當前時間戳,並在下一個請求中檢查是否已超過超時間隔;
- 提供登出功能;
- 在每個請求中檢查“瀏覽器指紋”。這是一個儲存在
$_SESSION變數中的雜湊值,包含使用者代理標頭、客戶端 IP 地址、鹽值和/或其他資訊的某種組合。有關此詳細資訊的更多討論,請參見下文;有些人認為它無非是“透過模糊來獲得安全性”。[待辦事項] - 檢查推薦來源:這並不適用於所有系統,但如果您知道您網站的使用者必須來自某個已知域,那麼您可以丟棄與來自其他地方的使用者繫結的會話。它依賴於使用者代理提供推薦來源標頭,這不能假定。
$timeout = 3 * 60; // 3 minutes
$fingerprint = md5('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT']);
session_start();
if ( (isset($_SESSION['last_active']) && (time() > ($_SESSION['last_active']+$timeout)))
|| (isset($_SESSION['fingerprint']) && $_SESSION['fingerprint']!=$fingerprint)
|| isset($_GET['logout']) ) {
do_logout();
}
session_regenerate_id();
$_SESSION['last_active'] = time();
$_SESSION['fingerprint'] = $fingerprint;
do_logout() 函式銷燬會話資料並取消設定會話 cookie。