Catch-22 mencegah layanan TCP WCF yang dialirkan dapat diamankan oleh WIF; merusak Natal saya, kesehatan mental

181

Saya memiliki persyaratan untuk mengamankan titik akhir layanan WCF net.tcp menggunakan WIF . Seharusnya mengotentikasi panggilan masuk terhadap server token kami. Layanan dialirkan karena dirancang untuk mentransfer sejumlah besar data dan barang.

Tampaknya ini mustahil. Dan jika saya tidak bisa mengatasi tangkapan, Natal saya akan hancur dan saya akan minum sampai mati dalam selokan sementara pembeli yang ceria melangkahi tubuh saya yang perlahan-lahan dingin. Totes serius, kalian.

Mengapa ini tidak mungkin? Inilah Catch-22.

Di klien, saya perlu membuat saluran dengan GenericXmlSecurityToken yang saya dapatkan dari server token kami. Tidak masalah.

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

Apakah saya mengatakan "tidak masalah"? Problemo. Bahkan, NullReferenceExceptionstyle problemo.

"Bro," aku bertanya pada Framework, "apakah kamu bahkan membatalkan cek?" Kerangka kerja itu diam, jadi saya membongkar dan menemukan itu

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

adalah sumber pengecualian, dan bahwa GetPropertypanggilan itu kembali null. Jadi, WTF? Ternyata jika saya mengaktifkan Keamanan pesan dan menetapkan tipe kredensial klien untuk IssuedTokenmaka properti ini sekarang ada di ClientFactory(protip: Tidak ada setara "SetProperty" di IChannel, bajingan itu).

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

Manis. Tidak ada lagi NRE. Namun, sekarang klien saya salah sejak lahir (masih mencintainya, tho). Menggali melalui diagnosa WCF (protip: membuat musuh terburuk Anda melakukan ini setelah menghancurkan mereka dan mengarahkan mereka sebelum Anda tetapi tepat sebelum menikmati ratapan wanita dan anak-anak mereka), saya melihat itu karena ketidakcocokan keamanan antara server dan klien.

Pembaruan yang diminta tidak didukung oleh 'net.tcp: // localhost: 49627 / MyService'. Ini bisa jadi karena binding yang tidak cocok (misalnya keamanan diaktifkan pada klien dan bukan pada server).

Memeriksa diags host (lagi: naksir, drive, baca log, nikmati ratapan), saya melihat ini benar

Aplikasi Jenis Protokol / ssl-tls dikirim ke layanan yang tidak mendukung jenis peningkatan itu.

"Yah, sendiri," kataku, "Aku hanya akan mengaktifkan keamanan pesan pada tuan rumah!" Dan saya lakukan. Jika Anda ingin tahu seperti apa itu, itu adalah salinan persis konfigurasi klien. Menengadah.

Hasil: Kaboom.

Penjilidan ('NetTcpBinding', ' http://tempuri.org/ ') mendukung streaming yang tidak dapat dikonfigurasi bersama dengan keamanan tingkat pesan. Pertimbangkan memilih mode transfer yang berbeda atau memilih keamanan tingkat transportasi.

Jadi, host saya tidak dapat di-stream dan diamankan melalui token . Catch-22.

tl; dr: Bagaimana cara mengamankan endpoint WCF net.tcp yang dialirkan menggunakan WIF ???

BoltClock
sumber
3
Ok, mungkin pertanyaan bodoh di sini, tetapi apakah WIF benar-benar memerlukan mode Pesan? Mode transport kedengarannya akan bekerja lebih baik dengan streaming, sesuatu seperti yang jelas belum teruji<security mode="Transport" /> <transport clientCredentialType="IssuedToken" /> </security>
Joachim Isaksson
3
TransportWithMessageCredentialmode dapat menjadi pilihan lain.
Joachim Isaksson
3
TMLK, MessageSecurity dapat menandatangani dan mengenkripsi payload buffered, tetapi gagal ketika berhadapan dengan stream. Sudahkah Anda mempertimbangkan untuk menggunakan otentikasiMode = IssuedTokenOverTransport?
OnoSendai
7
Biarkan saya melihat apakah saya dapat memanggil beberapa hantu dari masa lalu untuk membantu menyelamatkan liburan Anda. Beberapa petunjuk di sini: social.msdn.microsoft.com/Forums/vstudio/en-US/…
OnoSendai
2
Kesempatan Anda dapat memposting proyek kasus uji yang orang lain dapat bereksperimen dengan?
antiduh

Jawaban:

41

