Catch-22は、WIFによってセキュリティ保護可能なストリーミングTCP WCFサービスを防止します。私のクリスマス、メンタルヘルスを台無しにする


181

WIFを使用してストリーミングされたWCF net.tcpサービスエンドポイントを保護する必要があります。トークンサーバーに対して着信呼び出しを認証する必要があります。このサービスは、大量のデータを転送するように設計されているため、ストリーミングされます。

これは不可能のようです。 そして、もし私が捕まえられない場合、私のクリスマスは台無しになり、陽気な買い物客がゆっくりと冷えている体の上を歩き回る間、私は雨どいの中で自分を飲み殺してしまいます。トート深刻です、皆さん。

なぜこれが不可能なのですか?これがCatch-22です。

クライアントでは、トークンサーバーから取得したGenericXmlSecurityTokenを使用してチャネルを作成する必要があります。問題ありません。

// people around here hate the Framework Design Guidelines.
var token = Authentication.Current._Token;
var service = base.ChannelFactory.CreateChannelWithIssuedToken(token);
return service.Derp();

「問題ありません」と言いましたか?問題。実際には、NullReferenceExceptionスタイルの問題。

「ブロ、」私はフレームワークに尋ねました、「ヌルチェックすらしますか?」フレームワークはサイレントだったので、分解してみた

((IChannel)(object)tChannel).
    GetProperty<ChannelParameterCollection>().
    Add(federatedClientCredentialsParameter);

例外の原因であり、GetProperty呼び出しが返されていたnull。それで、WTF?メッセージセキュリティをオンにして、クライアントの資格情報の種類をに設定するとIssuedToken、このプロパティがに存在することがClientFactoryわかります(ヒント:IChannelには同等の "SetProperty"はありません)。

<binding name="OMGWTFLOL22" transferMode="Streamed" >
    <security mode="Message">
        <message clientCredentialType="IssuedToken"/>
    </security>
</binding>

甘い。NREはもうありません。しかし、今私のクライアントは出生時に失敗しています(まだ彼を愛しています、tho)。WCF診断を掘り下げて(ヒント:最悪の敵を粉砕し、運転する前に運転して、女性と子供の悲嘆を楽しむ直前に)、サーバーとクライアント間のセキュリティの不一致が原因であると思います。

要求されたアップグレードは 'net.tcp:// localhost:49627 / MyService'ではサポートされていません。これは、バインディングの不一致が原因である可能性があります(たとえば、サーバーではなくクライアントでセキュリティが有効になっている)。

ホストの診断をチェックします(ここでも、クラッシュ、ドライブ、ログの読み取り、嘆きをお楽しみください)。これは本当です。

プロトコルタイプapplication / ssl-tlsは、そのタイプのアップグレードをサポートしないサービスに送信されました。

「まあ、私は」と私は言います。「ホストでメッセージセキュリティをオンにします!」そして私はそうします。 それがどのように見えるかを知りたい場合は、クライアント構成の正確なコピーです。調べる。

結果: カブーム。

バインディング( 'NetTcpBinding'、 ' http://tempuri.org/ ')は、メッセージレベルのセキュリティと一緒に構成できないストリーミングをサポートしています。別の転送モードを選択するか、トランスポートレベルのセキュリティを選択することを検討してください。

そのため、私のホストはトークンを介してストリーミングと保護の両方を行うことはできません。キャッチ-22。

tl; dr:WIFを使用して、ストリーミングされたnet.tcp WCFエンドポイントをどのように保護できますか?


3
わかりました、おそらくここでは無知の質問ですが、WIFには本当にメッセージモードが必要ですか?トランスポートモードは、ストリーミングでよりうまく機能するように聞こえます。明らかにテストされていないようなものです<security mode="Transport" /> <transport clientCredentialType="IssuedToken" /> </security>
Joachim Isaksson

3
TransportWithMessageCredentialモードは別のオプションであるかもしれません。
Joachim Isaksson

3
TMLK、MessageSecurityは、バッファされたペイロードに署名して暗号化できますが、ストリームを処理する際に混乱します。authenticationMode = IssuedTokenOverTransportの使用を検討しましたか?
小野仙台2013

7
私が過去の幽霊を召喚してあなたの休日を救うことができるかどうか見てみましょう。ここにいくつかのヒント:social.msdn.microsoft.com/Forums/vstudio/en-US/...
OnoSendai

2
他の人が実験できるテストケースプロジェクトを投稿できる可能性はありますか?
antiduh 2014年

回答:


41

WCFは、ほとんどの人が機能するはずであると考える方法で事前認証を実行できないという根本的な問題が原因で、ストリーミングに関するいくつかの領域(私はMTOM 1を見ている)で問題を抱えています(そのチャネルの後続のリクエストにのみ影響します) 、最初のリクエストではありません)わかりました。これは正確にあなたの問題ではありませんが、最後にあなたの問題にたどり着くので、それに従ってください。通常、HTTPチャレンジは次のように機能します。

  1. クライアントは匿名でサーバーにアクセスします
  2. サーバーによると、申し訳ありません、401、認証が必要です
  3. クライアントが認証トークンでサーバーにアクセスする
  4. サーバーは受け入れます。

