Bagikan melalui


Pengantar SignalR Security

oleh Patrick Fletcher, Tom FitzMacken

Peringatan

Dokumentasi ini bukan untuk versi terbaru SignalR. Lihatlah ASP.NET Core SignalR.

Artikel ini menjelaskan masalah keamanan yang harus Anda pertimbangkan saat mengembangkan aplikasi SignalR.

Versi perangkat lunak yang digunakan dalam topik ini

Versi sebelumnya dari topik ini

Untuk informasi tentang versi SignalR yang lebih lama, lihat Versi Lama SignalR.

Pertanyaan dan komentar

Silakan tinggalkan umpan balik tentang bagaimana Anda menyukai tutorial ini dan apa yang dapat kami tingkatkan di komentar di bagian bawah halaman. Jika Anda memiliki pertanyaan yang tidak terkait langsung dengan tutorial, Anda dapat mempostingnya ke forum ASP.NET SignalR atau StackOverflow.com.

Gambaran Umum

Dokumen ini berisi bagian berikut:

Konsep Keamanan SignalR

Autentikasi dan Otorisasi

SignalR tidak menyediakan fitur apa pun untuk mengautentikasi pengguna. Sebagai gantinya, Anda mengintegrasikan fitur SignalR ke dalam struktur autentikasi yang ada untuk aplikasi. Anda mengautentikasi pengguna seperti biasanya di aplikasi Anda, dan bekerja dengan hasil autentikasi dalam kode SignalR Anda. Misalnya, Anda dapat mengautentikasi pengguna dengan autentikasi formulir ASP.NET, lalu di hub Anda, menerapkan pengguna atau peran mana yang berwenang untuk memanggil metode. Di hub, Anda juga dapat meneruskan informasi autentikasi, seperti nama pengguna atau apakah pengguna termasuk dalam peran, kepada klien.

SignalR menyediakan atribut Otorisasi untuk menentukan pengguna mana yang memiliki akses ke hub atau metode. Anda menerapkan atribut Otorisasi ke hub atau metode tertentu di hub. Tanpa atribut Otorisasi, semua metode publik di hub tersedia untuk klien yang terhubung ke hub. Untuk informasi selengkapnya tentang hub, lihat Autentikasi dan Otorisasi untuk SignalR Hubs.

Anda menerapkan atribut ke Authorize hub, tetapi bukan koneksi persisten. Untuk menerapkan aturan otorisasi saat menggunakan, PersistentConnection Anda harus mengambil AuthorizeRequest alih metode . Untuk informasi selengkapnya tentang koneksi persisten, lihat Autentikasi dan Otorisasi untuk Koneksi Persisten SignalR.

Token koneksi

SignalR mengurangi risiko menjalankan perintah berbahaya dengan memvalidasi identitas pengirim. Untuk setiap permintaan, klien dan server meneruskan token koneksi yang berisi id koneksi dan nama pengguna untuk pengguna yang diautentikasi. Id koneksi secara unik mengidentifikasi setiap klien yang terhubung. Server secara acak menghasilkan id koneksi saat koneksi baru dibuat, dan mempertahankan id tersebut selama durasi koneksi. Mekanisme autentikasi untuk aplikasi web menyediakan nama pengguna. SignalR menggunakan enkripsi dan tanda tangan digital untuk melindungi token koneksi.

Diagram yang memperlihatkan panah dari Permintaan Koneksi Baru Klien ke Permintaan Koneksi yang Diterima Server ke Respons Server ke Respons yang Diterima Klien. Sistem Autentikasi menghasilkan Token Koneksi dalam kotak Respons dan Respons yang Diterima.

Untuk setiap permintaan, server memvalidasi konten token untuk memastikan bahwa permintaan berasal dari pengguna yang ditentukan. Nama pengguna harus sesuai dengan id koneksi. Dengan memvalidasi id koneksi dan nama pengguna, SignalR mencegah pengguna jahat dengan mudah meniru pengguna lain. Jika server tidak dapat memvalidasi token koneksi, permintaan gagal.

Diagram yang memperlihatkan panah dari Permintaan Klien ke Server Menerima Permintaan ke Token Tersimpan. Token Koneksi dan Pesan ada di kotak Klien dan kotak Server.

Karena id koneksi adalah bagian dari proses verifikasi, Anda tidak boleh mengungkapkan id koneksi satu pengguna kepada pengguna lain atau menyimpan nilai pada klien, seperti di cookie.

Token koneksi vs. jenis token lainnya

Token koneksi kadang-kadang ditandai oleh alat keamanan karena tampaknya merupakan token sesi atau token autentikasi, yang menimbulkan risiko jika terekspos.

