web-dev-qa-db-ja.com

パスワードを保存して機能を覚える

(ところで、これはすべてPHPでコード化されています。以下の関数からわかると思います)

パスワードを保存するとき、私はあなたがパスワードをハッシュしなければならないことを知っています。実際、これが私のコードです(十分に安全かどうか教えてください):

function hash($password)
{
    return password_hash($password, PASSWORD_BCRYPT, array(
        'cost' => 12,
        'salt' => bin2hex(openssl_random_pseudo_bytes(16))
    ));
}

ただし、実際の質問は、適切なログインシステムを使用しているかどうかです。次の段落では、現在のシステムがどのように機能するかを説明します。問題がないか、変更する必要があるかどうかを誰かに教えてください。あなたがそうすることを想定している適切な方法は、クライアントがクッキーまたは何かに保存するトークンを使用することであると聞いたことがあります。

ユーザーが最初にサイトにアクセスし、アカウントが登録されると、ログインするように求められます。彼らが提供したパスワードを使用して、私はそれをハッシュし、それがデータベース内のパスワードとpassword_verify()で一致するかどうかを確認します。検証されたら、彼らは正しいログイン情報を持っているので、$ _ SESSIONにユーザー名とパスワード(サーバー側に保存されていることを理解しています)を設定して認証を行い、ユーザーが[Remember me]ボタンをチェックした場合はユーザー名を保存しますCookieのパスワード(ハッシュ化されていない)は1週間で期限切れになります。

アカウント情報などのページを読み込むなど、新しいアクションを実行しようとするたびに、コードの上部で関数が実行され、認証されているかどうかを返し、認証されているかどうかを確認します。 $ _SESSIONでユーザー名とパスワードを確認し、再度認証します。彼らがカチカチ音をたてて、$ _ SESSIONの有効期限が切れている場合は、そこからユーザー名とパスワードを取得します。

私の懸念は、ほとんどのWebサイトがトークンシステムを使用していると確信しているため、ログインするとCookieにトークンが保存され、毎回サインインする代わりにトークンが使用されます。また、たとえばフォーラムでは、誰がオンラインかを確認できますが、私の場合は確認できません。

誰かが私がしたことが正しいか、変更する必要があるか、それは最善ではないが技術的には安全であるかどうかに応じてください。私が確信しているセッションの部分は安全であり、私が見たいくつかのビデオよりもさらに安全です。ユーザーのIDをセッションに保存するだけで、ユーザーがパスワードを変更しても、まだログインしていると言う人もいます。しかし、Cookieの部分は、Cookieを盗む恐怖で私をつまずかせて、ハッシュ化せずにCookieに保存しています。

4
user120698

答えを見つけました。このため、JWTを使用しています。 Json Web Tokens。これらは、jsonデータの2つのbase64エンコードされた文字列と、情報が変更されていないことを検証する最後の有効な署名です。ログインセッションの有効期限とそのユーザー名が含まれます。ログインのために1つのデータベースと同期する必要がないため、新しいサーバーを簡単に採用したい場合に特に便利です。

認証をしたい人は誰でも、私は間違いなくそれをお勧めします。とても使いやすい、これもlibです: https://Gist.github.com/anonymous/e223abe8066b66c40332649404553385 <-これは1つのエラーを削除して簡単にするために編集した以外は、githubで見つけました。

$key="1682da5b920f4ceb74a542922f43b2a4"/* You need to keep this to decode */
$a = new JWT;

$jwt = $a->encode(json_encode(array(
            "typ" => "JWT",
            "alg" => "HS256"
        )), json_encode(array(
            "iss" => "http://yourwebsite.com/",
            "iat" => time(),
            "exp" => time() + (20 * 60),
            "username" => "authenticated Username"
        )), $key);

        setcookie('jwt_token', $jwt, 0, '/');

JWTのデータセットは変更できません。キーが後で提供する署名によってこの方法が維持されるためです。

ユーザーがサインインしようとしているときに$ a-> decode()関数を実行すると、ユーザー名を変更して「管理者」としてサインインしようとした場合など、データが改ざんされている場合はfalseが返されます。

$jwt = $this->jwt->decode($_COOKIE['jwt_token'], $key);
        if($jwt == false) {
            echo 'Invalid JWT signature, tampered with!'
        } else {
            $json = json_decode($jwt, true);

            if(time() > $json['exp']) { /* expired */ }
            if(time() < $json['iat']) { /* invalid */ }

            /* 
             VALIDATED, let them through as being the user:
             $json['username']
            */
        }

上記のようにfalseが返された場合、改ざんされているため、署名は無効です。次に、json_decoded配列を使用して「exp」などの情報を確認できます。time()> expの場合、期限切れです。 time()<iatの場合は、スプーフィングも行っています。すべてが検証されたら、ユーザー名を確認し、蜂がそのユーザーのアカウントにアクセスする権限を持っていることを100%確認できます。

0
user120698

