bcrypt関数を使用してパスワードを生成


数年前、私と同じ開発者の多くはMD 5関数を使ってユーザーのパスワードなどの機密コンテンツをハッシュ化してデータベースに格納していたと信じています.今でも多くの開発者がこのようなやり方をしています.
しかし、多くの事実は、現在MD 5関数で生成されている値が、レインボーテーブルと強力なGPUに基づいて数億回の毎秒の暴力的な解読の下で簡単に解読できることを示しています.
したがって,ユーザパスワードなどの機密情報を保存する必要がある場合には,別の信頼性の高い安全な暗号化方式を探す必要がある.
なぜMD 5が信頼できないのかについては、私の別の文章「10万の理由:MD 5でパスワードを暗号化しないでください」を参照してください.
現在推奨されているスキームは、bcrypt関数を使用してパスワードを生成することです.それは絶対に安全で解読できないからではなく、解読のコストが十分に高いからです.
世界には絶対的な安全はありません.私たちができることは、解読のコストを高めることです.
2つの要因
まずbcryptは暗号暗号化関数であり,Niels ProvosとDavid Mazieresによって設計され,1999年に正式に世間に提案された.
この関数は、2つの重要な要素によって信頼性と安全性を確保します.
第1点:多くの他の暗号化関数やスキームのように、saltが混ざっています.つまり、私たちがよく言う「塩を加える」ということです.塩があれば、攻撃者は虹の表で解読できません.彼は塩の値も推測しなければ解読できません.
しかし、塩を加えるだけで、多くの暗号化関数やMD 5を使って塩を組み合わせることもでき、その強力な理由ではありません.
第2点:bcryptは1つのパラメータcostを受け入れることによって計算時間を向上させ、言い換えればcost数値が大きいほどbcryptが計算を実行するのに要する時間が長くなる.
シーンを想像します.
我々はMD 5+saltのシナリオでパスワードを生成し、攻撃者がこのパスワードを手に入れた後、レインボーテーブル攻撃に基づいて無効になった後、いっそ暴力的な検索攻撃を採用した.MD 5関数を1回実行するのに要する時間は強力な計算能力の前では短いので、あまり時間をかけて解読する必要はない.MD 5関数を1回実行するのに要する時間は1ミリ秒であると仮定した.
次に、bcrypt関数を使用してパスワードを生成します.このcostパラメータ値を1に指定し、このときにbcrypt関数を1回実行するのに要する時間も1ミリ秒ですが、このcostパラメータ値を10に大きくすると、bcrypt関数を1回実行するのに要する時間は50ミリ秒になる可能性があります.それは、平均1時間でパスワードを解読することができたのに、今では50時間で解読することができます.
攻撃者は往々にしてユーザーのパスワードを一度に解読するので、この時間コストと計算力コストがどれだけ大きいか想像できます.
適切なcostの選択方法
一般的に、goのbcrypt.DefaultCostが10であるなど、costパラメータの値として10をデフォルトで取ります.
また、現在のサーバのパフォーマンスに基づいて適切なcost値を選択することもできます.たとえば、bcryptを実行する時間は200ミリ秒を超えないと思います.これにより、簡単に解読されず、時間もかかりません.次のGoコードに基づいて適切なcost値を選択できます.
package main

import (
    "fmt"
    "time"

    "golang.org/x/crypto/bcrypt"
)

func main() {
    for cost := 10; cost <= 20; cost++ {
        start := time.Now()
        bcrypt.GenerateFromPassword([]byte("pa55w0rd"), cost)
        fmt.Printf("cost: %d, duration: %v
", cost, time.Since(start)) } }

私の本機で実行した結果は以下の通りです.
cost: 10, duration: 75.797197ms
cost: 11, duration: 146.597944ms
cost: 12, duration: 298.971358ms
cost: 13, duration: 610.758023ms
cost: 14, duration: 1.181615153s
cost: 15, duration: 2.433344989s
cost: 16, duration: 4.917117451s
cost: 17, duration: 9.453614867s
cost: 18, duration: 19.186913882s
cost: 19, duration: 37.79228015s
cost: 20, duration: 1m16.157706237s

では、私はこれに基づいてcost値を11と選択することができますが、実際には上の実行結果からもcost値と実行時間の関係がわかります.costが1増加するたびに、実行時間が2倍になります.具体的なアルゴリズムに興味のある人は、文末のWikipediaリファレンスリンクで詳細な情報を見つけることができます.
以下のPHPバージョンも添付しましょう.
 $cost]);
    $end = microtime(true);
    echo "cost: " . $cost . ", duration: " . ($end - $start) * 1000 . "
"; } ?>

サンプルコード
ここでは、PHPとGoの2つのサンプルコードを参照してください.
";

$hash = password_hash($pwd, PASSWORD_BCRYPT, ["cost" =?> 10]);
echo "Encrypted Password: " . $hash . "
"; $match = password_verify($pwd, $hash); echo "Match Result: " . $match; ?>
package main

import (
    "fmt"

    "golang.org/x/crypto/bcrypt"
)

func main() {
    pwd := "pa55w0rd"

    fmt.Println("Origin Password: " + pwd)

    hash, _ := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost)

    fmt.Println("Encrypted Password: " + string(hash))

    err := bcrypt.CompareHashAndPassword(hash, []byte(pwd))
    fmt.Println("Match Result: ", err == nil)
}

リファレンスリンク
  • https://en.wikipedia.org/wiki/Bcrypt