SignalR Güvenliğine Giriş (SignalR 1.x)

Patrick Fletcher, Tom FitzMacken

Uyarı

Bu belgeler SignalR'nin en son sürümüne yönelik değildir. SignalR ASP.NET Core göz atın.

Bu makalede SignalR uygulaması geliştirirken dikkate almanız gereken güvenlik sorunları açıklanmaktadır.

Genel Bakış

Bu belgede aşağıdaki bölümler yer alır:

SignalR Güvenlik Kavramları

Kimlik doğrulaması ve yetkilendirme

SignalR, bir uygulama için mevcut kimlik doğrulama yapısıyla tümleştirilecek şekilde tasarlanmıştır. Kullanıcıların kimliğini doğrulamak için herhangi bir özellik sağlamaz. Bunun yerine, uygulamanızda normalde yaptığınız gibi kullanıcıların kimliğini doğrular ve ardından SignalR kodunuzda kimlik doğrulamasının sonuçlarıyla çalışırsınız. Örneğin, ASP.NET form kimlik doğrulaması ile kullanıcılarınızın kimliğini doğrulayabilir ve ardından hub'ınızda hangi kullanıcıların veya rollerin yöntem çağırma yetkisine sahip olduğunu zorunlu kabilirsiniz. Hub'ınızda, kullanıcı adı veya kullanıcının bir role ait olup olmadığı gibi kimlik doğrulama bilgilerini de istemciye geçirebilirsiniz.

SignalR, hub'a veya yönteme erişimi olan kullanıcıları belirtmek için Authorize özniteliğini sağlar. Authorize özniteliğini bir hub'a veya hub'daki belirli yöntemlere uygularsınız. Authorize özniteliği olmadan, hub'daki tüm genel yöntemler hub'a bağlı bir istemci tarafından kullanılabilir. Hub'lar hakkında daha fazla bilgi için bkz. SignalR Hubs için Kimlik Doğrulaması ve Yetkilendirme.

Authorize özniteliği yalnızca hub'larla kullanılır. kullanırken PersistentConnection yetkilendirme kurallarını zorunlu kılmak için yöntemini geçersiz kılmanız AuthorizeRequest gerekir. Kalıcı bağlantılar hakkında daha fazla bilgi için bkz. SignalR Kalıcı Bağlantıları için Kimlik Doğrulaması ve Yetkilendirme.

Bağlantı belirteci

SignalR, gönderenin kimliğini doğrulayarak kötü amaçlı komutları yürütme riskini azaltır. Kimliği doğrulanmış kullanıcıların bağlantı kimliğini ve kullanıcı adını içeren bir bağlantı belirteci, her istek için istemci ile sunucu arasında geçirilir. Bağlantı kimliği, yeni bir bağlantı oluşturulduğunda sunucu tarafından rastgele oluşturulan ve bağlantı süresince kalıcı hale gelen benzersiz bir tanımlayıcıdır. Kullanıcı adı, web uygulaması için kimlik doğrulama mekanizması tarafından sağlanır. Bağlantı belirteci şifreleme ve dijital imza ile korunur.

İstemci, Sunucu, Kimlik Doğrulama Sistemi ve Bağlantı Belirteci arasındaki ilişkiyi gösteren Diyagram Bağlantı Belirteci sistemi.

Her istek için, sunucu belirtecin içeriğini doğrular ve isteğin belirtilen kullanıcıdan gelmesini sağlar. Kullanıcı adı bağlantı kimliğine karşılık gelir. SignalR, hem bağlantı kimliğini hem de kullanıcı adını doğrulayarak kötü amaçlı bir kullanıcının başka bir kullanıcının kimliğine kolayca bürünmesini engeller. Sunucu bağlantı belirtecini doğrulayamazsa istek başarısız olur.

İstemci, Sunucu ve Kaydedilmiş Belirteç arasındaki ilişkiyi gösteren Bağlantı Belirteci sisteminin diyagramı.

Bağlantı kimliği doğrulama işleminin bir parçası olduğundan, bir kullanıcının bağlantı kimliğini diğer kullanıcılara göstermemeli veya değeri bir tanımlama bilgisinde olduğu gibi istemcide depolamamalısınız.

Yeniden bağlanırken gruplara yeniden katılma