Token koneksi SignalR bukan token autentikasi. Ini digunakan untuk mengonfirmasi bahwa pengguna yang membuat permintaan ini sama dengan yang membuat koneksi. Token koneksi diperlukan karena ASP.NET SignalR memungkinkan koneksi berpindah antar server. Token mengaitkan koneksi dengan pengguna tertentu tetapi tidak menegaskan identitas pengguna yang membuat permintaan. Agar permintaan SignalR diautentikasi dengan benar, permintaan tersebut harus memiliki beberapa token lain yang menegaskan identitas pengguna, seperti cookie atau token pembawa. Namun, token koneksi itu sendiri tidak membuat klaim bahwa permintaan dibuat oleh pengguna tersebut, hanya ID koneksi yang terkandung dalam token yang terkait dengan pengguna tersebut.

Karena token koneksi tidak menyediakan klaim autentikasi sendiri, token tersebut tidak dianggap sebagai token "sesi" atau "autentikasi". Mengambil token koneksi pengguna tertentu dan memutar ulang dalam permintaan yang diautentikasi sebagai pengguna lain (atau permintaan yang tidak diautentikasi) akan gagal, karena identitas pengguna permintaan dan identitas yang disimpan dalam token tidak akan cocok.

Bergabung kembali dengan grup saat menyambungkan kembali

Secara default, aplikasi SignalR akan secara otomatis menetapkan ulang pengguna ke grup yang sesuai saat menyambungkan kembali dari gangguan sementara, seperti ketika koneksi diputuskan dan dibuat ulang sebelum waktu koneksi habis. Saat menyambungkan kembali, klien meneruskan token grup yang menyertakan id koneksi dan grup yang ditetapkan. Token grup ditandatangani dan dienkripsi secara digital. Klien mempertahankan id koneksi yang sama setelah koneksi ulang; oleh karena itu, id koneksi yang diteruskan dari klien yang terhubung kembali harus cocok dengan id koneksi sebelumnya yang digunakan oleh klien. Verifikasi ini mencegah pengguna jahat meneruskan permintaan untuk bergabung dengan grup yang tidak sah saat menyambungkan kembali.

Namun, penting untuk dicatat, bahwa token grup tidak kedaluwarsa. Jika pengguna termasuk dalam grup di masa lalu, tetapi dilarang dari grup tersebut, pengguna tersebut mungkin dapat menimpulkan token grup yang menyertakan grup yang dilarang. Jika Anda perlu mengelola pengguna mana yang termasuk dalam grup mana dengan aman, Anda perlu menyimpan data tersebut di server, seperti dalam database. Kemudian, tambahkan logika ke aplikasi Anda yang memverifikasi di server apakah pengguna termasuk dalam grup. Untuk contoh memverifikasi keanggotaan grup, lihat Bekerja dengan grup.

Bergabung kembali grup secara otomatis hanya berlaku saat koneksi disambungkan kembali setelah gangguan sementara. Jika pengguna terputus dengan menavigasi menjauh dari aplikasi atau aplikasi dimulai ulang, aplikasi Anda harus menangani cara menambahkan pengguna tersebut ke grup yang benar. Untuk informasi selengkapnya, lihat Bekerja dengan grup.

Bagaimana SignalR mencegah Pemalsuan Permintaan Lintas Situs

Pemalsuan Permintaan Lintas Situs (CSRF) adalah serangan di mana situs berbahaya mengirim permintaan ke situs yang rentan tempat pengguna saat ini masuk. SignalR mencegah CSRF dengan membuatnya sangat tidak mungkin bagi situs berbahaya untuk membuat permintaan yang valid untuk aplikasi SignalR Anda.

Deskripsi serangan CSRF

Berikut adalah contoh serangan CSRF:

  1. Pengguna masuk ke www.example.com, menggunakan autentikasi formulir.

  2. Server mengautentikasi pengguna. Respons dari server menyertakan cookie autentikasi.

  3. Tanpa keluar, pengguna mengunjungi situs web berbahaya. Situs berbahaya ini berisi formulir HTML berikut:

    <h1>You Are a Winner!</h1>
    <form action="http://example.com/api/account" method="post">
        <input type="hidden" name="Transaction" value="withdraw" />
        <input type="hidden" name="Amount" value="1000000" />
        <input type="submit" value="Click Me"/>
    </form>
    

    Perhatikan bahwa tindakan formulir memposting ke situs yang rentan, bukan ke situs berbahaya. Ini adalah bagian "lintas situs" dari CSRF.

  4. Pengguna mengklik tombol kirim. Browser menyertakan cookie autentikasi dengan permintaan.

  5. Permintaan berjalan di server example.com dengan konteks autentikasi pengguna, dan dapat melakukan apa pun yang diizinkan untuk dilakukan oleh pengguna terautentikasi.

