2013-03-08 37 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

相关问题