3

現在、SourceForgeのSPNEGO ライブラリを使用して、SPNEGO で保護された Web サービスに Java クライアントを実装しようとしています (サーバーは同じライブラリを使用しています)。正常に認証できません。リクエストは常に次のようになります

HTTP/1.1 500 Failure unspecified at GSS-API level (Mechanism level: Checksum failed)

これは、不適切なホスト名を使用してブラウザーから Web サービスにアクセスしたときに発生する症状に似ています。実際、Wireshark でのデバッグによって、クライアントが要求で間違った SPN を送信していることが明らかになりました。SPNservice-test.client.comとして登録されているに送信します。およびADNS にレコードがありますが、Windows ドメインに として登録されていますserver-1234.client.corp。リクエストを送信してもhttp://service-test.client.com(一致するHostヘッダーを参照)、Java がチケットをリクエストする SPN は「内部」Windows 名です。

HTTP 要求の Wireshark デコード

Chrome または IE から送信された同じものには、一致するHostヘッダーと SPN があります。

ここに画像の説明を入力

私のコードや SPNEGO ライブラリではこの変換は行われていないので、JRE のどこかで行われているに違いないと推測します。JGSSのソースを調べてみたのですが、ちょっとわかりにくいです。この翻訳をスキップして正しい SPN のチケットを取得する方法を誰か教えてもらえますか?

クライアントコード:

SpnegoHttpURLConnection con = new SpnegoHttpURLConnection("spnego-client", user, password);
con.connect(new URL("http://service-test.client.com:8083/service"));
int rc = con.getResponseCode();
String msg = con.getResponseMessage();
4

1 に答える 1

4

上記のコメントからの要約:

DNSを再確認してください。逆引き参照を実行します。ほとんどの問題は、誤った逆引きDNSエントリから発生します。

RFC2713の85ページは、RFC4120をチェックし、「canon」を検索するのに役立つ場合があります。

ホストベースのサービスのSPNがGSS-APIを使用して構築されている場合、ターゲットメカニズムを使用してその名前を正規化する必要があります。RFCは言う

このタイプの名前への参照が解決されると、「ホスト名」は(実装戦略の例として)DNSルックアップを試行し、返される完全修飾ドメイン名を使用するか、「ホスト名」を使用して正規化できます。 DNSルックアップが失敗した場合に提供されます。正規化操作では、ホストの名前も小文字にマップされます。

Kerberos 5RFCが言うところ:

サーバーと送信時。したがって、たとえば、攻撃者がマッピングを変更して偽装する可能性があるため、保護されていないDNSレコードに依存して、ホストエイリアスをサーバーのプライマリ名にマッピングし、プライマリ名を接続先として受け入れるべきではありません。パーティ。

KerberosおよびKerberosに基づくプロトコルの実装では、安全でないDNSクエリを使用してサービスプリンシパル名のホスト名コンポーネントを正規化してはなりません(つまり、安全でないDNSクエリを使用して、ある名前を別の名前にマップして、プリンシパル名のホスト部分を決定してはなりません。どちらが通信するか)。セキュアネームサービスのない環境では、アプリケーションの作成者は、静的に構成されたドメイン名を、セキュリティメカニズムに名前を渡す前に、修飾されていないホスト名に追加できますが、それ以上は実行しないでください。安全なネームサービス機能は、利用可能な場合、ホスト名の正規化について信頼できる可能性がありますが、クライアントによるそのような正規化は、KDCの実装では必要とされるべきではありません。

実装上の注意:現在の多くの実装では、提供されたサービス名をある程度正規化しており、セキュリティ上の問題が発生したとしても、DNSを使用することがよくあります。ただし、サービス名が大文字と小文字で折りたたまれているか、逆解像度が使用されているかについては、実装間で一貫性がありません。相互運用性とセキュリティを最大化するために、アプリケーションは、他の変更や正規化を実行せずに、ユーザーが入力した名前を小文字に折りたたむことで生じる名前をセキュリティメカニズムに提供する必要があります。

GSS-API implsは正規化する可能性があるようですが、DNSが信頼できない場合、Kerberosは正規化するべきではありません。ですからそれは状況次第です。逆引き参照が行われるのは完全に自然なことです。これは、Kerberosがホスト名を検証する方法です。DNSラウンドロビンを実行している場合、これは実際には非常に重要です。それがなければ、実際のSPNを構築することはできません。

私は実際にKerberosメーリングリストでこれを行いますが。これは非常に興味深い点です。

krb5_sname_to_principalMIT Kerberosの実装を確認しましたが、次のソースコードを確認すると、実際にこれを行う方法がありsn2princ.cます。

if (type == KRB5_NT_SRV_HST) {
        struct addrinfo *ai = NULL, hints;
        int err;
        char hnamebuf[NI_MAXHOST];

        /* Note that the old code would accept numeric addresses,
           and if the gethostbyaddr step could convert them to
           real hostnames, you could actually get reasonable
           results.  If the mapping failed, you'd get dotted
           triples as realm names.  *sigh*

           The latter has been fixed in hst_realm.c, but we should
           keep supporting numeric addresses if they do have
           hostnames associated.  */

        memset(&hints, 0, sizeof(hints));
        hints.ai_flags = AI_CANONNAME;
        err = getaddrinfo(hostname, 0, &hints, &ai);
        if (err) {
#ifdef DEBUG_REFERRALS
            printf("sname_to_princ: failed to canonicalize %s; using as-is", hostname);
#endif
        }
        remote_host = strdup((ai && ai->ai_canonname) ? ai->ai_canonname : hostname);
        if (!remote_host) {
            if(ai)
                freeaddrinfo(ai);
            return ENOMEM;
        }

        if ((!err) && maybe_use_reverse_dns(context, DEFAULT_RDNS_LOOKUP)) {
            /*
             * Do a reverse resolution to get the full name, just in
             * case there's some funny business going on.  If there
             * isn't an in-addr record, give up.
             */
            /* XXX: This is *so* bogus.  There are several cases where
               this won't get us the canonical name of the host, but
               this is what we've trained people to expect.  We'll
               probably fix it at some point, but let's try to
               preserve the current behavior and only shake things up
               once when it comes time to fix this lossage.  */
            err = getnameinfo(ai->ai_addr, ai->ai_addrlen,
                              hnamebuf, sizeof(hnamebuf), 0, 0, NI_NAMEREQD);
            freeaddrinfo(ai);
            if (err == 0) {
                free(remote_host);
                remote_host = strdup(hnamebuf);
                if (!remote_host)
                    return ENOMEM;
            }
        } else
            freeaddrinfo(ai);
    }

だから、私たちはメーリングリストで尋ねなければならないと思います。

于 2012-09-03T18:29:02.660 に答える