Varsayılan olarak SignalR uygulaması, bağlantı zaman aşımına uğramadan önce bir bağlantının bırakılması ve yeniden kurulması gibi geçici bir kesintiden yeniden bağlanırken kullanıcıyı otomatik olarak uygun gruplara yeniden atar. Yeniden bağlanırken, istemci bağlantı kimliğini ve atanan grupları içeren bir grup belirteci geçirir. Grup belirteci dijital olarak imzalanır ve şifrelenir. İstemci, yeniden bağlantıdan sonra aynı bağlantı kimliğini korur; Bu nedenle, yeniden bağlanan istemciden geçirilen bağlantı kimliği, istemci tarafından kullanılan önceki bağlantı kimliğiyle eşleşmelidir. Bu doğrulama, kötü amaçlı bir kullanıcının yeniden bağlanırken yetkisiz gruplara katılmak için istek geçirmesini engeller.

Ancak, grup belirtecinin süresinin dolmadığını unutmayın. Bir kullanıcı geçmişte bir gruba aitse ancak bu gruptan yasaklanmışsa, bu kullanıcı yasaklanmış grubu içeren bir grup belirtecini taklit edebilir. Hangi kullanıcıların hangi gruplara ait olduğunu güvenli bir şekilde yönetmeniz gerekiyorsa, bu verileri bir veritabanında olduğu gibi sunucuda depolamanız gerekir. Ardından, uygulamanıza bir kullanıcının bir gruba üye olup olmadığını doğrulayan bir mantık ekleyin. Grup üyeliğini doğrulama örneği için bkz. Gruplarla çalışma.

Gruplara otomatik olarak yeniden katılma yalnızca geçici bir kesintiden sonra bağlantı yeniden bağlandığında uygulanır. Bir kullanıcı uygulamadan uzaklaşarak bağlantıyı keserse veya uygulama yeniden başlatılırsa, uygulamanızın bu kullanıcıyı doğru gruplara nasıl ekleyeceğini işlemesi gerekir. Daha fazla bilgi için bkz . Gruplarla çalışma.

SignalR Siteler Arası İstek Sahteciliğini nasıl önler?

Siteler Arası İstek Sahteciliği (CSRF), kötü amaçlı bir sitenin kullanıcının şu anda oturum açtığı savunmasız bir siteye istek gönderdiği bir saldırıdır. SignalR, kötü amaçlı bir sitenin SignalR uygulamanız için geçerli bir istek oluşturmasını çok düşük bir olasılık haline getirerek CSRF'yi engeller.

CSRF saldırısının açıklaması

CsRF saldırısı örneği aşağıda verilmiştir:

  1. Bir kullanıcı form kimlik doğrulaması kullanarak 'de www.example.comoturum açar.

  2. Sunucu kullanıcının kimliğini doğrular. Sunucudan gelen yanıt bir kimlik doğrulama tanımlama bilgisi içerir.

  3. Kullanıcı oturumu kapatmadan kötü amaçlı bir web sitesini ziyaret etti. Bu kötü amaçlı site aşağıdaki HTML formunu içerir:

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

    Form eyleminin kötü amaçlı siteye değil, güvenlik açığı bulunan siteye gönderiler göndermesine dikkat edin. Bu, CSRF'nin "siteler arası" bölümüdür.

  4. Kullanıcı gönder düğmesine tıklar. Tarayıcı, istekle birlikte kimlik doğrulama tanımlama bilgisini içerir.

  5. İstek, kullanıcının kimlik doğrulama bağlamıyla example.com sunucusunda çalışır ve kimliği doğrulanmış bir kullanıcının gerçekleştirmesine izin verilen her şeyi yapabilir.

Bu örnek kullanıcının form düğmesine tıklamasını gerektirse de kötü amaçlı sayfa SignalR uygulamanıza AJAX isteği gönderen bir betiği aynı şekilde kolayca çalıştırabilir. Ayrıca, kötü amaçlı site bir "https://" isteği gönderebileceğinden SSL kullanılması CSRF saldırısını engellemez.

