- 相關推薦
PHP中使用會話控制
會話控制的思想是指能夠在網(wǎng)站中根據(jù)一個會話跟蹤用戶,下面是小編整理的PHP中使用會話控制,希望大家喜歡。
PHP中使用會話控制
1、什么是會話控制
HTTP是一種無狀態(tài)協(xié)議,它的內(nèi)部沒有一個內(nèi)建機制來維護兩個事務之間的狀態(tài)。當一個用戶在請求一個頁面后再請求另一個頁面,HTTP將無法告訴我們這兩個請求時來自同一個用戶。
會話控制的思想是指能夠在網(wǎng)站中根據(jù)一個會話跟蹤用戶,這樣可以很容易的做到對用戶登錄的支持,并根據(jù)其授權級別和個人喜好顯示相應的內(nèi)容,我們可以根據(jù)會話控制記錄該用戶行為,還可以實現(xiàn)購物車。
2、理解基本的會話功能
PHP的會話是通過唯一的會話ID來驅動的,會話ID是一個加密的隨機數(shù)字。它由PHP生成,在會話的生命周期中會保存在客戶端,它可以保存在用戶機器里的cookie中,或者通過URL在網(wǎng)絡上傳遞。
會話ID就像一把鑰匙,它允許我們注冊一些特定的變量,也成為會話變量。這些變量的內(nèi)容會保存在服務器端。會話ID是客戶端唯一可見信息。如果在一次特定的網(wǎng)站鏈接中,客戶端可以通過cookie或URL看到會話ID,那么我們就可以訪問該會話保存在服務器中的會話變量。在默認情況下,會話變量保存在服務器上的普通文件中。
把會話ID保存在URL中,如果在URL中有一串看起來像隨機數(shù)字的字符串,可能它就是某種形式的會話控制。
cookie是與會話不同的解決方案,它也解決了在多個事務之間保持狀態(tài)的問題,同時還可以保持一個整潔的URL。
會話控制過程:用戶登錄或者第一次瀏覽某個站點的頁面時,該站點會生成一個PHP的會話ID并通過cookie發(fā)送到客戶端(瀏覽器)。當用戶點擊該站點的另一個頁面時,瀏覽器開始連接這個URL。在連接之前,瀏覽器會先搜索本地保存的cookie,如果在cookie中有任何與正在連接的URL相關的cookie,就將它提交到服務器。而剛好在登陸或第一次連接時,已經(jīng)產(chǎn)生了一個與該網(wǎng)站URL相關的cookie(保存的會話ID),所以當用戶再次連接這個站點時,站點就可以通過這個會話ID識別出用戶,從服務器的會話文件中取出與這個會話ID相關的會話變量,從而保持事務之間的連續(xù)。
3、什么是Cookie
cookie是在服務器端被創(chuàng)建并寫回到客戶端瀏覽器,瀏覽器接到響應頭中關于寫cookie的指令則在本地臨時文件夾中。創(chuàng)建了一個cookie文件,其中保存了你的cookie內(nèi)容,cookie內(nèi)容的存儲是鍵值對的方式,鍵和值都只能是字符串。
cookie其實就是一小段信息,它可以由腳本在客戶端機器保存。可以通過發(fā)送一個包含特定數(shù)據(jù)并且具有如下格式的HTTP標題頭,從而在用戶端機器設置一個cookie:
Set-Cookie:NAME = VALUE; [expires=DATE;] [path=PATH;] [domain=DOAMIN_NAME;] [secure]
這會創(chuàng)建一個名為NAME,值為VALUE的cookie。除了該參數(shù),其它參數(shù)都是可選的。expires域設置該cookie的失效日期(如果不設置失效日期將永遠有效,除非手動刪除)。path和domain域結合起來制定URL或與cookie有關的URL。secure的關鍵字的意思是在普通的HTTP連接中不發(fā)動cookie。
當瀏覽器連接一個URL時,首先要搜索當?shù)乇4娴腸ookie。如果有任何與正在連接的URL相關的cookie,瀏覽器將它提交到服務器。
4、什么是Session
Session是由應用服務器維持的一個服務器端的存儲空間,用戶在連接服務器時,會由服務器創(chuàng)建生成一個唯一的sessionID,用該sessionID為標識符來存取服務器端的Session存儲空間,在會話期間,分配給客戶端的唯一sessionID,用來標識當前用戶,與其他用戶進行區(qū)分。通過SessionID接受每一次訪問的請求,從而識別當前用戶,跟蹤和保持用戶的具體資料,以及session變量,可在session中存儲數(shù)字或文字資料.比如session_name.這些信息都保存在服務器端。當然,sessionID也可以作為會話信息保存到數(shù)據(jù)庫中,進行session持久化。這樣可以跟蹤用戶的登陸次數(shù)、在線與否、在線時間等從而維護HTTP無狀態(tài)事物之間的關系。session的內(nèi)容存儲是鍵值對的列表,鍵是字符串類型,session的存儲更方便,值可以是對象。
在session會話期間,session會分別保存在客戶端和服務器端兩個文件,客戶端可以是cookie方式保存的sessionID(默認的保存方式)或通過url字符串形式傳遞。服務器端一般以文本的形式保存在指定的session目錄中。在服務器端我們可以通過session.use_cookies來控制客戶端使用哪一種保存方式。如果定義為cookie保存方式,我們可以通過session.cookie_lifetime(默認值0,閉瀏覽器就清除)來控制被保存在client上的cookie的有效期。而如果客戶端用cookie方式保存的sessionID,則使用“臨時”的cookie保存(cookie的名稱為PHPSESSID,通過Firebug你可以了解到詳細的信息,該名稱你可以通過php.ini session.name進行更改),用戶提交頁面時,會將這一SessionID提交到服務器端,來存取session數(shù)據(jù)。這一過程,是不用開發(fā)人員干預的。
5、SESSION和COOKIE的區(qū)別與聯(lián)系
相同點:都可以在解決HTTP無狀態(tài)的問題,使同一個客戶端在訪問網(wǎng)站的多次請求中,可以保存,設置信息,并且在請求事物之間建立聯(lián)系。
不同點:簡單的說cookie的信息保存在客戶端,session的信息保存在服務器端。
Session采用鍵值對,也就是說ID存放客戶端,而值放在服務器端,是通過用戶的ID去找服務器上對應的值,這種方式值放置在服務器端,有個時間限制,時間到則服務器自動回收/釋放。
Cookies則有兩種方法,一種方法是把值保存在瀏覽器的變量中,當瀏覽器關閉時結束,另一種方法是保存在硬盤中,只要時間不過期,下次還可使用。
聯(lián)系:當客戶端使用基于Cookie方式保存的SessionID時,SessionID一般保存在cookie中。
備注:cookie在相同內(nèi)核的瀏覽器之間是共享的,不同內(nèi)核瀏覽器是不共享的例如火狐和IE(存放位置都不同,當然不共享)。不同內(nèi)核瀏覽器不能共享cookie,也會產(chǎn)生不同sessionid。
PHP中使用會話控制
會話管理基礎
會話安全
會話模塊無法保證你存儲在會話中的信息只能被創(chuàng)建會話的用戶本人可見。 你需要采取額外的手段來保護會話中的機密信息, 至于采取何種方式來保護機密信息, 取決于你在會話中存儲的數(shù)據(jù)的機密程度。
評估會話中存儲的數(shù)據(jù)的重要性, 以及為此增加額外的保護機制, 通常需要付出一定的代價,同時會降低便利性。 例如,如果你需要保護用戶免受社會工程學攻擊, 你需要啟用session.use_only_cookies選項。 這就要求用戶在使用過程中,必須把瀏覽器設置為接受 cookie, 否則就無法正常使用會話功能了。
有很多種方式都可以導致會話 ID 被泄露給第三方。 例如,JavaScript 注入,URL 中包含會話 ID,數(shù)據(jù)包偵聽, 或者直接訪問你的物理設備等。 如果會話 ID 被泄漏給第三方, 那么他們就可以訪問這個會話 ID 可以訪問的全部資源。 首先,如果在 URL 中包含了會話 ID, 并且訪問了外部的站點, 那么你的會話 ID 可能在外部站點的訪問日志中被記錄(referrer 請求頭)。 另外,攻擊者也可以監(jiān)聽你的網(wǎng)絡通信,如果通信未加密, 那么會話 ID 將會在網(wǎng)絡中以明文的形式進行傳輸。 針對這種情況的解決方案就是在服務端配置 SSL/TLS, 另外,使用 HSTS 可以達到更高的安全性。
注意:即使使用 HTTPS 協(xié)議,也無法百分百保證機密數(shù)據(jù)不被泄漏。 例如,CRIME 和 BEAST 漏洞可以使得攻擊者讀取到你的數(shù)據(jù)。 另外,出于網(wǎng)絡通信審計目的,很多網(wǎng)絡中都存在 HTTPS MITM 代理, 可以讀取 HTTPS 協(xié)議下的通信數(shù)據(jù)。 那么攻擊者也可以搭建類似的代理服務器,用來竊取 HTTPS 協(xié)議下的通信數(shù)據(jù)。
非自適應會話管理
目前,默認情況下,PHP 是以自適應的方式來管理會話的, 這種方式使用起來很靈活,但是同樣也帶來了一定的風險。
新增加了一個配置項:session.use_strict_mode。 當啟用這個配置項,并且你所用的會話存儲處理器支持的話,未經(jīng)初始化的會話 ID 會被拒絕, 并為其生成一個全新的會話,這可以避免攻擊者使用一個已知的會話 ID 來進行攻擊。 例如,攻擊者可以通過郵件給受害者發(fā)送一個包含會話ID 的鏈接: http://example.com/page.php?PHPSESSID=123456789。 如果啟用了session.use_trans_sid配置項, 那么受害者將會使用攻擊者所提供的會話 ID 開始一個新的會話。 如果啟用了session.use_strict_mode選項,就可以降低風險。
警告
用戶自定義的會話存儲器也可以通過實現(xiàn)會話 ID 驗證來支持嚴格會話模式。 建議用戶在實現(xiàn)自己的會話存儲器的時候, 一定要對會話 ID 的合法性進行驗證。
在瀏覽器一側,可以為用來保存會話 ID 的 cookie 設置域,路徑, 僅允許 HTTP 訪問,必須使用 HTTPS 訪問等安全屬性。 如果使用的是 PHP 7.3. 版本,還可以對 cookie 設置 SameSite 屬性。 攻擊者可以利用瀏覽器的這些特性來設置永久可用的會話 ID。 僅僅設置session.use_only_cookies配置項 無法解決這個問題。而session.use_strict_mode配置項 可以降低這種風險。設置session.use_strict_mode=On, 來拒絕未經(jīng)初始化的會話 ID。
注意:雖然使用session.use_strict_mode配置項 可以降低靈活會話管理方式所帶來的風險, 攻擊者還是通過利用 JavaScript 注入等手段, 強制用戶使用由攻擊者創(chuàng)建的并且經(jīng)過了正常的初始化的會話 ID。 如何降低這種風向,可以參考本手冊的建議部分。如果你已經(jīng)啟用了session.use_strict_mode配置項, 同時使用基于時間戳的會話管理, 并且通過設置session_regenerate_id()配置項 來重新生成會話 ID, 那么,攻擊者生成的會話 ID 就可以被刪除掉了。當發(fā)生對過期會話訪問的時候, 你應該保存活躍會話的所有數(shù)據(jù), 以備后續(xù)分析使用。 然后讓用戶退出當前的會話,并且重新登錄。 防止攻擊者繼續(xù)使用“偷”來的會話。
警告
對過期會話數(shù)據(jù)的訪問并不總是意味著正在遭受攻擊。 不穩(wěn)定的網(wǎng)絡狀況,或者不正確的會話刪除行為, 都會導致合法的用戶產(chǎn)生訪問過期會話數(shù)據(jù)的情況。
從 PHP 7.1.0 開始,增加了session_create_id()函數(shù)。 這個函數(shù)允許開發(fā)者在會話 ID 中增加用戶 ID 作為前綴, 以確保用戶訪問到正確對應的會話數(shù)據(jù)。 要使用這個函數(shù), 請確保啟用了session.use_strict_mode配置項, 否則惡意用戶可能會偽造其他用戶的會話 ID。
注意:對于 PHP 7.1.0 之前的用戶,應該使用CSPRNG(例如/dev/urandom) 或者random_bytes()函數(shù)以及哈希函數(shù) 來產(chǎn)生新的會話 ID。session_create_id()函數(shù)本身包含碰撞檢測的能力, 并且根據(jù) INI 文件中和會話相關的配置項來生成會話 ID。 所以,建議使用session_create_id()函數(shù)來生成會話 ID。
重新生成會話 ID
雖然session.use_strict_mode配置項可以降低風險,但是還不夠。為了確保會話安全,開發(fā)者還需要使用session_regenerate_id()函數(shù)。
會話 ID 重生機制可以有效的降低會話被竊取的風險, 所以,必須周期性的調用session_regenerate_id()函數(shù) 來重新生成會話 ID, 例如,對于機密內(nèi)容,每隔 15 分鐘就重新生成會話 ID。 這樣一來,即使會話 ID 被竊取, 那么攻擊者所得到的會話 ID 也會很快的過期, 如果他們進一步訪問,就會產(chǎn)生對過期會話數(shù)據(jù)訪問的錯誤。
當用戶成功通過認證之后,必須為其重新生成會話 ID。 并且,必須在向$_SESSION中保存用戶認證信息之前 調用session_regenerate_id()函數(shù)(session_regenerate_id()函數(shù) 會自動將重生之前的會話數(shù)據(jù)保存到新生成的會話)。 請確保只有新的會話包含用戶認證信息。
開發(fā)者不可過分依賴session.gc_maxlifetime配置項。 因為攻擊者可以在受害者的會話過期之前訪問系統(tǒng), 并且維持這個會話的活動,以保證這個會話不會過期。
實際上,你需要自己實現(xiàn)基于時間戳的會話數(shù)據(jù)管理機制。
警告
雖然會話處理程序可以透明的管理時間戳,但是這個特性尚未完整的實現(xiàn)。 在 GC 發(fā)生之前,舊的會話數(shù)據(jù)還得保存, 同時,開發(fā)者還得保證過期的會話數(shù)據(jù)已經(jīng)被移除。 但是,開發(fā)者又不能立即移除活躍會話中的數(shù)據(jù)。 所以,不要同時在活躍會話上調用session_regenerate_id(true);
和session_destroy()函數(shù)。 這聽起來有點兒自相矛盾,但是事實上必須得這么做。
默認情況下,session_regenerate_id()函數(shù)不會刪除舊的會話, 所以即使重生了會話 ID,舊的會話可能還是可用的。 開發(fā)者需要使用時間戳等機制, 來確保舊的會話數(shù)據(jù)不會再次被訪問。
警告
刪除活躍會話可能會帶來非預期的一些影響。 例如,在網(wǎng)絡狀態(tài)不穩(wěn)定,或者有并發(fā)請求到達 Web 服務器的情況下, 立即刪除活躍會話可能導致個別請求會話失效的問題。
立即刪除活躍會話也無法檢測可能存在的惡意訪問。
作為替代方案, 你要在$_SESSION中設置一個很短的過期時間, 然后根據(jù)這個時間戳來判斷后續(xù)的訪問是被允許的還是被禁止的。
在調用session_regenerate_id()函數(shù)之后, 不能立即禁止對舊的會話數(shù)據(jù)的訪問,應該再一小段之間之后再禁止訪問。 例如,在穩(wěn)定的網(wǎng)絡條件下,可以設置為幾秒鐘, 在不穩(wěn)定的網(wǎng)絡條件下,可以設置為幾分鐘。
如果用戶訪問了舊的會話數(shù)據(jù)(已經(jīng)過期的), 那么應該禁止訪問。 建議從會話中移除這個用戶的認證信息,因為這看起來像是在遭受攻擊。
如果攻擊者設置了不可刪除的 cookie,那么使用session.use_only_cookies和session_regenerate_id()會導致正常用戶遭受拒絕服務的問題。 如果發(fā)生這種情況,請讓用戶刪除 cookie 并且警告用戶他可能面臨一些安全問題。 攻擊者可以通過惡意的 Web 應用、瀏覽器插件以及對安全性較差的物理設備進行攻擊 來偽造惡意的 cookie。
警告
請勿誤解這里的拒絕服務攻擊風險所指的含義。 通常來講,要保護會話 ID 的安全,session.use_strict_mode=On 是必須要做的。 建議所有的站點都啟用session.use_strict_mode。
只有當賬號處于被攻擊的時候,才會發(fā)生拒絕服務的問題。 通常都是由于應用中被注入了惡意的 JavaScript 才會導致這個問題。
會話中數(shù)據(jù)的刪除
過期的會話中的數(shù)據(jù)應該是被刪除的,并且不可訪問。 現(xiàn)在的會話模塊尚未很好的支持這種特性。
應該盡可能快的刪除過期會話中的數(shù)據(jù)。 但是,活躍會話一定不要立即刪除。 為了能夠同時滿足這兩點要求, 你需要自己來實現(xiàn)基于時間戳的會話數(shù)據(jù)管理機制。
在 $_SESSION 中設置會話過期時間戳,并且對其進行管理, 以便能夠阻止對于過期會話的訪問。 當發(fā)生對于過期會話的訪問時,建議從相關用戶的所有會話中刪除認證信息, 并且要求用戶重新認證。 對于過期會話數(shù)據(jù)的訪問可能是一種攻擊行為, 為了保護會話數(shù)據(jù),你需要追蹤每個用戶的活躍會話。
注意:當用戶處于不穩(wěn)定的網(wǎng)絡,或者 web 應用存在并發(fā)的請求的時候, 也可能發(fā)生對于過期會話數(shù)據(jù)的訪問。 服務器嘗試為用戶設置新的會話 ID, 但是很可能由于網(wǎng)絡原因,導致 Set-Cookie 的數(shù)據(jù)包無法到達用戶的瀏覽器。 當通過session_regenerate_id()函數(shù) 為一個連接生成新的會話 ID 之后,其他的并發(fā)連接可能尚未得到這個新的會話 ID。 因此,不能立即阻止對于過期會話數(shù)據(jù)的訪問,而是要延遲一個很小的時間段, 這就是為什么我們需要實現(xiàn)基于時間戳的會話管理。
簡而言之,不要在調用session_regenerate_id()或者session_destroy()函數(shù)的時候立即刪除舊的會話數(shù)據(jù), 而是要通過一個時間戳來控制后續(xù)對于這個舊會話數(shù)據(jù)的訪問。 從會話存儲中刪除數(shù)據(jù)的工作交給session_gc()函數(shù)來完成吧。
會話和鎖定
默認情況下,為了保證會話數(shù)據(jù)在多個請求之間的一致性, 對于會話數(shù)據(jù)的訪問是加鎖進行的。
但是,這種鎖定機制也會導致被攻擊者利用,來進行對于用戶的拒絕服務攻擊。 為了降低這種風險,請在訪問會話數(shù)據(jù)的時候,盡可能的縮短鎖定的時間。 當某個請求不需要更新會話數(shù)據(jù)的時候,使用只讀模式訪問會話數(shù)據(jù)。 也就是說,在調用session_start()函數(shù)的時候, 使用 read_and_close 選項:session_start([read_and_close=>1]);
。 另外,如果需要更新會話數(shù)據(jù),那么在更新完畢之后, 馬上調用session_commit()函數(shù)來釋放對于會話數(shù)據(jù)的鎖。
當會話不活躍的時候,當前的會話模塊不會檢測對于 $_SESSION 的修改。 你需要自己來保證 在會話處于不活躍狀態(tài)的時候,不要去修改它。
活躍會話
開發(fā)者需要自己來追蹤每個用戶的活躍會話, 要知道每個用戶創(chuàng)建了多少活躍會話,每個活躍會話來自那個 IP 地址, 活躍了多長時間等。 PHP 不會自動完成這項工作,需要開發(fā)者來完成。
有很多種方式可以做到追蹤用戶的活躍會話。 你可以通過在數(shù)據(jù)庫中存儲會話信息來跟蹤用戶會話。 由于會話是可以被垃圾收集器收集掉的, 所以你也需要處理被收集掉的會話數(shù)據(jù), 以保證數(shù)據(jù)庫中的數(shù)據(jù)和真實的活躍會話數(shù)據(jù)的一致性。
一種很簡單的方式就是使用“使用用戶 ID 作為會話 ID 前綴”,并且保存必要的信息到 $_SESSION 中。 大部分的數(shù)據(jù)庫產(chǎn)品對于字符串前綴查詢(譯注:也即右模糊查詢,可以利用索引)都有很好的性能表現(xiàn)。 為了實現(xiàn)這種方式,可以使用session_regenerate_id()和session_create_id()函數(shù)。
警告
永遠不要使用機密數(shù)據(jù)作為會話 ID 前綴! 如果用戶 ID 屬于機密數(shù)據(jù),那么可以考慮使用hash_hmac()函數(shù)對其進行摘要后再使用。
警告
必須啟用session.use_strict_mode配置項。 請確保已經(jīng)啟用, 否則活躍會話數(shù)據(jù)庫可能會被入侵。
要能夠檢測對于過期會話數(shù)據(jù)的訪問, 基于時間戳的會話數(shù)據(jù)管理機制是必不可少的。 當檢測到對于過期會話數(shù)據(jù)的訪問時,你應該從相關用戶的活躍會話中刪除認證信息, 避免攻擊者持續(xù)使用盜取的會話。
會話和自動登錄
開發(fā)者不應該通過使用長生命周期的會話ID來實現(xiàn)自動登錄功能, 因為這種方式提高了會話被竊取的風險。 開發(fā)者應該自己實現(xiàn)自動登錄的機制。
在使用setcookie()的時候,傳入安全的一次性摘要結果作為自動登錄信息。 建議使用比 SHA-2 更高強度的摘要算法(例如 SHA-256) 對random_bytes()隨機生成的數(shù)據(jù) (也可以讀取/dev/urandom設備)進行摘要作為自動登錄的信息。
在用戶訪問的時候,如果發(fā)現(xiàn)用戶尚未認證, 那么就去檢查請求中是否包含了有效的一次性登錄信息。 如果包含有效的一次性登錄信息,那么就去認證用戶,并且重新生成新的一次性登錄信息。 自動登錄的關鍵信息一定是只能使用一次,永遠不要重復使用一次性登錄信息。
自動登錄信息是長生命周期的認證信息, 所以必須要盡可能的妥善保護。 可以對于自動登錄信息對應的 cookie 設置路徑、僅允許 HTTP 訪問、僅允許安全訪問 等屬性來加以保護,并且僅在必需的時候才傳送這個 cookie。
開發(fā)者也要提供禁用自動登錄的機制, 以及刪除不再需要的自動登錄數(shù)據(jù)的能力。
CSRF(跨站請求偽造)
會話和認證無法避免跨站請求偽造攻擊。 開發(fā)者需要自己來實現(xiàn)保護應用不受 CSRF 攻擊的功能。
output_add_rewrite_var()函數(shù)可以用來 保護應用免受 CSRF 攻擊。更多信息請參考文檔。
注意:PHP 7.2.0 之前的版本,這個函數(shù)和會話 ID 使用了同樣的輸出緩沖以及 INI 設置項, 所以不建議在 PHP 7.2.0 之前使用output_add_rewrite_var()函數(shù)。
大部分 Web 應用框架都提供了 CSRF 保護的特性。 詳細信息請參考你所用的 Web 框架的文檔。
從 PHP 7.3 開始,對于會話 cookie 增加了 SameSite 屬性, 這個屬性可以有效的降低 CSRF 攻擊的風險。
【PHP中使用會話控制】相關文章:
PHP中的trait是什么04-12
PHP中的Division by zero報錯處理技巧02-23
Word中各種通配符的使用09-18
在Dreamweaver中如何使用模板10-26
PHP基本語法04-29
php環(huán)境搭建06-11
PHP常量介紹04-21
PHP的基本作用03-17