Cookieの暗号化に最適な暗号化アルゴリズムは何ですか?
-
03-07-2019 - |
質問
この質問はかなり人気があるので、更新するのが便利だと思いました。
この質問に対して AviD が提供する正解を強調します。
Cookieに暗号化が必要なデータを保存しないでください。代わりに、適切なサイズ(128ビット/ 16バイト)のランダムキーをCookieに保存し、安全に保ちたい情報を保存しますCookieのキーで識別されるサーバー上。
Cookieを暗号化するための「最良の」暗号化アルゴリズムに関する情報を探しています。
次の要件を満たしている:
-
高速でなければなりません
データの暗号化と復号化は(ほぼ)すべてのリクエストに対して行われます -
小さなデータセット、通常は約100文字以下の文字列で動作します
-
安全である必要がありますが、銀行取引を保護しているわけではありません
-
SHA1などが公開されるように、情報を復号化できる必要があります。
今、私はBlowfishが高速かつ安全であることを読み、AESが高速かつ安全であることを読みました。 Blowfishのブロックサイズが小さい場合。
両方のアルゴリズムが十分なセキュリティ以上のものを提供すると思いますか?そのため、速度が決定的な要因になります。 しかし、これらのアルゴリズムが小さな文字列に適しているかどうか、Cookieを暗号化するのに適したアルゴリズムがあるかどうかは、まったくわかりません。
だから私の質問は:
Cookieデータの暗号化に最適な暗号化アルゴリズムは何ですか?
更新
より正確には、2つのCookieを暗号化します。1つはセッション情報を使用し、もう1つは「記憶」情報を使用します。
プラットフォームは、VPS上のLinux上のApacheモジュールとしてのPHPです。
更新2
cletus に同意します。Cookieに情報を保存することは安全ではありません。
ただし、「リバーミー」機能を実装する必要があります。これについて受け入れられる方法は、Cookieを設定することです。クライアントがこのCookieを提示すると、有効なユーザー名とパスワードの組み合わせを提示したかのように、(ほぼ)同等の権利でシステムにアクセスすることが許可されます。
したがって、少なくともクッキー内のすべてのデータを暗号化して、次のようにします。
a)悪意のあるユーザーはコンテンツを読むことができません、
b)悪意のあるユーザーが独自のCookieを作成したり、改ざんしたりすることはできません。
(Cookieのすべてのデータはサニタイズされ、有効性がチェックされてから処理されますが、これは別の話です)
セッションCookieにはsessionId / timestampが含まれています。おそらく暗号化なしで使用できますが、暗号化しても害はありませんか? (計算時間以外)。
一部のデータをCookieに保存する必要がある場合、暗号化する最善の方法は何ですか?
アップデート3
この質問に対する回答により、私は選択したアプローチを再考しました。実際、暗号化を必要とせずに同じことができます。データを暗号化する代わりに、コンテキストがない限り意味がなく、推測できないデータのみを送信する必要があります 。
しかし、私も迷っています:
暗号化によってBigBadWorld™にデータを送信できるようになり、それでも(公正に)誰もそれを読んだり改ざんしたりすることができないと確信しています...
それが暗号化のポイントではなかったのですか?
しかし、以下の反応は次の方向に向かっています。セキュリティを達成するために暗号化を信頼しないでください。
不足しているものは何ですか?
解決
256ビットの AES を使用しない理由はありません。必ず CBCモード、およびPKCS#7で使用してください。パディング。 あなたが言ったように、高速かつ安全。
Blowfishの方がわずかに速いかもしれないことを(テストしていませんが)読んだことがあります...しかし、Blowfishにはセットアップ時間が長いという大きな欠点があり、状況に悪影響を及ぼす可能性があります。また、AESはより「実証済み」です。
これは、Cookieデータを対称的に暗号化することが本当に必要であると想定しています。他の人が指摘したように、それは本当に必要ではない、そしてそうする以外に選択の余地がないいくつかのエッジケースがあります。一般に、設計を変更し、ランダムセッションIDに戻るか、必要に応じて一方向ハッシュ(SHA-256を使用)に戻る方が適しています。
あなたの場合、「通常」以外にランダムなセッション識別子、あなたの問題は「私を覚えている」機能-これも次のいずれかとして実装する必要があります。
- データベースに保存され、ユーザーアカウントにマッピングされた長い乱数。
- またはキーを含むハッシュ(例:HMAC)を含む例ユーザー名、タイムスタンプ、mebbe salt、および秘密サーバーキー。もちろん、これはすべてサーバー側で検証できます...
元の特定の質問のトピックから少し外れているようです-設計を変更することで質問の基礎を変更しました。...
そのため、私たちがそれをしている限り、いくつかの理由で、これらの永続的な「覚えておいてください」という機能を AGAINST することを強くお勧めします:
- 誰かがそのユーザーの記憶キーを盗む可能性がはるかに高くなり、ユーザーの身元を偽造する(そしておそらくパスワードを変更する)可能になります。
- CSRF -クロスサイトリクエストフォージェリー。この機能により、匿名の攻撃者は、知らないユーザーに「認証済み」を送信させることができます。実際にログインしなくても、アプリケーションへのリクエスト。
他のヒント
これは、2つの別個の問題に触れています。
まず、セッションハイジャック。これは、第三者が認証されたCookieを発見し、他の誰かの詳細にアクセスする場所です。
次に、セッションデータセキュリティがあります。つまり、データをCookie(ユーザー名など)に保存するということです。これは良い考えではありません。クライアントは必要なものを自由に送信できるため、このようなデータは、HTMLフォームデータが信頼できない(まったくJavascriptの検証やHTMLの長さ制限がある場合でも)のと同様に、基本的に信頼できません。
HTMLフォームデータをサニタイズすることを(正しく)主張する人をよく見かけますが、Cookieデータは額面どおりに盲目的に受け入れられます。大ミス。実際、Cookieに情報を保存することはありません。私はそれをセッションキーと見なし、それだけです。
Cookieにデータを保存する場合は、再検討することを強くお勧めします。
対称暗号化はブルートフォース攻撃を受けやすいため、このデータを暗号化しても情報の信頼性は低下しません。 AES-256は、たとえばDES(heh)よりも優れていることは明らかですが、256ビットのセキュリティは必ずしもあなたが思うほどには意味がありません。
1つには、SALTは通常、アルゴリズムに従って生成されるか、そうでなければ攻撃を受けやすくなります。
別の場合、Cookieデータは crib 攻撃の最有力候補です。暗号化されたデータにユーザー名が含まれていることがわかっているか疑われる場合は、ベビーベッドがあります。
これにより、最初のポイントであるハイジャックに戻ります。
PHPの共有ホスティング環境(一例として)では、セッションデータは単にファイルシステムに保存され、同じホスト上の他の誰でも読むことができることに注意してください。のためです。そのため、プレーンテキストのパスワード、クレジットカード番号、詳細な個人情報、または何らかの形で暗号化せずにそのような環境のセッションデータで機密と見なされる可能性のあるものを保存しないでください。データベース内のデータ。
注:上記はPHPに固有のものではありません。
ただし、これはサーバー側の暗号化です。
これで、セッションをいくつかの追加データで暗号化すると、ハイジャックからより安全になると主張できます。一般的な例は、ユーザーのIPアドレスです。問題は、多くの人々が多くの異なる場所(Wifiホットスポット、職場、自宅など)で同じPC /ラップトップを使用していることです。また、特に企業環境では、多くの環境でさまざまなIPアドレスがソースアドレスとして使用されます。
ユーザーエージェントも使用できますが、それは推測できます。
実際、私が知る限り、Cookie暗号化を使用する本当の理由はまったくありません。私は決して存在するとは思いませんでしたが、この質問に照らして、正しいか間違っているかの証明を求めて行きました。 Cookieデータを暗号化する方法、Apacheモジュールで透過的に行う方法などを提案する人々に関するスレッドをいくつか見つけましたが、これらはすべて、Cookieに格納されたデータを保護することによって動機付けられたようです(これは禁止です)。
セッションキー以外の何物でもないCookieを暗号化するためのセキュリティの議論はまだありません。
誰かが反対のことを指摘できるなら、私は喜んで間違っていると証明されます。
セキュリティ警告:これら2つの機能は安全ではありません。彼らは ECBモードを使用しており、暗号文を認証します。今後のより良い方法については、この回答をご覧ください。
PHPスクリプトでこのメソッドを使用したいという読者向け。 256ビットのRijndael(AESではない)を使用した実用的な例を次に示します。
function encrypt($text, $salt)
{
return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $salt, $text, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))));
}
function decrypt($text, $salt)
{
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $salt, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)));
}
次にCookieを保存します
setcookie("PHPSESSION", encrypt('thecookiedata', 'longsecretsalt'));
次のページで読む:
$data = decrypt(
セキュリティ警告:これら2つの機能は安全ではありません。彼らは ECBモードを使用しており、暗号文を認証します。今後のより良い方法については、この回答をご覧ください。
PHPスクリプトでこのメソッドを使用したいという読者向け。 256ビットのRijndael(AESではない)を使用した実用的な例を次に示します。
function encrypt($text, $salt)
{
return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $salt, $text, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))));
}
function decrypt($text, $salt)
{
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $salt, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)));
}
次にCookieを保存します
setcookie("PHPSESSION", encrypt('thecookiedata', 'longsecretsalt'));
次のページで読む:
<*>COOKIE['PHPSESSION'], 'longsecretsalt');
AESをEAXモードで使用することで、目的を安全に達成できます。暗号文は平文よりも大きくなります。これは安全な暗号化のための正常です。
もちろん、攻撃者は暗号文から平文の長さを知っていますが、他の何かを判断できないはずです。
AESキーをランダムに生成します。
必ず各暗号化に新しいノンスを使用し、「関連データ」を使用してください。ある目的のために暗号化したものが別の目的のものとして表示されないようにするためのフィールド(ユーザー名やCookie名などが入り込む可能性があります)
以下の反応は次の方向に向かっています。 達成するために暗号化を信頼しない セキュリティ。
その他&quot;あなたが暗号化の専門家でない場合、間違いを犯しやすいことを過小評価するでしょう。たとえば、このスレッドの他の誰もチェーンモードやメッセージの整合性について議論していないため、初心者のよくある2つの間違いを取り上げています。
Libsodiumを使用した高速暗号化Cookie
PHPで高速で安全な暗号化されたcookieが必要な場合は、 Halite がそれらをどのように実装するかを確認してください。 Haliteは、安全な暗号化を提供するために、 libsodium PECL拡張機能に依存しています。
<?php
use \ParagonIE\Halite\Cookie;
use \ParagonIE\Halite\Symmetric\Key;
use \ParagonIE\Halite\Symmetric\SecretKey;
// You can also use Key::deriveFromPassword($password, $salt, Key::CRYPTO_SECRETBOX);
$encryption_key = new SecretKey($some_constant_32byte_string_here);
$cookie = new Cookie($encryption_key);
$cookie->store('index', $any_value);
$some_value = $cookie->fetch('other_index');
PECL拡張機能をインストールできない場合は、システム管理者またはホスティングプロバイダーに依頼してください。彼らが拒否した場合、あなたにはまだ選択肢があります。
PHPで暗号化されたCookieを保護し、Saltを保持してください
他の回答では、opensslまたはmcryptを使用してデータを暗号化するように指示していますが、重要なステップが欠落しています。 PHPでデータを安全に暗号化する場合は、メッセージを認証する必要があります 。
OpenSSL拡張機能を使用すると、従う必要があるプロセスは次のようになります。
プリアンブル
-
(暗号化について考える前に)128ビット、192ビット、または256ビットのランダム文字列を生成します。これがマスターキーになります。
人間が読めるパスワードを使用しないでください。何らかの理由で人間が読めるパスワードを使用する必要がある場合は、暗号化SE をご覧ください。
特別な注意が必要な場合、雇用主は暗号化の開発を含むテクノロジーコンサルティングサービスを提供しています。機能。
暗号化
- ランダムな初期化ベクトル(IV)またはノンスを生成します。例えば
random_bytes(openssl_cipher_iv_length( 'aes-256-cbc'))
- HKDF を使用するマスターキーを2つのキーに分割する同様のアルゴリズム:
- 暗号化キー(
$ eKey
) - 認証キー(
$ aKey
)
- 暗号化キー(
- IVおよび適切な変更(例:
aes-256-ctr
)を使用してopenssl_encrypt()
で文字列を暗号化し、暗号化キー($ eKey
)ステップ2から。 - 手順3の暗号化テキストの認証タグを、HMAC-SHA256などのキー付きハッシュ関数を使用して計算します。例えば
hash_hmac( 'sha256'、$ iv。$ ciphertext、$ aKey)
。 暗号化後に認証を行い、IV / nonceもカプセル化することは非常に重要です。 - 認証タグ、IVまたはnonce、および暗号文を一緒にパッケージ化し、オプションで
bin2hex()
またはbase64_encode()
でエンコードします。 (警告:このアプローチでは、キャッシュタイミング情報が漏れる可能性があります。)
復号化
- 暗号化の手順2に従って、キーを分割します。復号化時には同じ2つのキーが必要です!
- (オプションで、デコードして)MAC、IV、および暗号化されたメッセージをパックされたメッセージからアンパックします。
- を使用して、IV / nonceのHMACとユーザー提供のHMACによる暗号文を再計算して認証タグを検証します
hash_equals()
。 - ステップ3が成功した場合にのみ、
$ eKey
を使用して暗号文を復号化します。
これがすべてどのように見えるかを確認したい場合は、サンプルコードを含むこの回答を参照してください。
これが大変すぎるように思える場合は、 defuse / php-encryption または zend-crypt を呼び出し、1日で呼び出します。
Remember Me C
両方とも非常に強力なものですが、AESは標準です。
小さなデータチャンクのセキュリティに関しては、小さいほど良いです。暗号化されたデータが少ないほど、キーを長く使用できます。システムをリスクにさらすことなく、特定のアルゴリズムの1つのキー内で暗号化できるデータ量には常に理論的な制限があります。
Cookieを暗号化する場合、サーバーは(同じキーをチェックするために)読み取るためにそれをデコードする必要があります。したがって、暗号化されたCookieは無意味です。アカウントに。まったく暗号化されていないのと同じくらい安全ではありません。
Cookieを盗む誰かの本当の問題は、サーバーとクライアント間の接続だと思います。ホストが提供するSSL接続を使用します。
Cookieについては、データベース内のユーザーごとに長いランダムIDを作成し(ログオンごとに変更する)、Cookieまたはセッションとして設定する必要があります。キーを含むcookieはphpで確認でき、データベースのアカウントまたはテーブルと等しい場合、通常のようにWebページにデータをダンプします。
前のコメントで何度か指摘したように、ユーザーに送信して返送する暗号文に完全性保護を適用する必要があります 。そうでない場合、保護されたデータを変更したり、暗号化キーを回復したりできます。
特に、PHPの世界にはこれを無視する悪い例がたくさんあります( PHP暗号化-注意して続行を参照) )しかし、これはどの言語にも当てはまります。
私が見た数少ない良い例の1つは、 PHP-CryptLib です。ジョブを実行するための認証モード。 Pythonの場合、 pyOCB は同様の機能を提供します。
Cookieを暗号化する理由
おわかりのように、クライアントにキーを渡すか、渡さないかの2つのケースがあります。
クライアントにキーを提供しない場合、なぜ彼らにデータを提供するのですか?弱い暗号化を使用した奇妙なゲームをプレイしている場合を除き(明示的にはそうではありません)、サーバーにデータを保存することもできます。
クライアントにキーを行う場合、最初に暗号化するのはなぜですか?キーの通信を暗号化しない場合、Cookieの暗号化は意味がありません。MITMはCookieを見て、必要なCookieを送信できます。クライアントに暗号化されたチャネルを使用する場合、保存されたデータを暗号化する余分なオーバーヘッドが必要な理由
クライアントのマシン上の他のユーザーがCookieを読み取ることを心配している場合は、あきらめて、ブラウザが適切な許可ビットを設定していると想定します:)
AES(Rijndaelとしても知られています)が最も人気があります。ブロックサイズは128ビットで、わずか16バイトで、「約100文字」と言っています。
「贈る」と思うユーザー名とパスワードに関するものである場合でも暗号化されたデータはすべて良くない... それを嗅ぐことができる多くのJSがあります... ユーザーDBテーブルにcookie_authフィールドなどを作成することをお勧めします...
最初のログイン収集後:現在:ブラウザ、IP、独自のソルトキー、およびホスト名変数...
ハッシュを作成し、そのフィールドに保存します... クッキーを設定します... Cookieが「応答する」ときこれらすべてを保存されたハッシュと比較して完了しました...
誰かが「盗む」場合でもCookieを使用できません:-)
これが役立つことを願って:-)
feha vision.to
さらに、 mcrypt_encrypt
を試してみましたが、一つ覚えておいてください。 base64_encode(mcrypt_encrypt(...))
を実行した場合。
その後、 base64_decode
を実行し、暗号化されたデータ( echo
)を出力します。あなたはおそらくねじ込まれ、何も見えないでしょう。ただし、 mcrypt_decrypt(... base64_decode($ value))
を実行した場合。元のデータが表示されます。