Playframework 如何在play框架中散列密码(可能使用BCrypt)

Playframework 如何在play框架中散列密码(可能使用BCrypt),playframework,playframework-2.1,bcrypt,password-encryption,Playframework,Playframework 2.1,Bcrypt,Password Encryption,我对框架和密码哈希有点陌生。我试图找到一些散列我的密码的解决方案,我找到了BCrypt。你认为对密码进行哈希运算足够好吗。如果它是好的,我如何让它在play框架中工作?(我正在使用play 2.1.3)谢谢 下面是我编写的一个示例Play Java项目,它使用BCrypt散列密码,请参见newUser()和signIn()操作: 您可以在Scala中执行类似的操作。总之,将jbycrpt添加到Build.scala中的依赖项中: val appDependencies = Seq( &qu

我对框架和密码哈希有点陌生。我试图找到一些散列我的密码的解决方案,我找到了BCrypt。你认为对密码进行哈希运算足够好吗。如果它是好的,我如何让它在play框架中工作?(我正在使用play 2.1.3)谢谢

下面是我编写的一个示例Play Java项目,它使用BCrypt散列密码,请参见newUser()和signIn()操作:

您可以在Scala中执行类似的操作。总之,将jbycrpt添加到Build.scala中的依赖项中:

val appDependencies = Seq(
  "org.mindrot" % "jbcrypt" % "0.3m"
)
然后使用以下命令哈希密码:

String passwordHash = BCrypt.hashpw(password, BCrypt.gensalt());
BCrypt.checkpw(password, passwordHash)
并使用以下方法验证密码:

String passwordHash = BCrypt.hashpw(password, BCrypt.gensalt());
BCrypt.checkpw(password, passwordHash)
更新(2020)

在我这些天的项目中,我不再使用BCrypt,而是使用PBKDF2散列,它的优点是不需要任何额外的依赖项,但缺点是需要编写更多的代码并手动管理salt。BCrypt还存在一些问题,不同的实现无法准确地使用彼此的输出,有些实现甚至会截断长密码,这非常糟糕。尽管它的代码要多得多,但我喜欢这种方法,因为它给了我更多的控制权,并且它清楚地显示了事情是如何工作的,而且随着时间的推移,由于对哈希算法和输入参数的建议不断变化,所以可以很容易地进行更新

无论如何,这里是我使用的代码,它在散列值中存储salt和使用的迭代次数(以便按照最佳实践的建议随时间增加),用冒号分隔:

val DefaultIterations=10000
val random=new SecureRandom()
私有def pbkdf2(密码:字符串,salt:Array[Byte],迭代次数:Int):Array[Byte]={
val keySpec=new-PBEKeySpec(password.tocharray,salt,iterations,256)
val keyFactory=SecretKeyFactory.getInstance(“PBKDF2WithHmacSHA256”)
keyFactory.GenerateCret(keySpec).getEncoded
}
def hashPassword(密码:字符串,salt:数组[字节]):字符串={
val salt=新数组[字节](16)
随机。下一字节(盐)
val hash=pbkdf2(密码、salt、默认迭代次数)
val salt64=Base64.getEncoder.encodeToString(salt)
val hash64=Base64.getEncoder.encodeToString(哈希)
s“$DefaultIterations:$hash64:$salt64”
}
def checkPassword(密码:字符串,密码哈希:字符串):布尔={
passwordHash.split(“:”)匹配{
case数组(it、hash64、salt64)如果it.forall(u.isDigit)=>
val hash=Base64.getDecoder.decode(hash64)
val salt=Base64.getDecoder.decode(salt64)
val calculatedHash=pbkdf2(密码、salt、it.toInt)
calculatedHash.SameeElements(哈希)
case other=>sys.error(“错误密码哈希”)
}
}

我的实际代码稍微复杂一点,我包括一个版本化的magic word作为第一个组件(
ph1:
),这意味着如果我决定更改哈希算法或其他未在输出值中编码的输入参数,我可以通过将magic word更新为
ph2:
,对这些哈希进行编码,然后我可以用代码验证旧的
ph1
和新的
ph2
散列。

BCrypt很适合散列密码。使用并使用密码插件。

此项目提供了一个很好的围绕jbcrypt的scala包装器-在过去使用过它,效果很好。

以下是最新的bcrypt t3hnar库版本4.1使用Play框架的说明:

将依赖项添加到build.sbt:

libraryDependencies += "com.github.t3hnar" %% "scala-bcrypt" % "4.1"
将哈希对象添加到项目中:

// Reference: https://github.com/t3hnar/scala-bcrypt

package utilities

import com.github.t3hnar.bcrypt._
import play.api.Logging
import scala.util.Success
import scala.util.Failure

object Hash extends Logging {

  private val log = Log.get

  def create(value: String): String = {

    log.debug("Encrypting a value")
    // Creating a salted hash
    val salt = generateSalt
    val hash = value.bcrypt(salt)
    // return hashed value
    hash

  }

  def validate(value: String, hash: String): Boolean = {

    // Validating the hash
    value.isBcryptedSafe(hash) match {
      case Success(result) => { // hash is valid - correct salt and number of rounds
        log.trace("Hash is safe")
        if (result) log.trace("Test hash matches stored hash") else log.trace("Test hash does not match stored hash")
        result // true if test hash matches the stored has, false if it does not
      }
      case Failure(failure) => {
        // Hash is invalid
        log.trace("Hash is not safe")
        false
      }
    }

  }

}
使用示例:

// Password hashing
val hash = Hash.create(password)

// Password validation
def authenticate(email: String, password: String): Option[User] = {

    log.debug(s"Authenticating user: $email")

    // Get user
    read(email) match {
      case Some(user) => {
        // Compare password with the hashed value
        if (Hash.validate(password, user.hash)) Some(user) else None
      }
      case None => {
        // Cannot find user with this email
        log.trace(s"User not found")
        None
      }
    }
  }
请访问查看更多信息

哈希实用程序示例:


用户模型示例:

如果BCrypt使用salt创建哈希,您需要向用户模型添加salt,不是吗?在您的示例中,“salt”没有这样的字段。不,BCrypt在其输出的值中包含纯salt。我不是100%确定格式,但它应该是类似于“randomsalthere:saltedhashhere”的东西。因此,它只需首先解析值,提取salt和散列,然后使用散列和salt进行密码检查。