php 安全基礎 第四章 會話與 Cookies

來源:互聯網
上載者:User
本章主要討論會話和有狀態的Web應用的內在風險。你會首先學習狀態、cookies、與會話;然後我會討論關於cookie盜竊、會話資料暴露、會話固定、及工作階段劫持的問題及防範它們的方法。

  正如大家知道的,HTTP是一種無狀態的協議。這說明了兩個HTTP請求之間缺乏聯絡。由於協議中未提供任何讓用戶端標識自己的方法,因此伺服器也就無法區分用戶端。

  雖然HTTP無狀態的特性還是有一些好處,畢竟維護狀態是比較麻煩的,但是它向需要開發有狀態的Web應用的開發人員提出了前所未有的挑戰。由於無法標識用戶端,就不可能確認使用者是否已登入,在購物車中加入商品,或者是需要註冊。

  一個最初由網景公司構思的超強解決方案誕生了,它就是被命名為cookies的一種狀態管理機制。Cookies是對HTTP協議的擴充。更確切地說,它們由兩個HTTP頭部組成:Set-Cookie回應標頭部和Cookie要求標頭部。

  當用戶端發出對一個特定URL的請求時,伺服器會在響應時選擇包含一個Set-Cookie頭部。它要求用戶端在下面的請求中包含一個相就的Cookie頭部。圖4-1說明了這個基本的互動過程。

 

圖4-1. 兩個HTTP事務間Cookie的完整互動過程

 

 

  如果你根據這個基本概念在每一個請求中包含同一個唯一標識碼(在cookie頭部中),你就能唯一標識用戶端從而把它發出的所有請求聯絡起來。這就是狀態所要求的,同時也是這一機制的主要應用。

 

小提示

迄今為止,最好的cookies使用指南依然是網景公司提供的規範,網址是:http://wp.netscape.com/newsref/std/cookie_spec.html 。它是最類似和接近於全行業支援的標準。

 

  基於會話管理的概念,可以通過管理每一個用戶端的各自資料來管理狀態。資料被儲存在會話儲存區中,通過每一次請求進行更新。由於會話記錄在儲存時有唯一的標識,因此它通常被稱為會話標識。

 

  如果你使用PHP內建的會話機制,所有的這些複雜過程都會由PHP為你處理。當   你調用函數session_start()時,PHP首先要確認在本次請求中是否包含會話標識。如果有的話,PHP就會讀取該會話資料並通過$_SESSION超級公用數組提供給你。如果不存在,PHP會產生一個會話標識並在會話儲存區建立一個新記錄。PHP還會處理會話標識的傳遞並在每一個請求時更新會話儲存區。圖4-2示範了這個過程。

 

  雖然這很簡便有效,但最重要的還是要意識到這並不是一個完整的解決方案,因為在PHP的會話機制中沒有內建的安全處理。除此之外,由於會話標識是完全隨機產生的,因此是不可預測的。你必須自行建立安全機制以防止所有其它的會話攻擊手段。在本章中,我會提出一些問題,並提供相應的解決方案。

 

4.1. Cookie 盜竊

  因使用Cookie而產生的一個風險是使用者的cookie會被攻擊者所盜竊。如果會話標識儲存在cookie中,cookie的暴露就是一個嚴重的風險,因為它能導致工作階段劫持。

 

圖4-2. PHP為你處理相關會話管理的複雜過程

最常見的cookie暴露原因是瀏覽器漏洞和跨站指令碼攻擊(見第2章)。雖然現在並沒有已知的該類瀏覽器漏洞,但是以往出現過幾例,其中最有名的一例同時發生在IE瀏覽器的4.0,5.0,5.5及6.0版本(這些漏洞都有相應補丁提供)。

 