Meskipun contoh ini mengharuskan pengguna untuk mengklik tombol formulir, halaman berbahaya bisa dengan mudah menjalankan skrip yang mengirim permintaan AJAX ke aplikasi SignalR Anda. Selain itu, menggunakan SSL tidak mencegah serangan CSRF, karena situs berbahaya dapat mengirim permintaan "https://".

Biasanya, serangan CSRF dimungkinkan terhadap situs web yang menggunakan cookie untuk autentikasi, karena browser mengirim semua cookie yang relevan ke situs web tujuan. Namun, serangan CSRF tidak terbatas pada mengeksploitasi cookie. Misalnya, autentikasi Dasar dan Hash juga rentan. Setelah pengguna masuk dengan autentikasi Dasar atau Hash, browser secara otomatis mengirim kredensial hingga sesi berakhir.

Mitigasi CSRF yang diambil oleh SignalR

SignalR mengambil langkah-langkah berikut untuk mencegah situs berbahaya membuat permintaan yang valid ke aplikasi Anda. SignalR mengambil langkah-langkah ini secara default, Anda tidak perlu mengambil tindakan apa pun dalam kode Anda.

  • Menonaktifkan permintaan lintas domain SignalR menonaktifkan permintaan lintas domain untuk mencegah pengguna memanggil titik akhir SignalR dari domain eksternal. SignalR menganggap setiap permintaan dari domain eksternal tidak valid dan memblokir permintaan. Kami menyarankan agar Anda menjaga perilaku default ini; jika tidak, situs berbahaya dapat mengelabui pengguna untuk mengirim perintah ke situs Anda. Jika Anda perlu menggunakan permintaan lintas domain, lihat Cara membuat koneksi lintas domain .
  • Meneruskan token koneksi dalam string kueri, bukan cookie SignalR meneruskan token koneksi sebagai nilai string kueri, bukan sebagai cookie. Menyimpan token koneksi dalam cookie tidak aman karena browser secara tidak sengaja dapat meneruskan token koneksi ketika kode berbahaya ditemui. Selain itu, meneruskan token koneksi dalam string kueri mencegah token koneksi bertahan di luar koneksi saat ini. Oleh karena itu, pengguna berbahaya tidak dapat membuat permintaan berdasarkan kredensial autentikasi pengguna lain.
  • Memverifikasi token koneksi Seperti yang dijelaskan di bagian Token koneksi , server mengetahui id koneksi mana yang terkait dengan setiap pengguna yang diautentikasi. Server tidak memproses permintaan apa pun dari id koneksi yang tidak cocok dengan nama pengguna. Tidak mungkin pengguna berbahaya dapat menebak permintaan yang valid karena pengguna jahat harus mengetahui nama pengguna dan id koneksi yang dihasilkan secara acak saat ini. Id koneksi tersebut menjadi tidak valid segera setelah koneksi berakhir. Pengguna anonim tidak boleh memiliki akses ke informasi sensitif apa pun.

Rekomendasi Keamanan SignalR

Protokol Secure Socket Layers (SSL)

Protokol SSL menggunakan enkripsi untuk mengamankan pengangkutan data antara klien dan server. Jika aplikasi SignalR Anda mengirimkan informasi sensitif antara klien dan server, gunakan SSL untuk transportasi. Untuk informasi selengkapnya tentang menyiapkan SSL, lihat Cara menyiapkan SSL di IIS 7.

Jangan gunakan grup sebagai mekanisme keamanan

Grup adalah cara mudah untuk mengumpulkan pengguna terkait, tetapi mereka bukan mekanisme yang aman untuk membatasi akses ke informasi sensitif. Ini terutama berlaku ketika pengguna dapat secara otomatis bergabung kembali dengan grup selama koneksi ulang. Sebagai gantinya, pertimbangkan untuk menambahkan pengguna istimewa ke peran dan membatasi akses ke metode hub hanya untuk anggota peran tersebut. Untuk contoh pembatasan akses berdasarkan peran, lihat Autentikasi dan Otorisasi untuk SignalR Hubs. Untuk contoh memeriksa akses pengguna ke grup saat menyambungkan kembali, lihat Bekerja dengan grup.

Menangani input dengan aman dari klien

