1

要求を Blowfish と Base64 でエンコードする必要がある API と通信する必要があります。

私のカスタムライブラリでは、次のものから始めます。

# encoding: utf-8
require "base64"
require 'crypt/blowfish'

インスタンスを作成します。

@blowfish_key = '1234567887654321'
@blowfish     = Crypt::Blowfish.new(@blowfish_key)

さらに、暗号化された文字列 (または API が呼び出す「チケット」) を作成します。

@string_to_encrypt  = "#{@partnerid},#{user.id},#{exam_id},#{return_url},#{time_stamp}"
@enc                = @blowfish.encrypt_string(@string_to_encrypt)

@blowfish.decrypt_string(@enc)Rails コンソールでは、問題なく復号化できます。しかし、APIは意味不明です:

Invalid ticket:
Decrypted String  :)IŠkó}*Ogû…xÃË-ÖÐHé%q‹×ÎmªÇjEê !©†xRðá=Ͳ    [À}=»ïN)'sïƒJJ=:›õ)¦$ô1X¢

また、「Hello」などのコンソールで単純なものを暗号化し、暗号化された文字列をhttp://webnet77.com/cgi-bin/helpers/blowfish.plなどのオンライン Blowfish デコーダーにフィードすると、同じ結果が得られます。意味不明な混乱。

Rubyフグの暗号は他では使われていないフォーマットのようです。

ノート:

実際のアプリケーションでは、暗号化された文字列をフォーム フィールド経由で Web サービスに送信します。暗号化された文字列は Base64 でエンコードされ、先頭に「a」が付きます。

@enc = Base64.encode64(@enc)
@enc = 'a' + CGI::escape(@enc)

これは、ドキュメントで説明されています。

チケットのフォーマット:

t=’a’ + URL_Encode (
Base64_Encode (
Blowfish_Encrypt ( ‘partnerid,user_id,test_id,URL_Encode(return_URL),ticket_timestamp’, ‘blowfish_key’)
      )
)

Blowfish_Encrypt 関数は、1) 暗号化する文字列と 2) 16 進キーの 2 つのパラメーターを受け入れることに注意してください。また、チケットには小文字の「a」(ASCII 97) がプレフィックスとして付けられていることにも注意してください。

HTML フォームがどのように見えるかの例:

<form method=”POST” action=”http://www.expertrating.com/partner_site_name/”&gt;
<input type=”hidden” name=”t” value=”adfinoidfhdfnsdfnoihoweirhqwdnd2394yuhealsnkxc234rwef45324fvsdf2” />
<input type=”submit” name=”submit” value=”Proceed to take the Test” />
</form>

道に迷ったのですが、どこが間違っていますか?

4

1 に答える 1

1

いくつかのことがあります:

1)コメントで述べたように、暗号化された文字列を印刷すると、暗号化された文字列には印刷できないか、または理解されない表現の非ASCII文字が含まれる可能性が非常に高いため、これはほとんどの場合問題を引き起こします。その他。広く理解されている表現を実現する最善の方法は、Base64 または Hex エンコーディングを使用して結果をエンコードすることです。そのため、アプリケーションで適用する Base64 エンコーディングは問題ありません。

2) リンクした Perl アプリは、たとえば 16 進エンコードを使用します。結果として、16 進数エンコーディングで暗号化された文字列のみを受け入れます。それが、あなたの入力をまったく受け入れない理由です。次のように、アプリケーションに適した 16 進エンコードを取得します。

hex = encrypted.unpack("H*")[0].upcase

3) しかし、Perl アプリではまだうまくいきません。1つの理由はこれです(Cryptソースから取得):

def encrypt_stream(plainStream, cryptStream)
  initVector = generate_initialization_vector(block_size() / 4)
  chain = encrypt_block(initVector)
  cryptStream.write(chain)

これが意味することは、Crypt が暗号化されたメッセージの最初のブロックとして IV を書き込むことです。これはまったく問題ありませんが、私が知っている最新の暗号化ライブラリのほとんどは、IV を先頭に追加せず、通信する 2 つの当事者間で帯域外情報として交換されると想定しています。