Genellikle, tarayıcılar tüm ilgili tanımlama bilgilerini hedef web sitesine gönderdiğinden kimlik doğrulaması için tanımlama bilgileri kullanan web sitelerine CSRF saldırıları yapılabilir. Ancak CSRF saldırıları tanımlama bilgilerinin kötüye kullanılmayla sınırlı değildir. Örneğin, Temel ve Özet kimlik doğrulaması da savunmasızdır. Kullanıcı Temel veya Özet kimlik doğrulamasıyla oturum açtığında, tarayıcı oturum bitene kadar kimlik bilgilerini otomatik olarak gönderir.

SignalR tarafından alınan CSRF azaltmaları

SignalR, kötü amaçlı bir sitenin SignalR uygulamanıza geçerli istekler oluşturmasını önlemek için aşağıdaki adımları uygular. Bu adımlar varsayılan olarak gerçekleştirilir ve kodunuzda herhangi bir eylem gerektirmez.

  • Etki alanları arası istekleri devre dışı bırakma
    Varsayılan olarak, kullanıcıların bir dış etki alanından SignalR uç noktasını çağırmasını önlemek için signalR uygulamasında etki alanları arası istekler devre dışı bırakılır. Dış etki alanından gelen tüm istekler otomatik olarak geçersiz kabul edilir ve engellenir. Bu varsayılan davranışı korumanız önerilir; aksi takdirde, kötü amaçlı bir site kullanıcıları sitenize komut göndermeleri için kandırabilir. Etki alanları arası istekleri kullanmanız gerekiyorsa, bkz. Etki alanları arası bağlantı kurma .
  • Bağlantı belirtecini tanımlama bilgisinde değil sorgu dizesinde geçirme
    SignalR, bağlantı belirtecini tanımlama bilgisi yerine sorgu dizesi değeri olarak geçirir. Bağlantı belirtecini tanımlama bilgisi olarak depolamadığınızda, kötü amaçlı kodla karşılaşıldığında bağlantı belirteci yanlışlıkla tarayıcı tarafından iletılmaz. Ayrıca, bağlantı belirteci geçerli bağlantının ötesinde kalıcı olmaz. Bu nedenle, kötü amaçlı bir kullanıcı başka bir kullanıcının kimlik doğrulaması kimlik bilgileri altında istekte bulunamaz.
  • Bağlantı belirtecini doğrulama
    Bağlantı belirteci bölümünde açıklandığı gibi, sunucu kimliği doğrulanmış her kullanıcıyla hangi bağlantı kimliğinin ilişkili olduğunu bilir. Sunucu, kullanıcı adıyla eşleşmeyen bir bağlantı kimliğinden gelen hiçbir isteği işlemez. Kötü amaçlı kullanıcının kullanıcı adını ve rastgele oluşturulan geçerli bağlantı kimliğini bilmesi gerekeceğinden, kötü amaçlı bir kullanıcının geçerli bir isteği tahmin etme olasılığı düşüktür. Bağlantı sona erdiği anda bu bağlantı kimliği geçersiz hale gelir. Anonim kullanıcıların hassas bilgilere erişimi olmamalıdır.

SignalR Güvenlik Önerileri

Güvenli Yuva Katmanları (SSL) protokolü

SSL protokolü, bir istemci ile sunucu arasında veri aktarımının güvenliğini sağlamak için şifreleme kullanır. SignalR uygulamanız istemci ve sunucu arasında hassas bilgiler aktarıyorsa, aktarım için SSL kullanın. SSL'yi ayarlama hakkında daha fazla bilgi için bkz. IIS 7'de SSL'yi ayarlama.

Grupları güvenlik mekanizması olarak kullanmayın

Gruplar, ilgili kullanıcıları toplamanın kolay bir yoludur, ancak hassas bilgilere erişimi sınırlamak için güvenli bir mekanizma değildir. Bu durum özellikle kullanıcılar yeniden bağlanma sırasında gruplara otomatik olarak yeniden bağlanabiliyorsa geçerlidir. Bunun yerine, bir role ayrıcalıklı kullanıcılar eklemeyi ve hub yöntemine erişimi yalnızca bu rolün üyeleriyle sınırlamayı göz önünde bulundurun. Rolü temel alarak erişimi kısıtlama örneği için bkz. SignalR Hubs için Kimlik Doğrulaması ve Yetkilendirme. Yeniden bağlanırken gruplara kullanıcı erişimini denetleme örneği için bkz. Gruplarla çalışma.