クイックリマインダー:

  • Saltを定義しないでください。password_hash()関数が管理します。 PHP7 では非推奨であることに注意してください。
  • bcryptはパスワードを切り捨てます 72文字より長い および NULバイト (\ 0)。これは設計によるものであり、PHP実装によるものではありません。これらの理由により、ハッシュ( 'SHA-384')のbase64_encode()結果を渡すのは 推奨 です)元のパスワードの代わりにpassword_hash()に直接:
 function safePasswordHash($ password){
 return password_hash(
 base64_encode(
 hash( 'sha384'、$ password、false)
)、 PASSWORD_BCRYPT、array( 'cost' => 12)
); 
} 

試してください: https://3v4l.org/R1ccr

この記事 に基づいて、ランダムセレクターとトークンを使用して、各ユーザーを個別のテーブル内の認証状態に関連付けることもできます(例: "token_auth")。

したがって、最初に12文字のランダムな文字列を2つ生成します。

  • 識別子として使用される「セレクター」。
  • Cookieにプレーンテキストで保存され、データベース(「トークン」フィールド)のハッシュ値に保存される「バリデーター」。ここではSHA-256を使用します。

次に、Cookieを「selector:validator」として設定します。 「FhpyQLjXYCc9:qXE6Bh417rYg」。

Cookieが有効であることを確認するには、まずデータベース内の「セレクター」と一致する「トークン」をフェッチしてから、Cookieに存在する「バリデーター」のSHA-256値と比較します。

hash_equals() 関数を使用して、潜在的なタイミング攻撃を回避します。

1
ATo

私はあなたがあなたのパスワードをハッシュしなければならないことを知っています、実際はここに私のコードがあります(それが十分に安全かどうか教えてください)

はい、安全です。 saltは渡さないでしょうが、password_hashはsaltを自動的に管理します。

$ _SESSIONにユーザー名とパスワードを設定しました(これはサーバー側に保存されていると理解しています)

はい、サーバー側に保存されます。それでも、回避できる場合は機密情報をセッションに保存しないでください。この場合は機密情報を保存できます(セッションでパスワードをまったく必要としません)。

これはセキュリティ上の問題であり、セッションデータが共有ホストで読み込まれたり、ファイルを含めたりして読み取られる可能性があるため、プレーンテキストのパスワードが漏洩する可能性があります。

彼らが「Remember me」ボタンをチェックした場合、ユーザー名とパスワード(ハッシュ化されていない)をCookieに保存します

繰り返しますが、これは良くありません。ハッシュされていないパスワード、特にCookieを保存したくない場合は、.

犠牲者のブラウザに一時的にアクセスできる人は誰でもプレーンテキストのパスワードにアクセスできるようになり、XSS経由でアクセスできます(少なくとも、CookieがhttpOnlyでない場合はそうする必要があります)など。

代わりに使用したいのは、生成してデータベースに保存するランダムな識別子です(理想的にはハッシュ化されています)。

私が確信しているセッションの部分は安全であり、私が見たいくつかのビデオよりもさらに安全です。ユーザーのIDをセッションに保存するだけで、ユーザーがパスワードを変更しても、まだログインしていると言う人もいます。しかし、Cookieの部分は、Cookieを盗む恐怖で私をつまずかせて、ハッシュ化せずにCookieに保存しています。

あなたはあなたがベストプラクティスに従わないことを知っているようです。では、なぜここで独自のものを構築するのでしょうか?あなたのアプローチは何の利点も提供していないようですが、いくつかのかなり深刻な欠点があります。

1
tim

パスワードをプレーンテキストでCookieに保存するという直観は正しいです。そうすることはお勧めできません。また、より安全な代替策があります。パスワードをソルトおよびハッシュしていますが、それらをプレーンテキストで_$_SESSION_変数に保存すると、一種の対抗策になります。つまり、攻撃者がサーバーにアクセスした場合、すべてのパスワードを取得できるということです。現在サインインしているユーザー。

私の知る限り、標準的な方法は、トークンを使用することとまったく同じです。これははるかに安全です。ユーザーのパスワードをプレーンテキストでどこにでも保存する必要はありません。一般的な考え方はこれです:

  • ユーザーが自分のユーザー名とパスワードを(HTTPS経由で)POSTするときは、password_verify()で確認します。
  • 認証が成功した場合は、_username=xxxx&expiry=xxxx&digest=xxxx_を使用してCookieをユーザーのコンピューターに保存します。トークンの持続時間はあなた次第です。 _admin=true_などの他の変数を追加することもできます。
  • ダイジェストはHMAC-ハッシュベースのメッセージ認証コードです。あなた(サーバー)だけがCookieを作成でき、改ざんされていないことが証明されます。これには、PHPの hash_hmac() を使用できます。サーバーに秘密鍵を保存する必要があることに注意してください。
  • これで、ユーザーが別のページにアクセスしようとしたときに、ユーザーがCookieを持っていることと、(決定的に)_digest=_が他のCookieデータのhash_hmac()と一致することを確認します。ユーザーがCookieを改ざんしようとした場合。別のユーザー名に変更すると、HMACは検証しません。

これに関する非常に優れた論文があり、私が読むことをお勧めします。 Webでのクライアント認証の推奨事項と禁止事項 (PDFリンク)。

0
tao_oat