2013-03-08 129 views
3

我在我的網站mydomain.com/forums上運行了一個論壇,該論壇使用了Vanilla Framework。使用Vanilla論壇對Cookie進行身份驗證

但是,我希望在該論壇上註冊的用戶能夠在我的網站的其他頁面mydomain.com/blog上發表評論。所以我需要一種檢查用戶是否登錄的方法,或者如果沒有,則提供一種向他們提供Vanilla登錄框的方法。

我的香草代碼根本不在我的博客頁面上,所以我需要一些額外的腳本。在大量的挖掘之後,我在網上找到了這個,https://gist.github.com/lincolnwebs/700805,如果登錄的話,它給出了user_id,如果沒有登錄,則給出0。所以它看起來工作得很好,因爲我不必包含整個香草框架。

腳本似乎在檢查用戶瀏覽器上的cookie值。有人可以僞造cookie的價值並獲得對某人帳戶的訪問權嗎?

作爲一個相對的新手,有人可以解釋,如果這是一個安全可靠的方式來驗證用戶登錄?我花了很長時間才發現這一點,而且似乎隱藏起來/沒有公佈。此外,該腳本不是100%完美的,因爲它在靜態函數中使用$ this。

感謝

<?php 
/** 
* @copyright Vanilla Forums Inc. 
* @license GNU GPL2 
*/ 

/** 
* Instantiating this class will store current user's ID from cookie as $this->UserID. 
*/ 
class VanillaIdentity { 

    # Copy these from Vanilla config 
    public $CookieName = 'Vanilla'; 
    public $CookieSalt = ''; 
    public $CookieHashMethod = 'md5'; 
    public $UserID = 0; 

    /** 
    * Returns the unique id assigned to the user in the database (retrieved 
    * from the session cookie if the cookie authenticates) or FALSE if not 
    * found or authentication fails. 
    * 
    * @return int 
    */ 
    public function __construct() {   
     if (!$this->_CheckCookie($this->CookieName)) return 0; 

     list($UserID, $Expiration) = $this->GetCookiePayload($this->CookieName); 

     if (!is_numeric($UserID) || $UserID < -2) // allow for handshake special id 
     $this->UserID = 0; 
     else 
     $this->UserID = $UserID; 
    } 

    public static function GetCookiePayload($CookieName) { 
     if (!self::CheckCookie($CookieName)) return FALSE; 

     $Payload = explode('|', $_COOKIE[$CookieName]); 

     // Get rid of check fields like HashKey, HMAC and Time 
     array_shift($Payload); 
     array_shift($Payload); 
     array_shift($Payload); 

     return $Payload; 
    } 

    protected function _CheckCookie($CookieName) { 
     return self::CheckCookie($CookieName); 
    } 

    public static function CheckCookie($CookieName) { 

     if (empty($_COOKIE[$CookieName])) { 
     return FALSE; 
     } 

     $CookieHashMethod = $this->CookieHashMethod; 
     $CookieSalt = $this->CookieSalt; 

     $CookieData = explode('|', $_COOKIE[$CookieName]); 
     if (count($CookieData) < 5) { 
     return FALSE; 
     } 

     list($HashKey, $CookieHash, $Time, $UserID, $Expiration) = $CookieData; 
     if ($Expiration < time() && $Expiration != 0) { 
     return FALSE; 
     } 

     $Key = self::_Hash($HashKey, $CookieHashMethod, $CookieSalt); 
     $GeneratedHash = self::_HashHMAC($CookieHashMethod, $HashKey, $Key); 

     if ($CookieHash != $GeneratedHash) { 
     return FALSE; 
     } 

     return TRUE; 
    } 

    /** 
    * Returns $this->_HashHMAC with the provided data, the default hashing method 
    * (md5), and the server's COOKIE.SALT string as the key. 
    * 
    * @param string $Data The data to place in the hash. 
    */ 
    protected static function _Hash($Data, $CookieHashMethod, $CookieSalt) { 
     return Gdn_CookieIdentity::_HashHMAC($CookieHashMethod, $Data, $CookieSalt); 
    } 

    /** 
    * Returns the provided data hashed with the specified method using the 
    * specified key. 
    * 
    * @param string $HashMethod The hashing method to use on $Data. Options are MD5 or SHA1. 
    * @param string $Data The data to place in the hash. 
    * @param string $Key The key to use when hashing the data. 
    */ 
    protected static function _HashHMAC($HashMethod, $Data, $Key) { 
     $PackFormats = array('md5' => 'H32', 'sha1' => 'H40'); 

     if (!isset($PackFormats[$HashMethod])) 
     return false; 

     $PackFormat = $PackFormats[$HashMethod]; 
     // this is the equivalent of "strlen($Key) > 64": 
     if (isset($Key[63])) 
     $Key = pack($PackFormat, $HashMethod($Key)); 
     else 
     $Key = str_pad($Key, 64, chr(0)); 

     $InnerPad = (substr($Key, 0, 64)^str_repeat(chr(0x36), 64)); 
     $OuterPad = (substr($Key, 0, 64)^str_repeat(chr(0x5C), 64)); 

     return $HashMethod($OuterPad . pack($PackFormat, $HashMethod($InnerPad . $Data))); 
    } 

} 
+0

你使用什麼框架來認證mydomain.com/blog? – Michael 2013-03-12 17:12:49

+0

這基本上是問題的關鍵。我目前沒有對博客進行任何身份驗證,但我想使用Vanilla的用戶管理軟件,所以我想使用Vanilla在我的論壇之外對用戶進行身份驗證。 – Lars 2013-03-12 17:30:21

回答

2

我不是香草和JavaScript專家。我很好理解HTTP身份驗證和SSO,我會盡力澄清你的一些問題。

首先,在HTTP身份驗證之後,應用程序將用戶cookie設置爲瀏覽器。 在下一次請求時,瀏覽器向服務器發送一個cookie。請注意,在cookie集合中使用哪條路徑很重要。如果路徑是「/」,瀏覽器會將cookie發送到服務器上的所有應用程序。

cookie可以被劫持並用於訪問應用程序。請注意,黑客可能不會解密cookie - 只是使用它。請參閱以下鏈接:https://www.owasp.org/index.php/Session_hijacking_attack。爲了防止會話劫持,您可以使用HTTPS。

解決你的問題,你需要 1)使用相同的用戶資源庫既爲mydomain.com/forums和mydomain.com/blog 在這種情況下用戶「鮑勃」將是這兩個應用程序相同的用戶。 2)確保Vanilla設置路徑爲「/' 的cookie在這種情況下,瀏覽器同時爲mydomain.com/forums和mydomain.com/blog發送cookie。

我發現下面的香草插件 - 它可以完全解決你的問題: http://vanillaforums.org/page/SingleSignOn

希望它能幫助。如果您需要任何額外的說明,請發表評論。

+1

同意。即使您可以在不解密cookie的情況下劫持會話,您也必須對其進行加密以防止其他攻擊。 VanillaIdentity和SingleSingOn(jsConnect)都使用md5(默認)或sha1。兩者都[已損壞](http://ehash.iaik.tugraz.at/wiki/The_Hash_Function_Zoo)。所以你可以調整這些庫來使用scrypt或者bcrypt,或者將它們配置爲使用sha1並且希望獲得最好的結果。 – serans 2013-03-18 14:11:19

+0

感謝您的回答。使用scrpt或bcrypt可以保護cookie不被劫持嗎? – Lars 2013-03-19 01:23:50

+0

保護cookie劫持最安全的方法是使用HTTPS – Michael 2013-03-19 05:37:51

相關問題