İstemcilerden gelen girişleri güvenli bir şekilde işleme

Kötü amaçlı bir kullanıcının diğer kullanıcılara betik göndermediğinden emin olmak için diğer istemcilere yayın için tasarlanan istemcilerden gelen tüm girişler kodlanmalıdır. SignalR uygulamanızın birçok farklı istemci türü olabileceğinden, iletileri sunucu yerine alıcı istemcilerde kodlamak en iyisidir. Bu nedenle, HTML kodlaması bir web istemcisi için çalışır, ancak diğer istemci türleri için çalışmaz. Örneğin, bir sohbet iletisini görüntülemek için kullanılan bir web istemcisi yöntemi, işlevi çağırarak html() kullanıcı adını ve iletiyi güvenli bir şekilde işleyebilir.

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

Etkin bağlantıyla kullanıcı durumundaki bir değişikliği mutabıklaştırma

Etkin bir bağlantı varken kullanıcının kimlik doğrulama durumu değişirse, kullanıcı "Etkin signalR bağlantısı sırasında kullanıcı kimliği değiştirilemez" hatasını alır. Bu durumda, bağlantı kimliğinin ve kullanıcı adının eşgüdümlü olduğundan emin olmak için uygulamanızın sunucuya yeniden bağlanması gerekir. Örneğin, uygulamanız etkin bir bağlantı varken kullanıcının oturumunu kapatmasına izin veriyorsa, bağlantının kullanıcı adı artık bir sonraki istek için geçirilen adla eşleşmez. Kullanıcı oturumu kapatmadan önce bağlantıyı durdurmak ve sonra yeniden başlatmak isteyeceksiniz.

Ancak, çoğu uygulamanın bağlantıyı el ile durdurması ve başlatması gerekmeyeceğini unutmayın. Uygulamanız, bir Web Forms uygulamasında veya MVC uygulamasında varsayılan davranış gibi oturumu kapattıktan sonra kullanıcıları ayrı bir sayfaya yönlendirirse veya oturumu kapattıktan sonra geçerli sayfayı yenilerse, etkin bağlantı otomatik olarak kesilir ve ek bir eylem gerektirmez.

Aşağıdaki örnek, kullanıcı durumu değiştiğinde bağlantının nasıl durdurulacağını ve başlatıldığını gösterir.

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

Öte yandan, siteniz Forms Kimlik Doğrulaması ile kayan süre sonu kullanıyorsa ve kimlik doğrulama tanımlama bilgisini geçerli tutacak bir etkinlik yoksa kullanıcının kimlik doğrulama durumu değişebilir. Bu durumda, kullanıcı oturumu kapatılır ve kullanıcı adı artık bağlantı belirtecindeki kullanıcı adıyla eşleşmez. Kimlik doğrulama tanımlama bilgisinin geçerli kalmasını sağlamak için web sunucusundaki bir kaynağı düzenli aralıklarla isteyen bazı betikler ekleyerek bu sorunu çözebilirsiniz. Aşağıdaki örnekte her 30 dakikada bir kaynak isteme gösterilmektedir.

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

Otomatik olarak oluşturulan JavaScript proxy dosyaları

Her kullanıcı için tüm hub'ları ve yöntemleri JavaScript proxy dosyasına eklemek istemiyorsanız, dosyanın otomatik olarak oluşturulmasını devre dışı bırakabilirsiniz. Birden çok hub've yönteminiz varsa ancak her kullanıcının tüm yöntemlerin farkında olmasını istemiyorsanız bu seçeneği belirleyebilirsiniz. EnableJavaScriptProxies ayarını false olarak ayarlayarak otomatik oluşturmayı devre dışı bırakırsınız.

var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableJavaScriptProxies = false;
RouteTable.Routes.MapHubs("/signalr", hubConfiguration);

JavaScript proxy dosyaları hakkında daha fazla bilgi için bkz. Oluşturulan ara sunucu ve sizin için yaptıkları.

Özel durumlar

Özel durum nesnelerini istemcilere geçirmekten kaçınmanız gerekir çünkü nesneler hassas bilgileri istemcilere gösterebilir. Bunun yerine, istemcide ilgili hata iletisini görüntüleyen bir yöntem çağırın.

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.");
    }
}