WCF memiliki beberapa peluang dalam streaming dengan beberapa hal (saya melihat Anda, MTOM 1 ) karena masalah mendasar dalam bagaimana ia gagal melakukan preauthentication dengan cara kebanyakan orang akan berpikir bahwa itu harus bekerja (itu hanya mempengaruhi permintaan berikutnya untuk saluran itu , bukan permintaan pertama) Ok, jadi ini bukan masalah Anda tapi tolong ikuti karena saya akan sampai ke Anda di akhir. Biasanya tantangan HTTP berfungsi seperti ini:

  1. klien menyentuh server secara anonim
  2. Server mengatakan, maaf, 401, saya perlu otentikasi
  3. client hits server dengan token otentikasi
  4. server menerima.

Sekarang, jika Anda pernah mencoba mengaktifkan streaming MTOM pada titik akhir WCF di server, itu tidak akan mengeluh. Tetapi, ketika Anda mengkonfigurasinya pada proksi klien (seperti seharusnya, mereka harus cocok dengan binding) itu akan meledak dalam kematian yang berapi-api. Alasan untuk ini adalah bahwa urutan kejadian di atas yang berusaha dicegah WCF adalah ini:

  1. klien stream file 100MB ke server secara anonim dalam satu POST
  2. Server mengatakan maaf, 401, saya perlu otentikasi
  3. klien lagi stream file 100MB ke server dengan header otentikasi
  4. server menerima.

Perhatikan bahwa Anda baru saja mengirim 200MB ke server ketika Anda hanya perlu mengirim 100MB. Nah, ini masalahnya. Jawabannya adalah mengirim otentikasi pada upaya pertama tetapi ini tidak mungkin di WCF tanpa menulis perilaku khusus. Lagi pula, saya ngelantur.

Masalahmu

Pertama, izinkan saya memberi tahu Anda bahwa apa yang Anda coba tidak mungkin 2 . Sekarang, agar Anda berhenti memutar roda Anda, izinkan saya memberi tahu Anda alasannya:

Itu mengejutkan saya bahwa Anda sekarang berkeliaran di kelas masalah yang sama. Jika Anda mengaktifkan keamanan tingkat pesan, klien harus memuat seluruh aliran data ke dalam memori sebelum benar-benar dapat menutup pesan dengan fungsi hash biasa dan tanda tangan xml yang diperlukan oleh keamanan-ws. Jika harus membaca seluruh aliran untuk menandatangani pesan tunggal (yang bukan benar-benar pesan, tetapi itu adalah aliran berkelanjutan tunggal) maka Anda dapat melihat masalahnya di sini. WCF harus melakukan streaming sekali "secara lokal" untuk menghitung keamanan pesan, kemudian mengalirkannya lagi untuk mengirimnya ke server. Ini jelas hal yang konyol, jadi WCF tidak mengizinkan keamanan tingkat pesan untuk streaming data.

Jadi, jawaban sederhana di sini adalah bahwa Anda harus mengirim token baik sebagai parameter ke layanan web awal, atau sebagai header SOAP dan menggunakan perilaku khusus untuk memvalidasinya. Anda tidak dapat menggunakan WS-Security untuk melakukan ini. Terus terang, ini bukan hanya masalah WCF - Saya tidak bisa melihat bagaimana ini bisa bekerja untuk tumpukan lainnya.

Memecahkan Masalah MTOM

Ini hanya untuk contoh bagaimana saya memecahkan masalah streaming MTOM saya untuk otentikasi dasar, jadi mungkin Anda bisa mengambil keberanian ini dan mengimplementasikan sesuatu yang serupa untuk masalah Anda. Intinya adalah untuk mengaktifkan inspektur pesan khusus Anda, Anda harus menonaktifkan semua gagasan keamanan pada proksi klien (tetap diaktifkan di server,) selain dari level transportasi (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

Perhatikan bahwa saya telah mematikan keamanan transportasi di sini karena saya akan menyediakannya sendiri menggunakan inspektur pesan dan perilaku khusus:

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;
    }
}

Jadi, contoh ini adalah untuk siapa saja yang menderita masalah MTOM, tetapi juga sebagai kerangka bagi Anda untuk menerapkan sesuatu yang serupa untuk mengautentikasi token Anda yang dihasilkan oleh layanan token utama yang diamankan oleh WIF.

Semoga ini membantu.

(1) Data Besar dan Streaming

(2) Keamanan Pesan di WCF (lihat "kerugian.")

x0n
sumber
MTOM and Basic Authorization, dan MTOM dan OAuth2 ?
Kiquenet