雖然瀏覽器漏洞的確不是web開發人員的錯,但是你可以採取步驟以減輕它對使用者的威脅。在某些情況下,你可能通過使用一些安全措施有效地消除風險。至少你可以告訴和指導使用者打上修正漏洞的安全補丁。

  基於以上原因,知道新的安全性漏洞是很有必要的。你可以跟蹤下面提供的幾個網站和郵件清單,同時有很多服務提供了RSS推送,因此只要訂閱RSS即可以得到新安全性漏洞的警告。SecurityFocus網站維護著一系列軟體漏洞的列表(http://online.securityfocus.com/vulnerabilities),你可以通過開發商、主題和版本進行檢索。PHP安全協會也維護著SecurityFocus的所有最新通知。(http://phpsec.org/projects/vulnerabilities/securityfocus.html)

  跨站指令碼攻擊是攻擊者盜竊cookie的更為常見的手段。其中之一已有第二章中描述。由於用戶端指令碼能訪問cookies,攻擊者所要的送是寫一段傳送資料的指令碼即可。唯一能限制這種情況發生的因素只有攻擊者的創造力了。

  防止cookie盜竊的手段是通過防止跨站指令碼漏洞和檢測導致cookie暴露的瀏覽器漏洞相結合。由於後者非常少見(此類漏洞將來也會比較罕見),所以它並不是需要關心的首要問題,但還是最好要緊記。

4.2. 會話資料暴露

  會話資料常會包含一些個人資訊和其它敏感性資料。基於這個原因,會話資料的暴露是被普遍關心的問題。一般來說,暴露的範圍不會很大,因為會話資料是儲存在伺服器環境中的,而不是在資料庫或檔案系統中。因此,會話資料自然不會公開暴露。

  使用SSL是一種特別有效手段,它可以使資料在伺服器和用戶端之間傳送時暴露的可能性降到最低。這對於傳送敏感性資料的應用來說非常重要。SSL在HTTP之上提供了一個保護層,以使所有在HTTP請求和應答中的資料都得到了保護。

  如果你關心的是會話資料儲存區本身的安全,你可以對會話資料進行加密,這樣沒有正確的密鑰就無法讀取它的內容。這在PHP中非常容易做到,你只要使用session_set_save_handler( )並寫上你自己的session加密儲存和解密讀取的處理函數即可。

4.3. 會話固定

  關於會話,需要關注的主要問題是會話標識的保密性問題。如果它是保密的,就不會存在工作階段劫持的風險了。通過一個合法的會話標識,一個攻擊者可以非常成功地冒充成為你的某一個使用者。

 

  一個攻擊者可以通過三種方法來取得合法的會話標識:

 

l        猜測

l        捕獲

l        固定

 

  PHP產生的是隨機性很強的會話標識,所以被猜測的風險是不存在的。常見的是通過捕獲網路通訊資料以得到會話標識。為了避免會話標識被捕獲的風險,可以使用SSL,同時還要對瀏覽器漏洞及時修補。

 

小提示

  要記住瀏覽器會根據請求中的Set-cookie頭部中的要求對之後所有的請求中都包含一個相應的Cookie頭部。最常見的是,會話標識會無謂的在對一些嵌入資源片的請求中被暴露。例如,請求一個包含10個圖片的網頁時,瀏覽器會發出11個帶有會話標識的請求,但只有一個是有必要帶有標識的。為了防止這種無謂的暴露,你可以考慮把所有的嵌入資源放在有另外一個網域名稱的伺服器上。

 

  會話固定是一種誘騙受害者使用攻擊者指定的會話標識的攻擊手段。這是攻擊者擷取合法會話標識的最簡單的方法。

  在這個最簡單的例子中,使用了一個連結進行會話固定攻擊:

 

  <a href="http://example.org/index.php?PHPSESSID=1234">Click Here</a>

 

另外一個方法是使用一個協議層級的轉向語句:

 

  <?php

 

  header('Location: http://example.org/index.php?PHPSESSID=1234');

 

  ?>

 

  這也可以通過Refresh頭部來進行,產生該頭部的方法是通過真正的HTTP頭部或meta標籤的http-equiv屬性指定。攻擊者的目標是讓使用者訪問包含有攻擊者指定的會話標識的URL。這是一個基本的攻擊的第一步,完整的攻擊過程見圖4-3所示。

 

Figure 4-3. 使用攻擊者指定的會話標識進行的會話固定攻擊

 

如果成功了,攻擊者就能繞過抓取或猜測合法會話標識的需要,這就使發起更多和更危險的攻擊成為可能。

  為了更好地使你理解這一步驟,最好的辦法是你自己嘗試一下。首先建立一個名為fixation.php的指令碼:

 

  <?php

 

  session_start();

  $_SESSION['username'] = 'chris';

 

  ?>

 

  確認你沒有儲存著任何當前伺服器的cookies,或通過清除所有的cookies以確保這一點。通過包含PHPSESSID的URL訪問fixation.php:

 

  http://example.org/fixation.php?PHPSESSID=1234

 

  它建立了一個值為chris的會話變數username。在檢查會話儲存區後發現1234成為了該資料的會話標識:

 

  $ cat /tmp/sess_1234

  username|s:5:"chris";

 

  建立第二段指令碼test.php,它在$_SESSION[‘username’]        存在的情況下即輸入出該值:

  <?php

 

  session_start();

 

  if (isset($_SESSION['username']))

  {

    echo $_SESSION['username'];

  }

 

  ?>

 

 

  在另外一台電腦上或者在另一個瀏覽器中訪問下面的URL,同時該URL指定了相同的會話標識:

 

  http://example.org/test.php?PHPSESSID=1234

 

  這使你可以在另一台電腦上或瀏覽器中(模仿攻擊者所在位置)恢複前面在fixation.php中建立的會話。這樣,你就作為一個攻擊者成功地劫持了一個會話。

  很明顯,我們不希望這種情況發生。因為通過上面的方法,攻擊者會提供一個到你的應用的連結,只要通過這個連結對你的網站進行訪問的使用者都會使用攻擊者所指定的會話標識。

  產生這個問題的一個原因是會話是由URL中的會話標識所建立的。當沒有指定會話標識時,PHP就會自動產生一個。這就為攻擊者大開了方便之門。幸運的是,我們以可以使用session_regenerate_id( )函數來防止這種情況的發生。

 

  <?php

 

  session_start();

 

  if (!isset($_SESSION['initiated']))

  {

    session_regenerate_id();

    $_SESSION['initiated'] = TRUE;

  }

 

  ?>

 

  這就保證了在會話初始化時能有一個全新的會話標識。可是,這並不是防止會話固定攻擊的有效解決方案。攻擊者能簡單地通過訪問你的網站,確定PHP給出的會話標識,並且在會話固定攻擊中使用該會話標識。

  這確實使攻擊者沒有機會去指定一個簡單的會話標識,如1234,但攻擊者依然可以通過檢查cookie或URL(依賴於標識的傳遞方式)得到PHP指定的會話標識。該流程4-4所示。

  該圖說明了會話的這個弱點,同時它可以協助你理解該問題涉及的範圍。會話固定只是一個基礎,攻擊的目的是要取得一個能用來劫持會話的標識。這通常用於這樣的一個系統,在這個系統中,攻擊者能合法取得較低的許可權(該權限等級只要能登入即可),這樣劫持一個具有較高許可權的會話是非常有用的。

  如果會話標識在許可權等級有改變時重建,就可以在事實上避開會話固定的風險:

 

  <?php

 

  $_SESSION['logged_in'] = FALSE;

 

  if (check_login())

  {

    session_regenerate_id();

    $_SESSION['logged_in'] = TRUE;

  }

 

  ?>

 

Figure 4-4. 通過首先初始化會話進行會話固定攻擊

 

 

小提示

 

  我不推薦在每一頁上重建會話標識。雖然這看起來確實是一個安全的方法。但與在許可權等級變化時重建會話標識相比,並沒有提供更多的保護手段。更重要的是,相反地它還會對你的合法使用者產生影響,特別是會話標識通過URL傳遞時尤甚。使用者可能會使用瀏覽器的訪問曆史機制去訪問以前訪問的頁面,這樣該頁上的連結就會指向一個不再存在的會話標識。

 

  如果你只在許可權等級變化時重建會話標識,同樣的情況也有可以發生,但是使用者在存取權限變更前的頁面時,不會因為會話丟失而奇怪,同時,這種情況也不常見。

 

4.4. 工作階段劫持

  最常見的針對會話的攻擊手段是工作階段劫持。它是所有攻擊者可以用來訪問其它人的會話的手段的總稱。所有這些手段的第一步都是取得一個合法的會話標識來偽裝成合法使用者,因此保證會話標識不被泄露非常重要。前面幾節中關於會話暴露和固定的知識能協助你保證會話標識只有伺服器及合法使用者才能知道。

 

  深度防範原則(見第一章)可以用在會話上,當會話標識不幸被攻擊者知道的情況下,一些不起眼的安全措施也會提供一些保護。作為一個關心安全的開發人員,你的目標應該是使前述的偽裝過程變得更複雜。記住無論多小的障礙,都會以你的應用提供保護。

 

  把偽裝過程變得更複雜的關鍵是加強驗證。會話標識是驗證的首要方法,同時你可以用其它資料來補充它。你可以用的所有資料只是在每個HTTP請求中的資料:

 

  GET / HTTP/1.1

  Host: example.org

  User-Agent: Firefox/1.0

  Accept: text/html, image/png, image/jpeg, image/gif, */*

  Cookie: PHPSESSID=1234

 

  你應該意識到請求的一致性,並把不一致的行為認為是可疑行為。例如,雖然User-Agent(發出本請求的瀏覽器類型)頭部是可選的,但是只要是發出該頭部的瀏覽器通常都不會變化它的值。如果你一個擁有1234的會話標識的使用者在登入後一直用Mozilla Firfox瀏覽器,突然轉換成了IE,這就比較可疑了。例如,此時你可以用要求輸入密碼方式來減輕風險,同時在誤判時,這也對合法使用者產生的衝擊也比較小。你可以用下面的代碼來檢測User-Agent的一致性:

 

  <?php

 

  session_start();

 

  if (isset($_SESSION['HTTP_USER_AGENT']))

  {

    if ($_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT']))

    {

      /* Prompt for password */

      exit;

    }

  }

  else

  {

    $_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);

  }

 

  ?>

 

  我觀察過,在某些版本的IE瀏覽器中,使用者正常訪問一個網頁和重新整理一個網頁時發出的Accept頭部資訊不同,因此Accept頭部不能用來判斷一致性。

 

  確保User-Agent頭部資訊一致的確是有效,但如果會話標識通過cookie傳遞(推薦方式),有道理認為,如果攻擊者能取得會話標識,他同時也能取得其它HTTP頭部。由於cookie暴露與瀏覽器漏洞或跨站指令碼漏洞相關,受害者需要訪問攻擊者的網站並暴露所有頭部資訊。所有攻擊者要做的只是重建頭部以防止任何對頭部資訊一致性的檢查。

 

  比較好的方法是產生在URL中傳遞一個標記,可以認為這是第二種驗證的形式(雖然更弱)。使用這個方法需要進行一些編程工作,PHP中沒有相應的功能。例如,假設標記儲存在$token中,你需要把它包含在所有你的應用的內部連結中:

 

  <?php

 

  $url = array();

  $html = array();

 

  $url['token'] = rawurlencode($token);

  $html['token'] = htmlentities($url['token'], ENT_QUOTES, 'UTF-8');

 

  ?>

 

  <a href="index.php?token=<?php echo $html['token']; ?>">Click Here</a>

 

  為了更方便地管理這個傳遞過程,你可能會把整個請求串放在一個變數中。你可以把這個變數附加到所有連結後面,這樣即便你一開始沒有使用該技巧,今後還是可以很方便地對你的代碼作出變化。

 

  該標記需要包含不可預測的內容,即便是在攻擊者知道了受害者瀏覽器發出的HTTP頭部的全部資訊也不行。一種方法是產生一個隨機串作為標記:

 

