PHP中的session安全嗎?

jopen 8年前發布 | 12K 次閱讀 PHP HTML

如果不做特殊處理,僅是使用PHP中原生的session的話,確實不安全。PHP只是為我們提供了一個session的實現,后續的安全工作需要程序員自己靈活去掌握,所以說PHP編程真的很靈活。

做PHP開發這么長時間,還真沒有真正關注過安全的問題,每次都是以完成項目為主,最近在網上看到了一篇關于安全的文章,看完以后才注意到自己以前的項目都存在著很大的安全漏洞,于是挑了一個項目進行了測試,發現很容易就中招兒了。在這里我會分享自己寫的一個測試的例子來說明PHP中的session是如何不安全的,以及在項目中如何加強其安全性。

對于session的原理機制,網上有很多好的文章來介紹,我們可以自行查閱。下面直接分享測試用的例子。

這個測試的例子主要就是一個登錄頁,登錄成功以后可以修改密碼,就這樣一個簡單的功能。

界面如下

PHP中的session安全嗎?

PHP中的session安全嗎?

首先是在項目入口的地方使用函數 session_start() 開啟了session。這樣當客戶端發起請求的時候,會產生一個身份標識 也就是 SessionID。通過cookie的方式保存在客戶端,客戶端和服務端每次的通信都是靠這個SessionID來進行身份識別的。

登錄成功以后,會將 用戶id、用戶名存入session中

$_SESSION[‘userid’] = 用戶id$_SESSION[‘uname’] = 用戶名

以后所有的操作都是通過判斷 $_SESSION[‘userid’]是否存在來檢查用戶是否登錄。代碼如下:

if ( isset ( $_SESSION ['userid']))   return true ;

對于修改密碼接口的調用是通過ajax  post的方式將數據傳輸到服務端的。

$.post("接口*******",

{

oldpass:oldpass,

newpass:newpass,

userid:uid,

},

function (data){

data = eval('(' +data+ ')');

$('.grant_info').html(infos[data.info]).show();

}

);

注意,我這里將這段代碼寫在了html頁面中,所以說如果看到了html代碼,也就知道了接口地址了。

修改密碼的接口是這樣實現的,首先是判斷用戶是否登錄,如果登錄才會進行密碼的修改操作。

測試例子的實現思路大概就是上面介紹的那樣。

利用SessionID攻擊

1. 首先是獲取SessionID,當然攻擊者獲取此標識的方式有很多,由于我的水平有限,至于如何獲取我在這里不做介紹。我們可以模擬一下,先正常訪問此項目,然后通過瀏覽器查看SessionID,以此得到一個合法的用戶標識。可以在請求頭中看到此項ID

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Encoding: gzip, deflate

Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3

Connection: keep-alive

Cookie: Hm_lvt_bf1154ec41057869fceed66e9b3af5e7=1450428827,1450678226,1450851291,1450851486; PHPSESSID=2eiq9hcpu3ksri4r587ckt9jt7;

Host: ******

Referer: ******

User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:41.0) Gecko/20100101 Firefox/41.0

得到sessionID以后,如果此用戶登錄成功,那么服務端的session里就有此用戶的信息了。

2. 獲取到SessionID以后,假如攻擊者已經知道修改密碼的接口,就可以直接修改此用戶的密碼了。如果攻擊者還沒有得到接口地址,可以通過查看頁面代碼找出接口地址。可以使用如下的命令

#curl --cookie "PHPSESSID=2eiq9hcpu3ksri4r587ckt9jt7" 頁面地址

上面我們說過,在此例子中ajax代碼是寫在html頁面中的,所以在此頁面可以查看到接口地址

部分html代碼如下

<html xmlns= "http://www.w3.org/1999/xhtml" >

<head>

……

var   uid = $(".userid").val();

$.post("/User/User/modifypass_do",

{

oldpass:oldpass,

newpass:newpass,

userid:uid,

},

function (data){

data = eval('(' +data+ ')');

$('.grant_info').html(infos[data.info]).show();

}

);

……

<span><input type= "password"   name= "oldpass"   id= "textfield_o"   placeholder= " 原密碼 " ></span>

<span><input type= "password"   name= "newpass"   id= "textfield_n"   placeholder= " 新密碼 " ></span>

<span><input type= "password"   name= "confirmpass"   id= "textfield_c"   placeholder= " 確認密碼 " ></span>

<input type= "button"   class= " btn_ok "   value= " 確認修改 "

/>

3. 得到接口以后可以通過curl 模擬post發送數據來修改密碼

命令如下

# curl --cookie "PHPSESSID=2eiq9hcpu3ksri4r587ckt9jt7" -d oldpass=111111 -d newpass=000000 -d userid=用戶id  接口地址

如果此用戶已經登錄,那么攻擊者可以通過執行以上命令修改用戶的密碼。

解決方法

對于以上方式的攻擊,我們可以通過使驗證方式復雜化來加強其安全性。其中一種方式就是利用請求頭中的User-Agent項來加強其安全性

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Encoding: gzip, deflate

Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3

Connection: keep-alive

Cookie: Hm_lvt_bf1154ec41057869fceed66e9b3af5e7=1450428827,1450678226,1450851291,1450851486; PHPSESSID=2eiq9hcpu3ksri4r587ckt9jt7;

Host: ******

Referer: ******

User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:41.0) Gecko/20100101 Firefox/41.0

在項目開始的時候最初我們只是用了session_start()函數來開啟session。現在我們可以在session_start() 下面 添加這段代碼

$_SESSION[‘User_Agent’] = md5($_SERVER[‘HTTP_USER_AGENT’]);

然后在每次判斷是否登錄的時候,添加判斷條件如下

If(isset($_SESSION[‘userid’]) && $_SESSION[‘User_Agent’] == md5($_SERVER[‘HTTP_USER_AGENT’])){

return true;

}

這樣就可以避免上述簡單的攻擊

總結:

當然,實際情況中的攻擊遠非這么簡單,首先在獲取SessionID這一步就比較困難,然后就是和服務端交互的代碼盡量加密,可以避免上述的情況。在我們第二次修改代碼以后,可以增加攻擊的復雜程度,并不能杜絕攻擊。攻擊的方式多種多樣,這里只是一種簡單的方式,僅提供一種思路,但是原理是一樣的,在實際情況中可以根據實際情況增強我們代碼的安全程度。由于我的水平有限,這里只是分享自己在工作中碰到的問題,權當拋磚引玉,如果大家有什么好的意見,請在下面留言,共同討論,共同提高。

來自: http://www.lupaworld.com/article-256767-1.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!