4) しかし、これを知っていても、Perl アプリではうまくいかないでしょう。その理由は、Crypt gem が CBC モードを使用するのに対し、Perl アプリは ECB モード暗号化を使用するためです。CBC モードは IV を使用するため、すべてゼロの IV を使用している場合を除き、1 ブロックのメッセージでも一致しません。しかし、すべてゼロの IV (または他の決定論的な IV) を使用することは悪い習慣です(Crypt はとにかくそれを行いません)。そうすることで、最初のブロックとランダムなブロックを区別することができ、BEASTのような攻撃が可能になります。ECB を使用することも、まったくまれなエッジ ケースを除いて悪い習慣です。Perl アプリのことは忘れて、目の前のことに集中しましょう。

5) 私は当然 Ruby OpenSSL を使用することに賛成ですが、この場合、Crypt gem の代わりに Ruby OpenSSL を使用する方が全体的なセキュリティのために優れていると言うのであれば、私は主観的ではないと思います。そんなことを言うだけではだめなので、その理由を 2 つ挙げます。

  • srandCrypt は、予測可能な乱数発生器 (との組み合わせrand) を使用して IV を生成しますが、それだけでは十分ではありません。暗号的に安全な乱数発生器でなければなりません。

  • クリプトはもはや維持されていないようであり、その間、当時は不明だった、またはそのプロジェクトの範囲に含まれていなかったことがいくつかありました. たとえば、OpenSSL は、タイミングやキャッシュ ミスなどを標的とするサイドチャネル攻撃を防ぐために、漏れに強い暗号化の処理を開始します。これはおそらく Crypt の意図ではありませんでしたが、そのような攻撃は実際の生活に真の脅威をもたらします。

6) もし私の説教があなたに変化を起こすことを納得させたなら、私は続けて、それが本当にフグでなければならないかどうかあなたに尋ねることができます. アルゴリズム自体は間違いなく優れていますが、たとえば AES など、より優れた、さらに安全なオプションが現在利用可能です。どうしても Blowfish でなければならない場合は、Ruby OpenSSL でもサポートされています。

cipher = OpenSSL::Cipher.new('bf-cbc')

7) プロダクション キーが例のように見える場合は、別の弱点があります。そのような文字列には十分なエントロピーがありません。ここでも、暗号的に安全なランダム ジェネレーターを使用してキーを生成する必要があります。これは、Ruby OpenSSL では非常に簡単です。

key = cipher.random_key

良い点は、使用する暗号アルゴリズムに応じて適切なキーの長さを自動的に選択することです。

8) 最後に、暗号化された結果を何らかの形式の認証トークンとして使用すると仮定するのは正しいですか? レンダリングされている HTML に追加する場合と同様に、POST リクエストでそれを受信するのを待ち、受信したトークンを元のトークンと比較して、アクションを認証しますか? この場合、これも悪い習慣になります。今回はさらにそうです。ここでは認証された暗号化を使用していません。つまり、暗号文は順応性があります。これは、攻撃者が暗号化キーを実際に知らなくても、そのトークンの内容を比較的簡単に偽造できることを意味します。これはあらゆる種類の攻撃につながり、鍵の回復を伴う完全な侵害にさえつながります.

認証された暗号化モード (GCM、CCM、EAX...) を使用するか、メッセージ認証コードを使用して、暗号文が改ざんされているかどうかを検出する必要があります。さらに良いことに、暗号化をまったく使用せず、安全なハッシュ関数を使用してチケットを生成してください。ここで重要なのは、安全にランダム化された値のハッシュを計算することです。それ以外の場合は、結果を予測することができます。あなたの例で使用されているように、タイムスタンプは十分ではありません。おそらくSecureRandomによって生成された、暗号的に安全なナンスでなければなりません。

しかし、そのようなトークンのリプレイ、トークンのハイジャックなどを検討する必要があります...そう簡単ではありません。

于 2012-05-27T01:46:34.197 に答える