<?php

 

  $string = $_SERVER['HTTP_USER_AGENT'];

  $string .= 'SHIFLETT';

 

  $token = md5($string);

  $_SESSION['token'] = $token;

 

  ?>

 

  當你使用隨機串時(如SHIFLETT),對它進行預測是不現實的。此時,捕獲標記將比預測標記更為方便,通過在URL中傳遞標記和在cookie中傳遞會話標識,攻擊時需要同時抓取它們二者。這樣除非攻擊者能夠察看受害者發往你的應用所有的HTTP請求原始資訊才可以,因為在這種情況下所有內容都暴露了。這種攻擊方式實現起來非常困難(所以很罕見),要防止它需要使用SSL。

 

  有專家警告不要依賴於檢查User-Agent的一致性。這是因為伺服器叢集中的HTTPProxy 伺服器會對User-Agent進行編輯,而本群集中的多個Proxy 伺服器在編輯該值時可能會不一致。

  如果你不希望依賴於檢查User-Agent的一致性。你可以產生一個隨機的標記:

 

  <?php

 

  $token = md5(uniqid(rand(), TRUE));

  $_SESSION['token'] = $token;

 

  ?>

 

  這一方法的安全性雖然是弱一些,但它更可靠。上面的兩個方法都對防止工作階段劫持提供了強有力的手段。你需要做的是在安全性和可靠性之間作出平衡。

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.