Introduktion till SignalR Security

av Patrick Fletcher, Tom FitzMacken

Varning

Den här dokumentationen gäller inte för den senaste versionen av SignalR. Ta en titt på ASP.NET Core SignalR.

I den här artikeln beskrivs de säkerhetsproblem som du måste tänka på när du utvecklar ett SignalR-program.

Programvaruversioner som används i det här avsnittet

Tidigare versioner av det här ämnet

Information om tidigare versioner av SignalR finns i Äldre SignalR-versioner.

Frågor och kommentarer

Lämna gärna feedback om hur du uppskattade den här handledningen och vad vi kan förbättra i kommentarerna längst ned på sidan. Om du har frågor som inte är direkt relaterade till självstudien kan du skicka dem till ASP.NET SignalR-forumet eller StackOverflow.com.

Översikt

Det här dokumentet innehåller följande avsnitt:

SignalR-säkerhetsbegrepp

Autentisering och auktorisering

SignalR tillhandahåller inga funktioner för autentisering av användare. I stället integrerar du SignalR-funktionerna i den befintliga autentiseringsstrukturen för ett program. Du autentiserar användare som vanligt i ditt program och arbetar med resultatet av autentiseringen i SignalR-koden. Du kan till exempel autentisera dina användare med ASP.NET formulärautentisering och sedan framtvinga vilka användare eller roller som har behörighet att anropa en metod i hubben. I din hubb kan du också skicka autentiseringsinformation, till exempel användarnamn eller om en användare tillhör en roll, till klienten.

SignalR tillhandahåller attributet Auktorisera för att ange vilka användare som har åtkomst till en hubb eller metod. Du använder attributet Auktorisera för antingen en hubb eller vissa metoder i en hubb. Utan attributet Auktorisera är alla offentliga metoder på hubben tillgängliga för en klient som är ansluten till hubben. Mer information om hubbar finns i Autentisering och auktorisering för SignalR Hubs.

Du använder Authorize attributet för hubbar, men inte beständiga anslutningar. Om du vill tillämpa auktoriseringsregler när du använder en PersistentConnection måste du åsidosätta AuthorizeRequest metoden. Mer information om beständiga anslutningar finns i Autentisering och auktorisering för Beständiga SignalR-anslutningar.

Anslutningstoken

SignalR minskar risken för att köra skadliga kommandon genom att verifiera avsändarens identitet. För varje begäran skickar klienten och servern en anslutningstoken som innehåller anslutnings-ID och användarnamn för autentiserade användare. Anslutnings-ID:t identifierar unikt varje ansluten klient. Servern genererar slumpmässigt anslutnings-ID:t när en ny anslutning skapas och bevarar det ID:t under anslutningens varaktighet. Autentiseringsmekanismen för webbprogrammet innehåller användarnamnet. SignalR använder kryptering och en digital signatur för att skydda anslutningstoken.

Diagram som visar en pil från Klientens nya anslutningsbegäran till server mottagen anslutningsbegäran till serversvar på mottaget svar från klienten. Autentiseringssystemet genererar en anslutningstoken i rutorna Svar och Mottaget svar.

För varje begäran verifierar servern innehållet i token för att säkerställa att begäran kommer från den angivna användaren. Användarnamnet måste motsvara anslutnings-ID:t. Genom att verifiera både anslutnings-ID:t och användarnamnet förhindrar SignalR att en obehörig användare enkelt utger sig för att vara en annan användare. Om servern inte kan verifiera anslutningstoken misslyckas begäran.

Diagram som visar en pil från klientbegäran till server mottagen begäran till sparad token. Anslutningstoken och meddelandet finns både i rutan Klient och i rutan Server.

Eftersom anslutnings-ID är en del av verifieringsprocessen bör du inte avslöja en användares anslutnings-ID för andra användare eller lagra värdet på klienten, till exempel i en cookie.

Anslutningstoken jämfört med andra tokentyper

Anslutningstoken flaggas ibland av säkerhetsverktyg eftersom de verkar vara sessionstoken eller autentiseringstoken, vilket utgör en risk om de exponeras.

SignalR:s anslutningstoken är inte en autentiseringstoken. Den används för att bekräfta att användaren som gör den här begäran är samma som skapade anslutningen. Anslutningstoken är nödvändig eftersom ASP.NET SignalR tillåter anslutningar att flytta mellan servrar. Token associerar anslutningen med en viss användare men bekräftar inte identiteten för den användare som gör begäran. För att en SignalR-begäran ska autentiseras korrekt måste den ha någon annan token som bekräftar användarens identitet, till exempel en cookie eller ägartoken. Själva anslutningstoken gör dock inget anspråk på att begäran gjordes av användaren, bara att anslutnings-ID:t i token är associerat med den användaren.

