2014-09-10 173 views
0

我正在使用Symfony2來實現密碼重置功能。我有關於哈希和salting確認代碼用於驗證重置請求的問題。Symfony是從哈希衍生鹽還是不是哈希鹽?

$user變量包含一個Acme\SecurityBundle\Model\User的實例。這個類的算法是bcrypt且成本15.

的Acme \ SecurityBundle \模型\用戶

namespace Acme\SecurityBundle\Model; 

use Acme\SecurityBundle\Model\om\BaseUser; 
use Symfony\Component\Security\Core\Util\SecureRandom; 

class User extends BaseUser 
{ 
    public function getSalt() 
    { 
     $random = new SecureRandom(); 
     return base64_encode($random->nextBytes(128/8)); 
    } 
} 



散列和驗證發生的控制器內部如下。


哈希:

// Generate confirmation code 
$tokenGenerator = new UriSafeTokenGenerator(); 
$resetConfirmationCodePlain = substr($tokenGenerator->generateToken(), 0, 20); 
// Hash confirmation code 
$factory = $this->get('security.encoder_factory'); 
$encoder = $factory->getEncoder($user); 
$resetConfirmationCode = $encoder->encodePassword($resetConfirmationCodePlain, $user->getSalt()); 


驗證:

// Validate confirmation code 
$factory = $this->get('security.encoder_factory'); 
$encoder = $factory->getEncoder($user); 
$isValid = $encoder->isPasswordValid(
    $user->getResetConfirmationCode(), $confirmationCode, null 
); 


正如你可以看到一個鹽而散列添加,但同時確認沒有添加。儘管如此,確認代碼已成功驗證。

有人可以解釋這一點嗎? Symfony是從哈希衍生鹽還是不是哈希鹽?

P.S.我以同樣的方式更新用戶的密碼。

+0

順便說一下,在德數據庫中的哈希值是這樣的:''$ 2Y $ 15 $ TjVaanFIV3psTlo4Y29HRexVg9nctTmXTcXeEoOZroZCgqMWroIT。'' – Stan 2014-09-10 08:35:20

+0

或者我不應該通過鹽加全部? [見BCryptPasswordEncoder.php中的這一行](https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Core/Encoder/BCryptPasswordEncoder.php#L57) – Stan 2014-09-10 09:17:24

回答

2

看一看哈希值本身...

$2y$10$nOUIs5kJ7naTuTFkBy1veuK0kSxUFXfuaOKdOKf9xYT0KKIGSJwFa 
| | |      | 
| | |      hash-value = K0kSxUFXfuaOKdOKf9xYT0KKIGSJwFa 
| | | 
| | salt = nOUIs5kJ7naTuTFkBy1veu (22 characters) 
| | 
| cost-factor = 10 = 2^10 iterations 
| 
hash-algorithm = 2y = BCrypt 

...你可以看到,鹽包括在存儲的哈希值。驗證功能可以從這個存儲的散列中讀取使用的salt和其他參數,這就是爲什麼您不必將此參數傳遞給函數。

根據Symfony的源代碼,BCryptPasswordEncoder內部使用PHP函數password_hash()。如果你省略了「salt」參數,這個函數會生成一個安全的鹽,所以我建議不要這個參數。如果你傳遞一個salt參數,函數會小心鹽的格式是有效的。

+0

「getSalt」 '方法返回一個長度爲24的base64編碼的字符串。散列中22個字符的鹽是怎樣的? 「'=」'個字符被剝離了嗎? – Stan 2014-09-10 11:32:53

+0

謝謝。我現在明白了。我會從''getSalt''返回'null'來讓PHP處理這個問題。 – Stan 2014-09-10 11:52:51

0

你在這裏一半。使用BCrypt生成的最終哈希包含密文,成本和使用的鹽。 PHP password_hash函數是通用的,並且允許你傳入一個salt(這對於某些算法是必需的),但是如果沒有提供編碼,BCrypt將生成一個,並且在解碼時可能會忽略它(因爲你可以從散列),因此可以傳入null。

因此,不僅在解碼時不需要傳遞鹽,編碼時也不應該傳遞一個,因爲BCrypt會以密碼安全的方式處理這個問題。

看到這個question和PHP文檔的password_hash()

+0

[User Provider](http://symfony.com/doc/current/cookbook/security/custom_provider.html)需要定義getSalt方法。根據該頁面底部的註釋,創建值''$ password。'''''',並且如果getSalt返回一些內容,則使用bcrypt進行哈希處理,否則只是編碼使用bcrypt。 – Stan 2014-09-10 11:36:48

+0

而且我不儲存我的鹽,那麼AP如何成功驗證哈希值?獲得值''getSalt''返回完全忽略? – Stan 2014-09-10 11:44:36

+0

我懷疑Symfony文檔頁面不準確,至少對於BCrypt。如果您查看BCrypt PasswordEncoder的源代碼,https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Core/Encoder/BCryptPasswordEncoder.php,明文密碼和salt仍然是當它們傳遞給'password_hash'時分開。因此,我們已經討論過,salt仍然可以從哈希中獲取,而當您不分開持久化鹽時,當您保存整個哈希值時,它會間接地持久化它。 – frumious 2014-09-10 12:15:19