これで、サーバー上のWCFエンドポイントでMTOMストリーミングを有効にしようとしても、文句は言われません。ただし、それをクライアントプロキシで構成すると(必要に応じて、バインディングと一致する必要があります)、爆発して爆発します。これは、WCFが防止しようとしている上記の一連のイベントがこれに該当するためです。

  1. クライアントは100MBのファイルを1つのPOSTで匿名でサーバーにストリーミングします
  2. サーバーは申し訳ありません、401、私は認証が必要です
  3. クライアントは認証ヘッダーを使用してサーバーに100MBファイルを再度ストリーミングします
  4. サーバーは受け入れます。

100MBを送信するだけでよいのに、サーバーに200MBを送信したことに注意してください。さて、これが問題です。答えは、最初の試行で認証を送信することですが、カスタム動作を記述せずにWCFでこれを行うことはできません。とにかく、私は余談です。

あなたの問題

まず最初に、あなたが試みていることは不可能であることをお伝えしましょう2。さて、あなたがあなたの車輪の回転を止めるために、私に理由を教えさせてください:

あなたは今、同様のクラスの問題をさまようしていることに私は驚かされます。メッセージレベルのセキュリティを有効にする場合、クライアントは、通常のハッシュ関数とws-securityが必要とするxml署名でメッセージを実際に閉じる前に、データのストリーム全体をメモリにロードする必要があります。ストリーム全体を読み取って単一のメッセージ(実際にはメッセージではありませんが、単一の連続したストリーム)に署名する必要がある場合は、ここで問題を確認できます。WCFは、メッセージのセキュリティを計算するために「ローカルに」一度ストリーミングし、サーバーに送信するために再度ストリーミングする必要があります。これは明らかにばかげたことなので、WCFはストリーミングデータのメッセージレベルのセキュリティを許可していません。

したがって、ここでの簡単な答えは、最初のWebサービスへのパラメーターとして、またはSOAPヘッダーとしてトークンを送信し、カスタム動作を使用してそれを検証する必要があるということです。WS-Securityを使用してこれを行うことはできません。率直に言って、これはWCFの問題だけではありません。他のスタックで実際にどのように機能するかはわかりません。

MTOM問題の解決

これは、基本認証でMTOMストリーミングの問題を解決した方法の例にすぎないため、これを直感的に理解し、同様の問題を実装できます。重要なのは、カスタムメッセージインスペクタを有効にするために、トランスポートレベル(SSL)を除いて、クライアントプロキシのセキュリティのすべての概念を無効にする必要があることです(サーバーでは有効のままです)。

this._contentService.Endpoint.Behaviors.Add(
    new BasicAuthenticationBehavior(
        username: this.Settings.HttpUser,
        password: this.Settings.HttpPass));
var binding = (BasicHttpBinding)this._contentService.Endpoint.Binding;
binding.Security.Mode = BasicHttpSecurityMode.Transport; // SSL only            
binding.Security.Transport.ClientCredentialType = 
   HttpClientCredentialType.None; // Do not provide

メッセージインスペクタとカスタム動作を使用して自分で提供するため、ここではトランスポートセキュリティをオフにしていることに注意してください。

internal class BasicAuthenticationBehavior : IEndpointBehavior
{
    private readonly string _username;
    private readonly string _password;

    public BasicAuthenticationBehavior(string username, string password)
    {
        this._username = username;
        this._password = password;
    }
    public void AddBindingParameters(ServiceEndpoint endpoint, 
        BindingParameterCollection bindingParameters) { }
    public void ApplyClientBehavior(ServiceEndpoint endpoint,
        ClientRuntime clientRuntime)
    {
        var inspector = new BasicAuthenticationInspector(
            this._username, this._password);
        clientRuntime.MessageInspectors.Add(inspector);
    }
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
        EndpointDispatcher endpointDispatcher) { }
    public void Validate(ServiceEndpoint endpoint) { }
}

internal class BasicAuthenticationInspector : IClientMessageInspector
{
    private readonly string _username;
    private readonly string _password;

    public BasicAuthenticationInspector(string username, string password)
    {
        this._username = username;
        this._password = password;
    }

    public void AfterReceiveReply(ref Message reply,
        object correlationState) { }

    public object BeforeSendRequest(ref Message request,
        IClientChannel channel)
    {
        // we add the headers manually rather than using credentials 
        // due to proxying issues, and with the 101-continue http verb 
        var authInfo = Convert.ToBase64String(
            Encoding.Default.GetBytes(this._username + ":" + this._password));

        var messageProperty = new HttpRequestMessageProperty();
        messageProperty.Headers.Add("Authorization", "Basic " + authInfo);
        request.Properties[HttpRequestMessageProperty.Name] = messageProperty;

        return null;
    }
}

したがって、この例は、MTOMの問題に苦しんでいる人を対象としていますが、主要なWIFで保護されたトークンサービスによって生成されたトークンを認証するようなものを実装するためのスケルトンとしても使用できます。

お役に立てれば。

(1)大きなデータとストリーミング

(2)WCFのメッセージセキュリティ(「欠点」を参照)


MTOM and Basic Authorization、およびMTOMとOAuth2
Kiquenet
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.