本文目錄一覽:
PHP網站要防哪幾種常見方式攻擊?
常見攻擊方式:1、命令注入,2、eval注入,3、客戶端腳本攻擊,4、跨網站腳本攻擊,5、SQL注入攻擊,6、跨網站請求偽造攻擊,7、Session 會話劫持,8、Session 固定攻擊,9、HTTP響應拆分攻擊,10、文件上傳漏洞,11、目錄穿越漏洞,12、遠程文件包含攻擊,13、動態函數注入攻擊,14、URL攻擊,15、表單提交欺騙攻擊,16、HTTP請求欺騙攻擊
PHP中SESSION的問題
Session 和 Cookie 有什麼關係
Cookie 也是由於 HTTP 無狀態的特點而產生的技術。也被用於保存訪問者的身份標示和一些數據。每次客戶端發起 HTTP 請求時,會將 Cookie 數據加到 HTTP header 中,提交給服務端。這樣服務端就可以根據 Cookie 的內容知道訪問者的信息了。 可以說,Session 和 Cookie 做著相似的事情,只是 Session 是將數據保存在服務端,通過客戶端提交來的 session_id 來獲取對應的數據;而 Cookie 是將數據保存在客戶端,每次發起請求時將數據提交給服務端的。
上面提到,session_id 可以通過 URL 或 cookie 來傳遞,由於 URL 的方式比 cookie 的方式更加不安全且使用不方便,所以一般是採用 cookie 來傳遞 session_id。
服務端生成 session_id,通過 HTTP 報文發送給客戶端(比如瀏覽器),客戶端收到後按指示創建保存著 session_id 的 cookie。cookie 是以 key/value 形式保存的,看上去大概就這個樣子的:PHPSESSID=e4tqo2ajfbqqia9prm8t83b1f2。在 PHP 中,保存 session_id 的 cookie 名稱默認叫作 PHPSESSID,這個名稱可以通過 php.ini 中 session.name 來修改,也可以通過函數 session_name() 來修改。
為什麼不推薦使用 PHP 自帶的 files 型 Session 處理器
在 PHP 中,默認的 Session 處理器是 files,處理器可以用戶自己實現(參見:自定義會話管理器)。我知道的成熟的 Session 處理器還有很多:Redis、Memcached、MongoDB……
為什麼不推薦使用 PHP 自帶的 files 類型處理器,PHP 官方手冊中給出過這樣一段 Note:
無論是通過調用函數 session_start() 手動開啟會話, 還是使用配置項 session.auto_start 自動開啟會話, 對於基於文件的會話數據保存(PHP 的默認行為)而言, 在會話開始的時候都會給會話數據文件加鎖, 直到 PHP 腳本執行完畢或者顯式調用 session_write_close() 來保存會話數據。 在此期間,其他腳本不可以訪問同一個會話數據文件。
上述引用參見:Session 的基本用法
為了證明這段話,我們創建一下 2 個文件: 文件:session1.php
?php
session_start();
sleep(5);
var_dump($_SESSION);
?
文件:session2.php
?php
session_start();
var_dump($_SESSION);
?
在同一個瀏覽器中,先訪問 ,然後在當前瀏覽器新的標籤頁立刻訪問 。實驗發現,session1.php 等了 5 秒鐘才有輸出,而 session2.php 也等到了將近 5 秒才有輸出。而單獨訪問 session2.php 是秒開的。在一個瀏覽器中訪問 session1.php,然後立刻在另外一個瀏覽器中訪問 session2.php。結果是 session1.php 等待 5 秒鐘有輸出,而 session2.php 是秒開的。
分析一下造成這個現象的原因:上面例子中,默認使用 Cookie 來傳遞 session_id,而且 Cookie 的作用域是相同。這樣,在同一個瀏覽器中訪問這 2 個地址,提交給伺服器的 session_id 就是相同的(這樣才能標記訪問者,這是我們期望的效果)。當訪問 session1.php 時,PHP 根據提交的 session_id,在伺服器保存 Session 文件的路徑(默認為 /tmp,通過 php.ini 中的 session.save_path 或者函數 session_save_path() 來修改)中找到了對應的 Session 文件,並對其加鎖。如果不顯式調用 session_write_close(),那麼直到當前 PHP 腳本執行完畢才會釋放文件鎖。如果在腳本中有比較耗時的操作(比如例子中的 sleep(5)),那麼另一個持有相同 session_id 的請求由於文件被鎖,所以只能被迫等待,於是就發生了請求阻塞的情況。
既然如此,在使用完 Session 後,立刻顯示調用 session_write_close() 是不是就解決問題了哩?比如上面例子中,在 sleep(5) 前面調用 session_write_close()。
確實,這樣 session2.php 就不會被 session1.php 所阻塞。但是,顯示調用了 session_write_close() 就意味著將數據寫到文件中並結束當前會話。那麼,在後面代碼中要使用 Session 時,必須重新調用 session_start()。
例如:
?php
session_start();
$_SESSION[‘name’] = ‘Jing’;
var_dump($_SESSION);
session_write_close();
sleep(5);
session_start();
$_SESSION[‘name’] = ‘Mr.Jing’;
var_dump($_SESSION);
?
官方給出的方案:
對於大量使用 Ajax 或者並發請求的網站而言,這可能是一個嚴重的問題。 解決這個問題最簡單的做法是如果修改了會話中的變數, 那麼應該儘快調用 session_write_close() 來保存會話數據並釋放文件鎖。 還有一種選擇就是使用支持並發操作的會話保存管理器來替代文件會話保存管理器。
我推薦的方式是使用 Redis 作為 Session 的處理器。
拓展閱讀:
為什麼不能用 memcached 存儲 Session
如何使用 Redis 作為 PHP Session handler
Session 數據是什麼時候被刪除的
這是一道經常被面試官問起的問題。
先看看官方手冊中的說明:
session.gc_maxlifetime 指定過了多少秒之後數據就會被視為”垃圾”並被清除。 垃圾搜集可能會在 session 啟動的時候開始( 取決於 session.gc_probability 和 session.gc_divisor)。 session.gc_probability 與 session.gc_divisor 合起來用來管理 gc(garbage collection 垃圾回收)進程啟動的概率。此概率用 gc_probability/gc_divisor 計算得來。例如 1/100 意味著在每個請求中有 1% 的概率啟動 gc 進程。session.gc_probability 默認為 1,session.gc_divisor 默認為 100。
繼續用我上面那個不太恰當的比方吧:如果我們把物品放在超市的儲物箱中而不取走,過了很久(比如一個月),那麼保安就要清理這些儲物箱中的物品了。當然並不是超過期限了保安就一定會來清理,也許他懶,又或者他壓根就沒有想起來這件事情。
再看看兩段手冊的引用:
如果使用默認的基於文件的會話處理器,則文件系統必須保持跟蹤訪問時間(atime)。Windows FAT 文件系統不行,因此如果必須使用 FAT 文件系統或者其他不能跟蹤 atime 的文件系統,那就不得不想別的辦法來處理會話數據的垃圾回收。自 PHP 4.2.3 起用 mtime(修改時間)來代替了 atime。因此對於不能跟蹤 atime 的文件系統也沒問題了。
GC 的運行時機並不是精準的,帶有一定的或然性,所以這個設置項並不能確保舊的會話數據被刪除。某些會話存儲處理模塊不使用此設置項。
對於這種刪除機制,我是存疑的。
比如 gc_probability/gc_divisor 設置得比較大,或者網站的請求量比較大,那麼 GC 進程啟動就會比較頻繁。
還有,GC 進程啟動後都需要遍歷 Session 文件列表,對比文件的修改時間和服務端的當前時間,判斷文件是否過期而決定是否刪除文件。
這也是我覺得不應該使用 PHP 自帶的 files 型 Session 處理器的原因。而 Redis 或 Memcached 天生就支持 key/value 過期機制的,用於作為會話處理器很合適。或者自己實現一個基於文件的處理器,當根據 session_id 獲取對應的單個 Session 文件時判斷文件是否過期。
為什麼重啟瀏覽器後 Session 數據就取不到了
session.cookie_lifetime 以秒數指定了發送到瀏覽器的 cookie 的生命周期。值為 0 表示”直到關閉瀏覽器”。默認為 0。
其實,並不是 Session 數據被刪除(也有可能是,概率比較小,參見上一節)。只是關閉瀏覽器時,保存 session_id 的 Cookie 沒有了。也就是你弄丟了打開超市儲物箱的鑰匙(session_id)。
同理,瀏覽器 Cookie 被手動清除或者其他軟體清除也會造成這個結果。
為什麼瀏覽器開著,我很久沒有操作就被登出了
這個是稱為「防呆」,為了保護用戶賬戶安全的。
這個小節放進來,是因為這個功能的實現可能和 Session 的刪除機制有關(之所以說是可能,是因為這個功能不一定要借住 Session 實現,用 Cookie 也同樣可以實現)。 說簡單一點,就是長時間沒有操作,服務端的 Session 文件過期被刪除了。
一個有意思的事情
在我試驗的過程中,發現了小有意思的事情:我把 GC 啟動的概率設置為 100%。如果只有一個訪問者請求,該訪問者即使過了很久(超過了過期時間)後才發起第二次請求,那麼 Session 數據也還是存在的(’session.save_path’ 目錄下面的 Session 文件存在)。是的,明明就超過了過期時間,卻沒有被 GC 刪除。這時,我用另外一個瀏覽器訪問時(相對於另一個訪問者),這次請求生成了新的 Session 文件,而上一個瀏覽器請求生成的那個 Session 文件終於沒有了(之前那個 Session 文件在 ‘session.save_path’ 目錄下面的消失了)。
還有,發現 Session 文件被刪除後,再次請求,還是會生成和之前文件名相同的 Session 文件(因為瀏覽器並沒有關閉,再次請求發送的 session_id 是相同的,所以重新生成的 Session 文件的文件名還是一樣的)。但是,我不理解的是:這個重新出現的文件的創建時間竟然是第一次的那個創建時間,難道它是從回收站中回來的?(確實,我做這個試驗時是在 window 下進行的)
我猜測的原因是這樣:當啟動會話後,PHP 根據 session_id 找到並打開了對應的 Session 文件,然後才啟動 GC 進程。GC 進程就只檢查除了當前這個 Session 文件外的其他文件,發現過期的就幹掉。所有,即使當前這個 Session 文件已經過期了,GC 也沒有刪除它。
我認為這個不合理的。
由於發生這種情況影響也不大(畢竟線上請求很多,當前請求的過期文件被其他請求喚起的 GC 幹掉的可能性是比較大的) + 我沒有信心去看 PHP 源代碼 + 我並不在線上使用 PHP 自帶的 files 型 Session 處理器。所以,這個問題我就沒有深入研究了。請諒解。
?php
// 過期時間設置為 30 秒
ini_set(‘session.gc_maxlifetime’, ’30’);
// GC 啟動概率設置為 100%
ini_set(‘session.gc_probability’, ‘100’);
ini_set(‘session.gc_divisor’, ‘100’);
session_start();
$_SESSION[‘name’] = ‘Jing’;
var_dump($_SESSION);
?
PHP的網站主要攻擊方式有哪些
1、命令注入(Command Injection)
2、eval注入(Eval Injection)
3、客戶端腳本攻擊(Script Insertion)
4、跨網站腳本攻擊(Cross Site Scripting, XSS)
5、SQL注入攻擊(SQL injection)
6、跨網站請求偽造攻擊(Cross Site Request Forgeries, CSRF)
7、Session 會話劫持(Session Hijacking)
8、Session 固定攻擊(Session Fixation)
9、HTTP響應拆分攻擊(HTTP Response Splitting)
10、文件上傳漏洞(File Upload Attack)
11、目錄穿越漏洞(Directory Traversal)
12、遠程文件包含攻擊(Remote Inclusion)
13、動態函數注入攻擊(Dynamic Variable Evaluation)
14、URL攻擊(URL attack)
15、表單提交欺騙攻擊(Spoofed Form Submissions)
16、HTTP請求欺騙攻擊(Spoofed HTTP Requests)
原創文章,作者:SARS,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/148990.html