web-dev-qa-db-ja.com

Cookieの暗号化に最適な暗号化アルゴリズムは何ですか?

この質問はかなり人気があるので、更新するのが便利だと思いました。

この質問に対して AviD で与えられる正解を強調させてください。

暗号化が必要なデータをCookieに保存しないでください。代わりに、適切なサイズ(128ビット/ 16バイト)のランダムキーをCookieに保存し、サーバー上で安全に保ちたい情報を保存します、Cookieのキーで識別されます。



クッキーを暗号化するための「最高の」暗号化アルゴリズムに関する情報を探しています。

私は次の要件を持っています:

  • 速くなければならない
    データの暗号化と復号化は、(ほぼ)すべてのリクエストに対して行われます

  • 通常、約100文字以下の文字列の小さなデータセットで動作します。

  • 安全でなければなりませんが、銀行取引を保護しているわけではありません

  • SHA1などが公開されるように、情報を解読できる必要があります。

今、私はBlowfishが高速かつ安全であることを読み、AESが高速かつ安全であることを読みました。 Blowfishのブロックサイズが小さい場合。

両方のアルゴリズムが十分なセキュリティ以上のものを提供すると思いますか?そのため、速度が決定的な要因になります。しかし、これらのアルゴリズムが小さな文字列に適しているかどうか、Cookieを暗号化するのにより適したアルゴリズムがあるかどうかは、本当にわかりません。

だから私の質問は:
Cookieデータの暗号化に最適な暗号化アルゴリズムは何ですか?

更新
より正確には、2つのCookieを暗号化します。1つはセッション情報を使用し、もう1つは「記憶」情報を使用します。

プラットフォームは、VPS上のLinux上のApacheモジュールとしてPHPです。

更新2
同意します cletus Cookieに情報を保存することは安全ではありません。

ただし、「記憶」機能を実装する必要があります。これについて受け入れられる方法は、Cookieを設定することです。クライアントがこのCookieを提示する場合、有効なユーザー名とパスワードの組み合わせを提示したかのように、クライアントは(ほぼ)同等の権利でシステムにアクセスできます。

したがって、少なくともCookie内のすべてのデータを暗号化して、次のようにします。
a)悪意のあるユーザーはコンテンツを読むことができません。
b)悪意のあるユーザーは、独自のCookieを作成したり、改ざんしたりすることはできません。

(Cookieのすべてのデータはサニタイズされ、有効性がチェックされてから処理されますが、それは別の話です)

セッションCookieにはsessionId/timestampが含まれています。おそらく暗号化なしで使用できますが、暗号化しても害はありませんか? (計算時間以外)。

では、Cookieにデータを保存する必要があるので、それを暗号化する最良の方法は何ですか?

更新
この質問に対する回答により、選択したアプローチを再考することができました。暗号化を必要とせずに、実際に同じことができます。データを暗号化する代わりに、コンテキストがなく推測できないデータのみを送信する必要があります

しかし、私も迷っています:
暗号化によってBigBadWorld™にデータを送信できるようになり、それでも(公正に)誰もそれを読み取ったり改ざんしたりすることができないと確信しています...
それが暗号化の要点ではなかったのですか?

しかし、以下の反応は次のようにプッシュします。セキュリティを達成するために暗号化を信頼しないでください。

不足しているものは何ですか?

48
Jacco

