26

私はフレームワークとパスワードハッシュをプレイするのが少し新しいです。パスワードをハッシュ化するための解決策をいくつか見つけようとしたところ、BCrypt が見つかりました。パスワードをハッシュするのに十分だと思いますか。それがよければ、どうすれば play フレームワークで動作させることができますか? (私は play 2.1.3 を使用しています) ありがとう!

4

4 に答える 4

50

これは、BCrypt を使用してパスワードをハッシュする、私が作成した Play Java プロジェクトのサンプルです。 newUser() および signIn() アクションを参照してください。

https://github.com/jroper/play-demo-twitbookplus/blob/master/app/controllers/UserController.java

Scalaでも同様のことができます。要約すると、Build.scala の依存関係に jbycrpt を追加します。

val appDependencies = Seq(
  "org.mindrot" % "jbcrypt" % "0.3m"
)

次に、これを使用してパスワードをハッシュします。

String passwordHash = BCrypt.hashpw(password, BCrypt.gensalt());

そして、これを使用してパスワードを確認します:

BCrypt.checkpw(password, passwordHash)

アップデート (2020)

最近の私のプロジェクトでは、BCrypt を使用しなくなり、PBKDF2 ハッシュを使用しています。これには、追加の依存関係を必要としないという利点がありますが、かなり多くのコードを記述して手動でソルトを管理する必要があるという欠点があります。BCrypt には、異なる実装が互いの出力を正確に消費できないという問題もあり、実装によっては長いパスワードを切り捨ててしまうこともありますが、これは非常に悪いことです。より多くのコードですが、私はこのアプローチが気に入っています。なぜなら、より多くの制御が可能になり、物事がどのように機能しているかを透過的に正確に示し、ハッシュアルゴリズムと入力パラメーターの推奨事項が絶えず変化するため、時間の経過とともに物事を簡単に更新できるからです。

とにかく、これが私が使用するコードです。ソルトと使用される反復回数を格納します (ベストプラクティスが推奨するように、時間の経過とともにこれらを増やすことができるようにするため)、コロンで区切られたハッシュ値:

val DefaultIterations = 10000
val random = new SecureRandom()

private def pbkdf2(password: String, salt: Array[Byte], iterations: Int): Array[Byte] = {
  val keySpec = new PBEKeySpec(password.toCharArray, salt, iterations, 256)
  val keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
  keyFactory.generateSecret(keySpec).getEncoded
}

def hashPassword(password: String, salt: Array[Byte]): String = {
  val salt = new Array[Byte](16)
  random.nextBytes(salt)
  val hash = pbkdf2(password, salt, DefaultIterations)
  val salt64 = Base64.getEncoder.encodeToString(salt)
  val hash64 = Base64.getEncoder.encodeToString(hash)
  
  s"$DefaultIterations:$hash64:$salt64"
}

def checkPassword(password: String, passwordHash: String): Boolean = {
  passwordHash.split(":") match {
    case Array(it, hash64, salt64) if it.forall(_.isDigit) =>
      val hash = Base64.getDecoder.decode(hash64)
      val salt = Base64.getDecoder.decode(salt64)

      val calculatedHash = pbkdf2(password, salt, it.toInt)
      calculatedHash.sameElements(hash)

    case other => sys.error("Bad password hash")
  }
}

私の実際のコードはもう少し複雑です。バージョン管理されたマジック ワードを最初のコンポーネント ( ph1:) として含めています。つまり、出力値にエンコードされていないハッシュ アルゴリズムやその他の入力パラメーターを変更する場合は、マジック ワードを に更新してこれらのハッシュをエンコードすると、古いハッシュと新しいハッシュph2:の両方を検証するコードを作成できます。ph1ph2

于 2013-08-15T23:01:54.633 に答える
8

BCrypt は、パスワードのハッシュに適しています。Silhouetteを使用し、パスワード プラグインにBCrypt パスワード ハッシャーを使用します。

于 2013-08-15T23:03:31.733 に答える
6

このプロジェクトは、jbcrypt https://github.com/t3hnar/scala-bcryptの優れた scala ラッパーを提供します- 過去に使用したことがあり、うまく機能します。

于 2015-07-05T05:38:06.757 に答える
0

最近の bcrypt t3hnar ライブラリ バージョン 4.1 を Play フレームワークと連携させるための手順は次のとおりです。

依存関係を build.sbt に追加します。

libraryDependencies += "com.github.t3hnar" %% "scala-bcrypt" % "4.1"

プロジェクトに Hash オブジェクトを追加します。

// 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
      }
    }
  }

詳細については、https://code.linedrop.io/guides/Ultimate-Guide-to-Building-a-Web-Application-with-Play-and-Scala/Utilities#PasswordHashingをご覧ください。

ハッシュ ユーティリティの例: https://github.com/LineDrop/play-scala-web-application/blob/master/app/utilities/Hash.scala

ユーザー モデルの例: https://github.com/LineDrop/play-scala-web-application/blob/master/app/models/User.scala

于 2020-04-07T19:07:09.380 に答える