Eftersom anslutningstoken inte ger något eget autentiseringsanspråk betraktas den inte som en "session" eller "autentiseringstoken". Det går inte att ta en viss användares anslutningstoken och spela upp den i en begäran som autentiserats som en annan användare (eller en oautentiserad begäran), eftersom användaridentiteten för begäran och identiteten som lagras i token inte matchar.

Återansluta till grupper vid återanslutning

Som standard tilldelar SignalR-programmet automatiskt en användare till lämpliga grupper när de återansluter från ett tillfälligt avbrott, till exempel när en anslutning tas bort och återupprättas innan anslutningen överskrider tidsgränsen. När du återansluter skickar klienten en grupptoken som innehåller anslutnings-ID:t och de tilldelade grupperna. Grupptoken är digitalt signerad och krypterad. Klienten behåller samma anslutnings-ID efter en återanslutning. Därför måste anslutnings-ID:t som skickades från den återanslutna klienten matcha det tidigare anslutnings-ID som användes av klienten. Den här verifieringen hindrar en obehörig användare från att skicka begäranden om att ansluta till obehöriga grupper vid återanslutning.

Det är dock viktigt att notera att grupptoken inte upphör att gälla. Om en användare tidigare tillhörde en grupp, men förbjöds från den gruppen, kanske användaren kan efterlikna en grupptoken som innehåller den förbjudna gruppen. Om du behöver hantera vilka användare som tillhör vilka grupper på ett säkert sätt måste du lagra dessa data på servern, till exempel i en databas. Lägg sedan till logik i ditt program som verifierar på servern om en användare tillhör en grupp. Ett exempel på hur du verifierar gruppmedlemskap finns i Arbeta med grupper.

Automatiskt återanslutna grupper gäller endast när en anslutning återansluts efter ett tillfälligt avbrott. Om en användare kopplar från genom att navigera bort från programmet eller om programmet startas om, måste programmet hantera hur användaren ska läggas till i rätt grupper. Mer information finns i Arbeta med grupper.

Så här förhindrar SignalR förfalskning av begäranden mellan webbplatser

Förfalskning av begäranden mellan webbplatser (CSRF) är ett angrepp där en skadlig webbplats skickar en begäran till en sårbar webbplats där användaren för närvarande är inloggad. SignalR förhindrar CSRF genom att göra det extremt osannolikt för en skadlig webbplats att skapa en giltig begäran för ditt SignalR-program.

Beskrivning av CSRF-attack

Här är ett exempel på en CSRF-attack:

  1. En användare loggar in på www.example.com, med hjälp av formulärautentisering.

  2. Servern autentiserar användaren. Svaret från servern innehåller en autentiseringscookie.

  3. Utan att logga ut besöker användaren en skadlig webbplats. Den här skadliga webbplatsen innehåller följande HTML-formulär:

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

    Observera att formuläråtgärden skickas till den sårbara webbplatsen, inte till den skadliga webbplatsen. Det här är "cross-site"-delen av CSRF.

  4. Användaren klickar på knappen Skicka. Webbläsaren innehåller autentiseringscookien med begäran.

  5. Begäran körs på example.com-servern med användarens autentiseringskontext och kan göra allt som en autentiserad användare får göra.

Även om det här exemplet kräver att användaren klickar på formulärknappen kan den skadliga sidan lika enkelt köra ett skript som skickar en AJAX-begäran till ditt SignalR-program. Dessutom förhindrar inte användning av SSL en CSRF-attack, eftersom den skadliga webbplatsen kan skicka en "https://"-begäran.

Normalt är CSRF-attacker möjliga mot webbplatser som använder cookies för autentisering, eftersom webbläsare skickar alla relevanta cookies till målwebbplatsen. CSRF-attacker är dock inte begränsade till att utnyttja cookies. Till exempel är grundläggande och sammanfattad autentisering också sårbara. När en användare har loggat in med Basic- eller Digest-autentisering skickar webbläsaren automatiskt autentiseringsuppgifterna tills sessionen är slut.

Åtgärder för att motverka CSRF som genomförs av SignalR

SignalR vidtar följande steg för att förhindra att en skadlig webbplats skapar giltiga begäranden till ditt program. SignalR vidtar dessa steg som standard. Du behöver inte vidta några åtgärder i koden.

  • Inaktivera begäranden mellan domäner SignalR inaktiverar begäranden mellan domäner för att förhindra att användare anropar en SignalR-slutpunkt från en extern domän. SignalR anser att alla förfrågningar från en extern domän är ogiltiga och blockerar begäran. Vi rekommenderar att du behåller det här standardbeteendet. Annars kan en skadlig webbplats lura användare att skicka kommandon till din webbplats. Om du behöver använda begäranden mellan domäner kan du läsa Så här upprättar du en anslutning mellan domäner .
  • Skicka anslutningstoken i frågesträngen, inte cookien SignalR skickar anslutningstoken som ett frågesträngsvärde i stället för som en cookie. Det är osäkert att lagra anslutningstoken i en cookie eftersom webbläsaren oavsiktligt kan vidarebefordra anslutningstoken när skadlig kod påträffas. Att skicka anslutningstoken i frågesträngen förhindrar också att anslutningstoken bevaras utanför den aktuella anslutningen. Därför kan en obehörig användare inte göra en begäran under en annan användares autentiseringsuppgifter.
  • Verifiera anslutningstoken Enligt beskrivningen i avsnittet Anslutningstoken vet servern vilket anslutnings-ID som är associerat med varje autentiserad användare. Servern bearbetar inte någon begäran från ett anslutnings-ID som inte matchar användarnamnet. Det är osannolikt att en obehörig användare kan gissa en giltig begäran eftersom den skadliga användaren måste känna till användarnamnet och det aktuella slumpmässigt genererade anslutnings-ID:t. Anslutnings-ID:t blir ogiltigt så snart anslutningen har avslutats. Anonyma användare bör inte ha åtkomst till känslig information.