Untuk memastikan bahwa pengguna jahat tidak mengirim skrip ke pengguna lain, Anda harus mengodekan semua input dari klien yang ditujukan untuk siaran ke klien lain. Anda harus mengodekan pesan pada klien penerima daripada server, karena aplikasi SignalR Anda mungkin memiliki banyak jenis klien yang berbeda. Oleh karena itu, pengodean HTML berfungsi untuk klien web, tetapi tidak untuk jenis klien lain. Misalnya, metode klien web untuk menampilkan pesan obrolan akan menangani nama pengguna dan pesan dengan aman dengan memanggil html() fungsi .

chat.client.addMessageToPage = function (name, message) {
    // Html encode display name and message. 
    var encodedName = $('<div />').text(name).html();
    var encodedMsg = $('<div />').text(message).html();
    // Add the message to the page. 
    $('#discussion').append('<li><strong>' + encodedName
        + '</strong>:  ' + encodedMsg + '</li>');
};

Mendamaikan perubahan status pengguna dengan koneksi aktif

Jika status autentikasi pengguna berubah saat ada koneksi aktif, pengguna akan menerima kesalahan yang menyatakan, "Identitas pengguna tidak dapat berubah selama koneksi SignalR aktif." Dalam hal ini, aplikasi Anda harus terhubung kembali ke server untuk memastikan id koneksi dan nama pengguna dikoordinasikan. Misalnya, jika aplikasi Anda memungkinkan pengguna untuk keluar saat koneksi aktif ada, nama pengguna untuk koneksi tidak akan lagi cocok dengan nama yang diteruskan untuk permintaan berikutnya. Anda akan ingin menghentikan koneksi sebelum pengguna keluar, lalu memulai ulang.

Namun, penting untuk dicatat bahwa sebagian besar aplikasi tidak perlu menghentikan dan memulai koneksi secara manual. Jika aplikasi Anda mengalihkan pengguna ke halaman terpisah setelah keluar, seperti perilaku default dalam aplikasi Formulir Web atau aplikasi MVC, atau me-refresh halaman saat ini setelah keluar, koneksi aktif secara otomatis terputus dan tidak memerlukan tindakan tambahan.

Contoh berikut menunjukkan cara menghentikan dan memulai koneksi saat status pengguna telah berubah.

<script type="text/javascript">
    $(function () {
        var chat = $.connection.sampleHub;
        $.connection.hub.start().done(function () {
            $('#logoutbutton').click(function () {
                chat.connection.stop();
                $.ajax({
                    url: "Services/SampleWebService.svc/LogOut",
                    type: "POST"
                }).done(function () {
                    chat.connection.start();
                });
            });
        });
    });
</script>

Atau, status autentikasi pengguna dapat berubah jika situs Anda menggunakan kedaluwarsa geser dengan Autentikasi Formulir, dan tidak ada aktivitas untuk menjaga cookie autentikasi tetap valid. Dalam hal ini, pengguna akan keluar dan nama pengguna tidak akan lagi cocok dengan nama pengguna dalam token koneksi. Anda dapat memperbaiki masalah ini dengan menambahkan beberapa skrip yang secara berkala meminta sumber daya di server web agar cookie autentikasi tetap valid. Contoh berikut menunjukkan cara meminta sumber daya setiap 30 menit.

$(function () {
    setInterval(function() {
        $.ajax({
            url: "Ping.aspx",
            cache: false
        });
    }, 1800000);
});

File proksi JavaScript yang dihasilkan secara otomatis

Jika Anda tidak ingin menyertakan semua hub dan metode dalam file proksi JavaScript untuk setiap pengguna, Anda dapat menonaktifkan pembuatan otomatis file. Anda dapat memilih opsi ini jika Anda memiliki beberapa hub dan metode, tetapi tidak ingin setiap pengguna menyadari semua metode. Anda menonaktifkan pembuatan otomatis dengan mengatur EnableJavaScriptProxies ke false.

var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableJavaScriptProxies = false;
app.MapSignalR(hubConfiguration);

Untuk informasi selengkapnya tentang file proksi JavaScript, lihat Proksi yang dihasilkan dan apa fungsinya untuk Anda.

Pengecualian

Anda harus menghindari meneruskan objek pengecualian ke klien karena objek dapat mengekspos informasi sensitif kepada klien. Sebagai gantinya, panggil metode pada klien yang menampilkan pesan kesalahan yang relevan.

public Task SampleMethod()
{
    try
    { 
        // code that can throw an exception
    }
    catch(Exception e)
    {
        // add code to log exception and take remedial steps

        return Clients.Caller.DisplayError("Sorry, the request could not be processed.");
    }
}