web-dev-qa-db-ja.com

XMPP SASLSCRAM-SHA1認証

最近、次の2つのWebサイトの指示に従って、Swift IOSでXMPPストリームに対してMD5認証を機能させることができました(CC-MD5関数を使用しました)実際のハッシュ用のAppleのCommonCryptoCライブラリの例):

http://wiki.xmpp.org/web/SASLandDIGEST-MD5

http://www.deusty.com/2007/09/example-please.html

他のハッシュSASL認証スキーム、特にSCRAM-SHA1を機能させる方法についても同様の説明を探しています。公式の RFC5802 ドキュメントを見つけましたが、理解するのに多くの問題があります(XMPPに固有のものでもありません)。実際のハッシュ以外の目的でライブラリを使用しないXMPP認証に固有の、より簡単な説明または簡単で読み取り可能なコード(C、PHP、C++、Javascript、Java)をいただければ幸いです。

プロセスを理解することに興味があり、iosXMPP-Frameworkを使用するつもりはありません。どんな助けでもいただければ幸いです。

12
Water Not Words

SCRAM-SHA-1

このメカニズムがどのように機能するかの基本的な概要は次のとおりです。

  • クライアントは、認証するユーザー名を送信します。
  • サーバーは、そのユーザーのソルトと反復回数を送り返します(それらを生成するか、データベースで指定されたユーザー名を検索します)。
  • クライアントは、指定された反復回数の間、指定されたソルトでパスワードをハッシュします。
  • クライアントは結果を送り返します。
  • サーバーはハッシュのバリエーションを実行し、その結果をクライアントに送り返します。そのため、クライアントはサーバーがパスワード/パスワードのハッシュを持っていることを確認することもできます。

必要な暗号化アルゴリズムは、SHA-1、HMACとSHA-1、および PBKDF2 とSHA-1です。ゼロから実装することはお勧めしませんので、言語/フレームワークでの使用方法を調べる必要があります。

詳細に

  1. 最初にパスワードを正規化します( SASLprep を使用)。これはnormalizedPasswordになります。これは、UTF8エンコーディングに同じパスワードのバリエーションを含めることができないようにするためです。
  2. ランダムな文字列を選択します(たとえば、32の16進エンコードバイト)。これはclientNonceになります。
  3. initialMessage"n=" .. username .. ",r=" .. clientNonceです(文字列の連結には..を使用しています)。
  4. クライアントはGS2ヘッダー("n,,")をinitialMessageの前に付加し、結果をbase64でエンコードします。これを最初のメッセージとして送信します。

    <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="SCRAM-SHA-1">
        biwsbj1yb21lbyxyPTZkNDQyYjVkOWU1MWE3NDBmMzY5ZTNkY2VjZjMxNzhl
    </auth>
    
  5. サーバーはチャレンジで応答します。チャレンジのデータはbase64でエンコードされています。

    <challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
        cj02ZDQ0MmI1ZDllNTFhNzQwZjM2OWUzZGNlY2YzMTc4ZWMxMmIzOTg1YmJkNGE4ZTZmODE0YjQyMmFiNzY2NTczLHM9UVNYQ1IrUTZzZWs4YmY5MixpPTQwOTY=
    </challenge>
    
  6. クライアントbase64はそれをデコードします:

    r=6d442b5d9e51a740f369e3dcecf3178ec12b3985bbd4a8e6f814b422ab766573,s=QSXCR+Q6sek8bf92,i=4096
    
  7. クライアントはこれを解析します:

    • r=これはserverNonceです。クライアントは、最初のメッセージで送信したclientNonceで始まることを確認する必要があります。
    • s=これはsalt、base64でエンコードされています(はい、これはbase64で2回エンコードされています!)
    • i=これは反復回数iです。
  8. クライアントは以下を計算します:

    clientFinalMessageBare = "c=biws,r=" .. serverNonce
    saltedPassword = PBKDF2-SHA-1(normalizedPassword, salt, i)
    clientKey = HMAC-SHA-1(saltedPassword, "Client Key")
    storedKey = SHA-1(clientKey)
    authMessage = initialMessage .. "," .. serverFirstMessage .. "," .. clientFinalMessageBare
    clientSignature = HMAC-SHA-1(storedKey, authMessage)
    clientProof = clientKey XOR clientSignature
    serverKey = HMAC-SHA-1(saltedPassword, "Server Key")
    serverSignature = HMAC-SHA-1(serverKey, authMessage)
    clientFinalMessage = clientFinalMessageBare .. ",p=" .. base64(clientProof)
    
  9. クライアントbase64はclientFinalMessageをエンコードし、応答として送信します。

    <response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
        Yz1iaXdzLHI9NmQ0NDJiNWQ5ZTUxYTc0MGYzNjllM2RjZWNmMzE3OGVjMTJiMzk4NWJiZDRhOGU2ZjgxNGI0MjJhYjc2NjU3MyxwPXlxbTcyWWxmc2hFTmpQUjFYeGFucG5IUVA4bz0=
    </response>
    
  10. すべてがうまくいけば、サーバーから<success>応答が返されます。

     <success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
         dj1wTk5ERlZFUXh1WHhDb1NFaVc4R0VaKzFSU289
     </success>
    
  11. これをデコードしたBase64には次のものが含まれます。

     v=pNNDFVEQxuXxCoSEiW8GEZ+1RSo=
    
  12. クライアントは、vの値がserverSignatureのbase64エンコーディングであることを確認する必要があります。