[〜#〜] aes [〜#〜] を256ビットで使用しない理由はありません。これを必ず CBCモード およびPKCS#7パディングで使用してください。あなたが言ったように、高速かつ安全。

Blowfishの方がわずかに高速である可能性があることを(テストしていませんが)読んだことがあります。また、AESはより「実証済み」です。

これは、Cookieデータを対称的に暗号化することが本当に必要であることを前提としています。他の人が指摘したように、それは本当に必要ではありません、そして、そうする以外に選択の余地がないいくつかのエッジのケースがあります。一般に、設計を変更し、ランダムセッションIDに戻るか、必要に応じて一方向ハッシュ(SHA-256を使用)に戻る方が適しています。
あなたの場合、「通常の」ランダムセッション識別子に加えて、あなたの問題は「私を覚えている」機能です-これは次のいずれかとして実装されるべきです:

  • データベースに保存され、ユーザーアカウントにマッピングされた長い乱数。
  • またはキーを含むハッシュ(HMACなど)ユーザー名、タイムスタンプ、mebbe salt、および秘密サーバーキー。もちろん、これはすべてサーバー側で検証できます...

元の特定の質問のトピックから少し外れているようです-そして、デザインを変更することで質問の基礎を変更しました...
それを行っている限り、[〜#〜] against [〜#〜]を強くお勧めします」、いくつかの理由から、それらの中で最大のもの:

  • 誰かがそのユーザーの記憶キーを盗む可能性がはるかに高くなり、ユーザーのIDをスプーフィング(およびおそらくパスワードを変更)できるようになります。
  • [〜#〜] csrf [〜#〜] - クロスサイトリクエストフォージェリ 。この機能により、匿名の攻撃者は、実際にログインしていなくても、知らないユーザーに「認証済み」リクエストをアプリケーションに送信させることができます。
25
AviD

これは、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を暗号化するためのセキュリティの議論はまだ見ていません。

誰かが反対のことを指摘できれば、私は喜んで間違っていると証明されます。

18
cletus

セキュリティ警告:これらの2つの機能は安全ではありません。彼らは ECBモード を使用しており、 暗号文の認証 に失敗しています。より良い方法については this answer をご覧ください。

PHPスクリプト。

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($_COOKIE['PHPSESSION'], 'longsecretsalt');
9
Xeoncross

EAXモードでAESを使用することにより、目的を安全に達成できます。暗号文は平文よりも大きくなります。これは、安全な暗号化では正常です。

攻撃者はもちろん暗号文からあなたの平文の長さを知っているでしょうが、他の何かを決定することはできません。

AESキーをランダムに生成します。

必ず各暗号化に新しいノンスを使用し、「関連データ」フィールドを使用して、ある目的のために暗号化したものが別の目的のものとして表示されないようにします(したがって、ユーザー名やCookie名などが入ります)そこ)

以下の反応プッシュプッシュ:セキュリティを達成するために暗号化を信頼しないでください。

さらに、「暗号化の専門家でない場合は、間違えやすいことを過小評価するでしょう」。たとえば、このスレッドの他の誰もチェーンモードやメッセージの整合性について議論していないため、2つの一般的な初心者の間違いをカバーしています。

4
Paul Crowley

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でデータを安全に暗号化する を使用する場合、mustメッセージを認証します。

OpenSSL拡張機能を使用すると、従う必要があるプロセスは次のようになります。


前文

  • (暗号化について考える前に)128ビット、192ビット、または256ビットのランダム文字列を生成します。これは、マスターキーになります。

    人間が読めるパスワードを使用しないでください。何らかの理由でmust人間が読めるパスワードを使用する場合は、 Cryptography SE ガイダンス用。

    特別な注意が必要な場合、雇用主は テクノロジーコンサルティングサービス を提供します。これには、暗号化機能の開発が含まれます。

暗号化

  1. ランダムな初期化ベクトル(IV)またはナンスを生成します。例えばrandom_bytes(openssl_cipher_iv_length('aes-256-cbc'))
  2. [〜#〜] hkdf [〜#〜] または同様のアルゴリズムを使用して、マスターキーを2つのキーに分割します:
    1. 暗号化キー(_$eKey_)
    2. 認証キー(_$aKey_)
  3. 手順2の暗号化キー(_aes-256-ctr_)を使用して、IVと適切な変更(_$eKey_)を使用して、openssl_encrypt()で文字列を暗号化します。
  4. HMAC-SHA256などのキー付きハッシュ関数を使用して、ステップ3から暗号文の認証タグを計算します。例えばhash_hmac('sha256', $iv.$ciphertext, $aKey)暗号化後に認証し、IV/nonceもカプセル化することは非常に重要です。
  5. 認証タグ、IVまたはnonce、および暗号文を一緒にパッケージ化し、オプションでbin2hex()またはbase64_encode()でエンコードします。 (警告:このアプローチmightキャッシュタイミング情報をリークします。)

解読

  1. 暗号化の手順2に従って、キーを分割します。復号化時には同じ2つのキーが必要です!
  2. (オプションで、パックされたメッセージからMAC、IV、および暗号化テキストをデコードおよびアンパックします。
  3. hash_equals() を使用して、IV/nonceのHMACとユーザー提供のHMACでの暗号文を再計算して、認証タグを検証します。
  4. ステップ3が成功した場合のみ、_$eKey_を使用して暗号文を復号化します。

このすべてがどのように見えるかを確認したい場合は、 サンプルコードがあるこの回答 を参照してください。

これがあまりにも多くの作業のように思える場合は、 defuse/php-encryption または zend-crypt を使用して1日呼び出します。


Cookieを記憶する

ただし、「記憶」機能を実装する必要があります。これについて受け入れられる方法は、Cookieを設定することです。クライアントがこのCookieを提示する場合、有効なユーザー名とパスワードの組み合わせを提示したかのように、クライアントは(ほぼ)同等の権利でシステムにアクセスできます。

暗号化は、実際にはこのジョブの正しいツールではありません。 PHPのcookieを安全に記憶する

Remember Meトークンの生成

  1. 2つのランダムな文字列を生成します。
    1. データベース検索に使用されるselector。 (シーケンシャルIDの代わりにランダムセレクターの目的は、notあなたのウェブサイトにいるアクティブユーザーの数を漏らすことです。この情報を漏らしたい場合は、シーケンシャルIDを使用してください。 )
    2. ユーザーを自動的に認証するために使用されるvalidator
  2. validatorのハッシュを計算します(単純なSHA-256ハッシュで十分です)。
  3. selectorvalidatorのハッシュを自動ログイン用に予約されたデータベーステーブルに保存します。
  4. selectorvalidatorをクライアントのCookieに保存します。

Remember Meトークンの引き換え

  1. 着信Cookieをselectorvalidatorに分割します。
  2. selectorに基づいてデータベースルックアップを実行します( 準備済みステートメント !を使用します)。
  3. 行が見つかった場合、validatorのハッシュを計算します。
  4. もう一度 hash_equals() を使用して、ステップ3で計算されたハッシュをデータベースに保存されているハッシュと比較します。
  5. 手順4でtrueが返された場合、ユーザーを適切なアカウントにログインします。

これは、 Gatekeeper が長期ユーザー認証に採用された戦略であり、この要件を満たすためにこれまでに提案された最も安全な戦略です。

4

以前のコメントで何度か指摘したように、mustを適用する必要があります完全性保護ユーザーに送信し、受け入れた暗号文。それ以外の場合、保護されたデータを変更したり、暗号化キーを回復したりできます。

特にPHPの世界はこれを無視する悪い例でいっぱいです( PHP暗号化-注意して進めてください を参照)が、これはどの言語にも当てはまります。

私が見たいくつかの良い例の1つは、 PHP-CryptLib です。これは、暗号化認証モードを組み合わせてジョブを実行します。 For Python pyOCB は同様の機能を提供します。

2
kravietz

両方とも非常に強力なものですが、AESは標準です。

データの小さなチャンクのセキュリティに関して:小さいほど良い。暗号化されたデータが少ないほど、キーを長く使用できます。システムをリスクにさらすことなく、特定のアルゴリズムの1つのキー内で暗号化できるデータの量には常に理論的な制限があります。

2
inazaruk

Cookieを暗号化する場合、サーバーは(同じキーをチェックするために)読み取りのためにデコードする必要があります。したがって、暗号化されたCookieは無意味です。 。まったく暗号化されていないのと同じくらい安全ではありません。

誰かがあなたのクッキーを盗むことの本当の問題は、サーバーとクライアントの間の接続だと思います。ホストが提供するSSL接続を使用します。

Cookieについては、データベース内のユーザーごとに長いランダムIDを作成し(ログオンごとに変更する)、それをCookieまたはセッションとして設定する必要があります。キーを含むCookieはphpで確認でき、データベースのアカウントまたはテーブルと等しい場合、通常のようにWebページにデータをダンプします。

1
mike

なぜクッキーを暗号化するのですか?

私が見るように、2つのケースがあります:クライアントにキーを与えるか、しないかのどちらかです。

クライアントにキーを渡さない場合、なぜ彼らにデータを渡していますか?弱い暗号化を使用した奇妙なゲームをプレイしているのでない限り(明示的にはそうではありません)、データをサーバーに保存することもできます。

doクライアントに鍵を渡した場合、なぜ最初に暗号化するのですか?キーの通信を暗号化しない場合、Cookieの暗号化は意味がありません。MITMはCookieを見て、必要なCookieを送信できます。クライアントに暗号化されたチャネルを使用する場合、保存されたデータを暗号化する余分なオーバーヘッドが発生するのはなぜですか?

クライアントのマシン上の他のユーザーがクッキーを読んでいるのが心配なら、あきらめてブラウザが適切な許可ビットを設定していると仮定してください:)

1
Jonas Kölker

さらに、_mcrypt_encrypt_を試してみましたが、覚えておいてください。 base64_encode(mcrypt_encrypt(...))を実行した場合。

その後、_base64_decode_を実行し、暗号化されたデータ(echo)を出力します。あなたはおそらくねじ込まれ、何も見えないでしょう。ただし、mcrypt_decrypt( ... base64_decode($value) )を実行する場合。元のデータが表示されます。

0
murvinlai

ユーザー名とパスワードについては暗号化されていてもデータを「渡す」ことは良くないと思います...それを嗅ぐことができる多くのJSがあります...ユーザーDBテーブルにcookie_authフィールドなどを作成することをお勧めします。

最初のログイン収集後:現在:ブラウザ、IP、独自のソルトキー、およびホスト名変数...

ハッシュを作成してそのフィールドに保存します... Cookieを設定します... Cookieが「応答する」ときに、これらすべてを保存されたハッシュと比較して完了します...

誰かがCookieを「盗んだ」としても、それを使用することはできません:-)

お役に立てれば :-)

feha vision.to

0
Feha

AES(Rijndaelとしても知られる)が最も人気があります。ブロックサイズは128ビットで、わずか16バイトで、「約100文字」と言っています。

0
vartec