SignalR-säkerhetsrekommendationer

SSL-protokoll (Secure Socket Layer)

SSL-protokollet använder kryptering för att skydda dataöverföringen mellan en klient och en server. Om SignalR-programmet överför känslig information mellan klienten och servern använder du SSL för transporten. Mer information om hur du konfigurerar SSL finns i Så här konfigurerar du SSL på IIS 7.

Använd inte grupper som en säkerhetsmekanism

Grupper är ett praktiskt sätt att samla in relaterade användare, men de är inte en säker mekanism för att begränsa åtkomsten till känslig information. Detta gäller särskilt när användare automatiskt kan återansluta grupper under en återanslutning. Överväg i stället att lägga till privilegierade användare i en roll och begränsa åtkomsten till en hubbmetod till endast medlemmar i den rollen. Ett exempel på hur du begränsar åtkomst baserat på en roll finns i Autentisering och auktorisering för SignalR Hubs. Ett exempel på hur du kontrollerar användaråtkomst till grupper vid återanslutning finns i Arbeta med grupper.

Hantera indata från klienter på ett säkert sätt

För att säkerställa att en obehörig användare inte skickar skript till andra användare måste du koda alla indata från klienter som är avsedda för sändning till andra klienter. Du bör koda meddelanden på de mottagande klienterna i stället för servern, eftersom signalR-programmet kan ha många olika typer av klienter. Därför fungerar HTML-kodning för en webbklient, men inte för andra typer av klienter. Till exempel skulle en webbklientmetod för att visa ett chattmeddelande hantera användarnamnet och meddelandet på ett säkert sätt genom att anropa html() funktionen.

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

Avstämning av en ändring i användarstatus med en aktiv anslutning

Om en användares autentiseringsstatus ändras när det finns en aktiv anslutning får användaren ett felmeddelande om att användarens identitet inte kan ändras under en aktiv SignalR-anslutning. I så fall bör programmet återansluta till servern för att se till att anslutnings-ID:t och användarnamnet är koordinerade. Om ditt program till exempel tillåter att användaren loggar ut medan det finns en aktiv anslutning matchar inte längre användarnamnet för anslutningen det namn som skickas för nästa begäran. Du vill stoppa anslutningen innan användaren loggar ut och sedan starta om den.

Observera dock att de flesta program inte behöver stoppa och starta anslutningen manuellt. Om ditt program omdirigerar användare till en separat sida efter utloggning, till exempel standardbeteendet i ett webbformulärprogram eller ett MVC-program, eller uppdaterar den aktuella sidan efter utloggning, kopplas den aktiva anslutningen automatiskt från och kräver ingen ytterligare åtgärd.

I följande exempel visas hur du stoppar och startar en anslutning när användarstatusen har ändrats.

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

Eller så kan användarens autentiseringsstatus ändras om din webbplats använder glidande förfallotid med formulärautentisering och det inte finns någon aktivitet för att hålla autentiseringscookien giltig. I så fall loggas användaren ut och användarnamnet matchar inte längre användarnamnet i anslutningstoken. Du kan åtgärda det här problemet genom att lägga till ett skript som regelbundet begär en resurs på webbservern för att hålla autentiseringscookien giltig. I följande exempel visas hur du begär en resurs var 30:e minut.

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

Automatiskt genererade JavaScript-proxyfiler

Om du inte vill inkludera alla hubbar och metoder i JavaScript-proxyfilen för varje användare kan du inaktivera den automatiska genereringen av filen. Du kan välja det här alternativet om du har flera hubbar och metoder, men inte vill att alla användare ska känna till alla metoder. Du inaktiverar automatisk generering genom att ange EnableJavaScriptProxies till false.

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

Mer information om JavaScript-proxyfilerna finns i Den genererade proxyn och vad den gör åt dig.

Undantag

Du bör undvika att skicka undantagsobjekt till klienter eftersom objekten kan exponera känslig information för klienterna. Anropa i stället en metod på klienten som visar relevant felmeddelande.

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