エクストラ

これはアルゴリズムの基本バージョンです。次のように拡張できます。

  • チャネルバインディング。これにより、TLS接続からプロシージャへの情報が混合され、MitM攻撃が防止されます。
  • ハッシュストレージ。サーバーが常に同じsaltiの値を送信する場合、クライアントはユーザーのパスワードの代わりにsaltedPasswordのみを保存できます。これは、クライアントが毎回すべてのキーストレッチを行う必要がないため、より安全で(クライアントはパスワードを保存する必要がなく、ソルトハッシュを逆にするのが難しいため)、より高速です。

    サーバーはハッシュストレージを使用することもできます。サーバーはsaltistoredKey、およびserverKeyのみを保存できます。詳細については ここ

  • おそらく、SCRAM-SHA-256も追加します(サーバーのサポートは存在しないようですが)。

落とし穴

いくつかの一般的な落とし穴:

  • ナンスまたはsaltの長さについては何も想定しないでください(ただし、ナンスを生成する場合は、十分な長さで暗号的にランダムであることを確認してください)。
  • saltはbase64でエンコードされており、任意のデータを含めることができます(埋め込まれたNULs)。
  • SASLprepを使用しないと、ASCIIパスワードを使用している場合は正常に機能する可能性がありますが、他のスクリプトを使用している場合はログインが完全に中断する可能性があります。
  • initialMessageauthMessage部分にはGS2ヘッダーが含まれていません(ほとんどの場合、これは"n,,"です)。

テストベクトル

実装をテストする場合は、RFCの例のすべての中間結果を次に示します。

  • ユーザー名:user

  • パスワード:pencil

  • クライアントはランダムナンスを生成しますfyko+d2lbbFgONRv9qkxdawL

  • 最初のメッセージ:n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL

  • サーバーはランダムナンスを生成します3rfcNHYJY1ZVvWVs7j

  • サーバーの応答:r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096

  • 塩(16進数):4125c247e43ab1e93c6dff76

  • クライアントの最終メッセージはむき出しです:c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j

  • 塩味のパスワード(16進数):1d96ee3a529b5a5f9e47c01f229a2cb8a6e15f7d

  • クライアントキー(16進数):e234c47bf6c36696dd6d852b99aaa2ba26555728

  • 保存されたキー(16進数):e9d94660c39d65c38fbad91c358f14da0eef2bd6

  • 認証メッセージ:n=user,r=fyko+d2lbbFgONRv9qkxdawL,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096,c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j

  • クライアントの署名(16進数):5d7138c486b0bfabdf49e3e2da8bd6e5c79db613

  • クライアントプルーフ(16進数):bf45fcbf7073d93d022466c94321745fe1c8e13b

  • サーバーキー(16進数):0fe09258b3ac852ba502cc62ba903eaacdbf7d31

  • サーバー署名(16進数):ae617da6a57c4bbb2e0286568dae1d251905b0a4

  • クライアントの最終メッセージ:c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=

  • サーバーの最終メッセージ:v=rmF9pqV8S7suAoZWja4dJRkFsKQ=

  • サーバーのサーバー署名(16進数):ae617da6a57c4bbb2e0286568dae1d251905b0a4

57
xnyhps