Úvod do zabezpečení knihovnou SignalR
Patrick Fletcher, Tom FitzMacken
Upozornění
Tato dokumentace není určená pro nejnovější verzi služby SignalR. Podívejte se na ASP.NET Core SignalR.
Tento článek popisuje problémy se zabezpečením, které je potřeba vzít v úvahu při vývoji aplikace SignalR.
Verze softwaru použité v tomto tématu
- Visual Studio 2013
- .NET 4.5
- SignalR verze 2
Předchozí verze tohoto tématu
Informace o starších verzích služby SignalR najdete v tématu Starší verze služby SignalR.
Dotazy a komentáře
V komentářích v dolní části stránky nám napište, jak se vám tento kurz líbil a co bychom mohli zlepšit. Pokud máte dotazy, které nesouvisejí přímo s kurzem, můžete je publikovat na fóru ASP.NET SignalR nebo StackOverflow.com.
Přehled
Tento dokument obsahuje následující části:
Koncepty zabezpečení služby SignalR
Ověřování a autorizace
SignalR neposkytuje žádné funkce pro ověřování uživatelů. Místo toho integrujete funkce SignalR do stávající struktury ověřování pro aplikaci. Uživatele ověřujete obvyklým způsobem ve své aplikaci a pracujete s výsledky ověřování v kódu SignalR. Můžete například ověřit uživatele pomocí ověřování pomocí ASP.NET formulářů a pak v centru vynutit, kteří uživatelé nebo role mají oprávnění volat metodu. V centru můžete klientovi předat také ověřovací informace, jako je uživatelské jméno nebo to, jestli uživatel patří do role.
SignalR poskytuje atribut Authorize ( Autorizovat ), který určuje, kteří uživatelé mají přístup k centru nebo metodě. Atribut Authorize použijete buď na centrum, nebo na konkrétní metody v centru. Bez atributu Authorize jsou všechny veřejné metody v centru k dispozici klientovi, který je připojený k centru. Další informace o centrech najdete v tématu Ověřování a autorizace pro centra SignalR.
Atribut použijete Authorize
na centra, ale ne trvalá připojení. Pokud chcete vynutit autorizační pravidla při použití , PersistentConnection
musíte přepsat metodu AuthorizeRequest
. Další informace o trvalých připojeních najdete v tématu Ověřování a autorizace pro trvalá připojení SignalR.
Token připojení
SignalR snižuje riziko spuštění škodlivých příkazů tím, že ověřuje identitu odesílatele. Pro každý požadavek předávají klient a server token připojení, který obsahuje ID připojení a uživatelské jméno pro ověřené uživatele. ID připojení jednoznačně identifikuje každého připojeného klienta. Server náhodně vygeneruje ID připojení při vytvoření nového připojení a toto ID zachová po dobu trvání připojení. Mechanismus ověřování webové aplikace poskytuje uživatelské jméno. SignalR používá k ochraně tokenu připojení šifrování a digitální podpis.
U každého požadavku server ověří obsah tokenu, aby se zajistilo, že požadavek pochází od zadaného uživatele. Uživatelské jméno musí odpovídat ID připojení. Tím, že signalR ověřuje ID připojení i uživatelské jméno, zabrání uživateli se zlými úmysly ve snadném zosobnění jiného uživatele. Pokud server nemůže ověřit token připojení, požadavek selže.
Vzhledem k tomu, že ID připojení je součástí procesu ověřování, neměli byste id připojení jednoho uživatele prozrazovat jiným uživatelům ani hodnotu ukládat v klientovi, například v souboru cookie.
Tokeny připojení vs. jiné typy tokenů
Nástroje zabezpečení občas označí tokeny připojení příznakem, protože se zdá, že se jedná o tokeny relací nebo ověřovací tokeny, které v případě zveřejnění představují riziko.
Token připojení služby SignalR není ověřovacím tokenem. Slouží k potvrzení, že uživatel, který tento požadavek vytváří, je stejný jako uživatel, který vytvořil připojení. Token připojení je nezbytný, protože ASP.NET SignalR umožňuje přesun připojení mezi servery. Token přidruží připojení ke konkrétnímu uživateli, ale neuplatňuje identitu uživatele, který požadavek vytváří. Aby se požadavek SignalR správně ověřil, musí mít nějaký jiný token, který potvrzuje identitu uživatele, například soubor cookie nebo nosný token. Samotný token připojení však netvrdí, že požadavek byl proveden tímto uživatelem, pouze id připojení obsažené v tokenu je přidruženo k tomuto uživateli.
Vzhledem k tomu, že token připojení neposkytuje žádnou vlastní deklaraci identity ověřování, nepovažuje se za "relaci" ani "ověřovací" token. Převzetí tokenu připojení daného uživatele a jeho přehrání v požadavku ověřeném jako jiný uživatel (nebo neověřený požadavek) selže, protože identita uživatele požadavku a identita uložená v tokenu se neshodují.
Opětovné připojení ke skupinám při opětovném připojování
Ve výchozím nastavení aplikace SignalR automaticky znovu přiřadí uživatele k příslušným skupinám při opětovném připojení z dočasného přerušení, například když dojde k ukončení a opětovnému navázání připojení před vypršením časového limitu připojení. Při opětovném připojení klient předá token skupiny, který obsahuje ID připojení a přiřazené skupiny. Token skupiny je digitálně podepsaný a zašifrovaný. Klient si po opětovném připojení zachová stejné ID připojení. PROTO MUSÍ ID připojení předané z znovupřipojeného klienta odpovídat předchozímu ID připojení použitému klientem. Toto ověření zabrání uživateli se zlými úmysly v předávání žádostí o připojení k neoprávněným skupinám při opětovném připojení.
Je však důležité si uvědomit, že platnost tokenu skupiny nevyprší. Pokud uživatel v minulosti patřil do skupiny, ale byl z této skupiny zakázán, může být tento uživatel schopen napodobit token skupiny, který obsahuje zakázanou skupinu. Pokud potřebujete bezpečně spravovat, kteří uživatelé patří do kterých skupin, musíte tato data uložit na serveru, například do databáze. Pak do aplikace přidejte logiku, která na serveru ověří, jestli uživatel patří do skupiny. Příklad ověření členství ve skupinách najdete v tématu Práce se skupinami.
Automatické opětovné připojení ke skupinám se použije jenom v případě, že se připojení po dočasném přerušení znovu připojí. Pokud se uživatel odpojí přechodem mimo aplikaci nebo se aplikace restartuje, musí aplikace zpracovat způsob přidání uživatele do správných skupin. Další informace najdete v tématu Práce se skupinami.
Jak SignalR zabraňuje padělání požadavků napříč weby
Útok CSRF (Cross-Site Request Forgery) je útok, kdy škodlivý web odešle požadavek na ohrožený web, na kterém je uživatel aktuálně přihlášený. SignalR brání CSRF tím, že je velmi nepravděpodobné, aby škodlivý web vytvořil platný požadavek pro vaši aplikaci SignalR.
Popis útoku CSRF
Tady je příklad útoku CSRF:
Uživatel se přihlásí k www.example.com pomocí ověřování pomocí formulářů.
Server ověří uživatele. Odpověď ze serveru obsahuje ověřovací soubor cookie.
Bez odhlášení uživatel navštíví škodlivý web. Tento škodlivý web obsahuje následující formulář HTML:
<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>
Všimněte si, že akce formuláře odešle příspěvek na ohrožený web, ne na škodlivý web. Toto je část CSRF "mezi weby".
Uživatel klikne na tlačítko Odeslat. Prohlížeč do požadavku zahrne ověřovací soubor cookie.
Požadavek se spouští na example.com serveru s kontextem ověřování uživatele a může provádět cokoliv, co má ověřený uživatel povoleno.
I když tento příklad vyžaduje, aby uživatel klikl na tlačítko formuláře, škodlivá stránka by mohla stejně snadno spustit skript, který odešle požadavek AJAX do aplikace SignalR. Navíc použití PROTOKOLU SSL nezabrání útoku CSRF, protože škodlivý web může odeslat požadavek na "https://".
Útoky CSRF jsou obvykle možné na weby, které k ověřování používají soubory cookie, protože prohlížeče odesílají všechny relevantní soubory cookie na cílový web. Útoky CSRF se však neomezují pouze na zneužití souborů cookie. Například základní ověřování a ověřování hodnotou hash jsou také ohroženy. Jakmile se uživatel přihlásí pomocí základního ověřování nebo ověřování hash, prohlížeč automaticky odešle přihlašovací údaje až do ukončení relace.
Zmírnění rizik CSRF, která provádí SignalR
Služba SignalR provede následující kroky, aby zabránila škodlivému webu ve vytváření platných požadavků na vaši aplikaci. SignalR ve výchozím nastavení provádí tyto kroky, v kódu nemusíte provádět žádnou akci.
- Zákaz mezidoménových požadavků SignalR zakáže žádosti mezi doménami, aby uživatelům zabránila volat koncový bod Služby SignalR z externí domény. SignalR považuje všechny požadavky z externí domény za neplatné a zablokuje ho. Doporučujeme zachovat toto výchozí chování; Jinak by škodlivý web mohl oklamat uživatele, aby na váš web odesílali příkazy. Pokud potřebujete použít žádosti mezi doménou, přečtěte si téma Jak navázat připojení mezi doménou .
- Předání tokenu připojení v řetězci dotazu, ne v souboru cookie SignalR předá token připojení jako hodnotu řetězce dotazu místo jako soubor cookie. Uložení tokenu připojení do souboru cookie je nebezpečné, protože prohlížeč může neúmyslně předat token připojení, když se zjistí škodlivý kód. Předání tokenu připojení v řetězci dotazu také zabrání tomu, aby token připojení zůstal zachován i nad rámec aktuálního připojení. Uživatel se zlými úmysly proto nemůže vytvořit žádost pod přihlašovacími údaji jiného uživatele.
- Ověření tokenu připojení Jak je popsáno v části Token připojení , server ví, které ID připojení je přidružené ke každému ověřenému uživateli. Server nezpracuje žádné požadavky z ID připojení, které neodpovídá uživatelskému jménu. Je nepravděpodobné, že by uživatel se zlými úmysly mohl uhodnout platný požadavek, protože by uživatel se zlými úmysly musel znát uživatelské jméno a aktuální náhodně generované ID připojení. Toto ID připojení se stane neplatným, jakmile se připojení ukončí. Anonymní uživatelé by neměli mít přístup k žádným citlivým informacím.
Doporučení k zabezpečení služby SignalR
Protokol SSL (Secure Socket Layer)
Protokol SSL používá šifrování k zabezpečení přenosu dat mezi klientem a serverem. Pokud vaše aplikace SignalR přenáší citlivé informace mezi klientem a serverem, použijte k přenosu protokol SSL. Další informace o nastavení SSL najdete v tématu Nastavení SSL ve službě IIS 7.
Nepoužívejte skupiny jako mechanismus zabezpečení.
Skupiny představují pohodlný způsob shromažďování souvisejících uživatelů, ale nepředstavují bezpečný mechanismus pro omezení přístupu k citlivým informacím. To platí zejména v případě, že se uživatelé můžou automaticky znovu připojit ke skupinám během opětovného připojení. Místo toho zvažte přidání privilegovaných uživatelů do role a omezení přístupu k metodě centra pouze na členy této role. Příklad omezení přístupu na základě role najdete v tématu Ověřování a autorizace pro SignalR Hubs. Příklad kontroly přístupu uživatelů ke skupinám při opětovném připojování najdete v tématu Práce se skupinami.
Bezpečné zpracování vstupu od klientů
Chcete-li zajistit, aby uživatel se zlými úmysly neodesílal skript ostatním uživatelům, musíte zakódovat veškerý vstup z klientů, který je určen pro vysílání do jiných klientů. Zprávy byste měli kódovat na přijímajících klientech místo na serveru, protože vaše aplikace SignalR může mít mnoho různých typů klientů. Kódování HTML proto funguje pro webového klienta, ale ne pro jiné typy klientů. Například metoda webového klienta pro zobrazení zprávy chatu by bezpečně zpracovávala uživatelské jméno a zprávu voláním html()
funkce .
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>');
};
Odsouhlasení změny stavu uživatele s aktivním připojením
Pokud se stav ověřování uživatele změní, když existuje aktivní připojení, zobrazí se uživateli chyba s oznámením, že během aktivního připojení SignalR se identita uživatele nemůže změnit. V takovém případě by se vaše aplikace měla znovu připojit k serveru, aby se zajistilo, že ID připojení a uživatelské jméno jsou sladěné. Pokud například aplikace umožňuje, aby se uživatel odhlašil, když existuje aktivní připojení, uživatelské jméno pro připojení se už nebude shodovat s názvem předaným pro další požadavek. Před odhlášením uživatele budete chtít zastavit připojení a pak ho restartovat.
Je však důležité si uvědomit, že většina aplikací nebude muset ručně zastavovat a spouštět připojení. Pokud vaše aplikace přesměruje uživatele po odhlášení na samostatnou stránku, například výchozí chování v Web Forms aplikaci nebo aplikaci MVC, nebo aktualizuje aktuální stránku po odhlášení, aktivní připojení se automaticky odpojí a nevyžaduje žádnou další akci.
Následující příklad ukazuje, jak zastavit a spustit připojení při změně stavu uživatele.
<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>
Nebo se stav ověřování uživatele může změnit, pokud váš web používá posuvné vypršení platnosti s ověřováním pomocí formulářů a neexistuje žádná aktivita, která by zachovala platnost ověřovacího souboru cookie. V takovém případě bude uživatel odhlášený a uživatelské jméno se už nebude shodovat s uživatelským jménem v tokenu připojení. Tento problém můžete vyřešit přidáním skriptu, který pravidelně vyžaduje prostředek na webovém serveru, aby ověřovací soubor cookie zůstal platný. Následující příklad ukazuje, jak každých 30 minut požádat o prostředek.
$(function () {
setInterval(function() {
$.ajax({
url: "Ping.aspx",
cache: false
});
}, 1800000);
});
Automaticky generované soubory proxy javascriptu
Pokud nechcete zahrnout všechna centra a metody do proxy souboru JavaScriptu pro každého uživatele, můžete zakázat automatické generování souboru. Tuto možnost můžete zvolit, pokud máte více center a metod, ale nechcete, aby každý uživatel věděl o všech metodách. Automatické generování zakážete nastavením EnableJavaScriptProxies na false.
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableJavaScriptProxies = false;
app.MapSignalR(hubConfiguration);
Další informace o souborech proxy javascriptu najdete v tématu vygenerovaný proxy server a jeho funkce.
Výjimky
Měli byste se vyhnout předávání objektů výjimek klientům, protože objekty mohou klientům vystavit citlivé informace. Místo toho v klientovi zavolejte metodu, která zobrazí příslušnou chybovou zprávu.
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.");
}
}