Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
von Patrick Fletcher, Tom FitzMacken
Warnung
Diese Dokumentation ist nicht für die neueste Version von SignalR vorgesehen. Sehen Sie sich ASP.NET Core SignalR an.
In diesem Artikel werden die Sicherheitsprobleme beschrieben, die Sie beim Entwickeln einer SignalR-Anwendung berücksichtigen müssen.
In diesem Thema verwendete Softwareversionen
- Visual Studio 2013
- .NET 4.5
- SignalR Version 2
Frühere Versionen dieses Themas
Informationen zu früheren Versionen von SignalR finden Sie unter "Ältere Versionen von SignalR".
Fragen und Kommentare
Bitte geben Sie Feedback dazu, wie Ihnen dieses Lernprogramm gefallen hat und was wir in den Kommentaren unten auf der Seite verbessern könnten. Wenn Sie Fragen haben, die nicht direkt mit dem Lernprogramm zusammenhängen, können Sie sie im ASP.NET SignalR-Forum oder StackOverflow.com posten.
Überblick
Dieses Dokument enthält die folgenden Abschnitte:
SignalR-Sicherheitskonzepte
Authentifizierung und Autorisierung
SignalR bietet keine Features für die Authentifizierung von Benutzern. Stattdessen integrieren Sie die SignalR-Features in die vorhandene Authentifizierungsstruktur für eine Anwendung. Sie authentifizieren Benutzer wie normalerweise in Ihrer Anwendung und arbeiten mit den Ergebnissen der Authentifizierung in Ihrem SignalR-Code. Beispielsweise können Sie Ihre Benutzer mit ASP.NET Formularauthentifizierung authentifizieren und dann in Ihrem Hub erzwingen, welche Benutzer oder Rollen zum Aufrufen einer Methode autorisiert sind. In Ihrem Hub können Sie auch Authentifizierungsinformationen wie benutzername oder ob ein Benutzer zu einer Rolle gehört, an den Client übergeben.
SignalR stellt das Authorize-Attribut bereit, um anzugeben, welche Benutzer Zugriff auf einen Hub oder eine Methode haben. Sie wenden das Authorize-Attribut entweder auf einen Hub oder bestimmte Methoden in einem Hub an. Ohne das Authorize-Attribut sind alle öffentlichen Methoden auf dem Hub für einen Client verfügbar, der mit dem Hub verbunden ist. Weitere Informationen zu Hubs finden Sie unter Authentifizierung und Autorisierung für SignalR-Hubs.
Sie wenden das Authorize
Attribut auf Hubs an, aber nicht auf dauerhafte Verbindungen. Zum Erzwingen von Autorisierungsregeln bei der Verwendung einer PersistentConnection
müssen Sie die AuthorizeRequest
Methode überschreiben. Weitere Informationen zu beständigen Verbindungen finden Sie unter Authentifizierung und Autorisierung für persistente SignalR-Verbindungen.
Token für die Verbindung
SignalR verringert das Risiko, böswillige Befehle auszuführen, indem die Identität des Absenders überprüft wird. Für jede Anforderung übergeben der Client und der Server ein Verbindungstoken, das die Verbindungs-ID und den Benutzernamen für authentifizierte Benutzer enthält. Die Verbindungs-ID identifiziert jeden verbundenen Client eindeutig. Der Server generiert zufällig die Verbindungs-ID, wenn eine neue Verbindung erstellt wird, und speichert diese ID für die Dauer der Verbindung. Der Authentifizierungsmechanismus für die Webanwendung stellt den Benutzernamen bereit. SignalR verwendet Verschlüsselung und eine digitale Signatur zum Schutz des Verbindungstokens.
Für jede Anforderung überprüft der Server den Inhalt des Tokens, um sicherzustellen, dass die Anforderung vom angegebenen Benutzer stammt. Der Benutzername muss der Verbindungs-ID entsprechen. Durch die Überprüfung der Verbindungs-ID und des Benutzernamens verhindert SignalR, dass ein böswilliger Benutzer die Identität eines anderen Benutzers leicht imitiert. Wenn der Server das Verbindungstoken nicht überprüfen kann, schlägt die Anforderung fehl.
Da die Verbindungs-ID Teil des Überprüfungsprozesses ist, sollten Sie die Verbindungs-ID eines Benutzers nicht mit anderen Benutzern anzeigen oder den Wert auf dem Client speichern, z. B. in einem Cookie.
Verbindungstoken im Vergleich zu anderen Tokentypen
Verbindungstoken werden gelegentlich von Sicherheitstools gekennzeichnet, da sie als Sitzungstoken oder Authentifizierungstoken erscheinen, was ein Risiko darstellt, wenn sie verfügbar gemacht werden.
Das Verbindungstoken von SignalR ist kein Authentifizierungstoken. Es wird verwendet, um zu bestätigen, dass der Benutzer, der diese Anforderung stellt, der gleiche ist, der die Verbindung erstellt hat. Das Verbindungstoken ist erforderlich, da ASP.NET SignalR Verbindungen zwischen Servern ermöglicht. Das Token ordnet die Verbindung einem bestimmten Benutzer zu, bestätigt jedoch nicht die Identität des Benutzers, der die Anforderung stellt. Damit eine SignalR-Anforderung ordnungsgemäß authentifiziert werden kann, muss es ein anderes Token aufweisen, das die Identität des Benutzers bestätigt, z. B. ein Cookie oder bearertoken. Das Verbindungstoken selbst macht jedoch keinen Anspruch, dass die Anforderung von diesem Benutzer vorgenommen wurde, nur dass die im Token enthaltene Verbindungs-ID diesem Benutzer zugeordnet ist.
Da das Verbindungstoken keinen eigenen Authentifizierungsanspruch bereitstellt, wird es nicht als "Sitzungs-" oder "Authentifizierungstoken" betrachtet. Wenn Sie das Verbindungs-Token eines bestimmten Benutzers nehmen und es in einer Anfrage wiedergeben, die als ein anderer Benutzer authentifiziert ist (oder in einer nicht authentifizierten Anfrage), schlägt dies fehl, da die Benutzeridentität der Anfrage und die im Token gespeicherte Identität nicht übereinstimmen.
Gruppen bei erneuter Verbindung wieder beitreten
Standardmäßig weist die SignalR-Anwendung Benutzer automatisch den entsprechenden Gruppen zu, wenn die Verbindung nach einer kurzen Unterbrechung wiederhergestellt wird, z. B. wenn eine Verbindung abgebrochen und neu aufgebaut wird, bevor die Verbindung abläuft. Beim erneuten Verbinden übergibt der Client ein Gruppentoken, das die Verbindungs-ID und die zugewiesenen Gruppen enthält. Das Gruppentoken wird digital signiert und verschlüsselt. Der Client behält die gleiche Verbindungs-ID nach einer erneuten Verbindung bei; Daher muss die vom erneut verbundenen Client übergebene Verbindungs-ID mit der vorherigen Verbindungs-ID übereinstimmen, die vom Client verwendet wird. Diese Überprüfung verhindert, dass ein bösartiger Benutzer Anfragen zum Beitritt zu nicht autorisierten Gruppen stellt, beim erneuten Verbinden.
Es ist jedoch wichtig zu beachten, dass das Gruppentoken nicht abläuft. Wenn ein Benutzer in der Vergangenheit zu einer Gruppe gehörte, aber von dieser Gruppe gesperrt wurde, kann dieser Benutzer möglicherweise ein Gruppentoken nachahmen, das die verbotene Gruppe enthält. Wenn Sie sicher verwalten müssen, welche Benutzer zu welchen Gruppen gehören, müssen Sie diese Daten auf dem Server speichern, z. B. in einer Datenbank. Fügen Sie dann Ihrer Anwendung Logik hinzu, die auf dem Server überprüft, ob ein Benutzer zu einer Gruppe gehört. Ein Beispiel für die Überprüfung der Gruppenmitgliedschaft finden Sie unter "Arbeiten mit Gruppen".
Das automatische erneute Beitreten zu Gruppen gilt nur, wenn eine Verbindung nach einer temporären Unterbrechung wiederhergestellt wird. Wenn ein Benutzer die Verbindung trennt, indem er von der Anwendung weg navigiert oder die Anwendung neu startet, muss Ihre Anwendung sicherstellen, dass dieser Benutzer den richtigen Gruppen hinzugefügt wird. Weitere Informationen finden Sie unter Arbeiten mit Gruppen.
Wie SignalR die standortübergreifende Anforderungsverfälschung verhindert
Cross-Site Request Forgery (CSRF) ist ein Angriff, bei dem eine bösartige Website eine Anforderung an eine anfällige Website sendet, auf der der Benutzer derzeit angemeldet ist. SignalR verhindert CSRF, indem es extrem unwahrscheinlich ist, dass eine schädliche Website eine gültige Anforderung für Ihre SignalR-Anwendung erstellt.
Beschreibung des CSRF-Angriffs
Hier ist ein Beispiel für einen CSRF-Angriff:
Ein Benutzer meldet sich bei
www.example.com
an und verwendet die Formularauthentifizierung.Der Server authentifiziert den Benutzer. Die Antwort vom Server enthält ein Authentifizierungscookie.
Ohne Abmelden besucht der Benutzer eine bösartige Website. Diese bösartige Website enthält das folgende HTML-Formular:
<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>
Beachten Sie, dass die Formularaktion auf der anfälligen Website und nicht auf der bösartigen Website veröffentlicht wird. Dies ist der websiteübergreifende Teil von CSRF.
Der Benutzer klickt auf die Schaltfläche "Absenden". Der Browser sendet das Authentifizierungs-Cookie mit der Anfrage.
Die Anforderung wird auf dem example.com-Server mit dem Authentifizierungskontext des Benutzers ausgeführt und kann alles tun, was ein authentifizierter Benutzer tun darf.
Obwohl in diesem Beispiel der Benutzer auf die Formularschaltfläche klickt, kann die schädliche Seite genauso einfach ein Skript ausführen, das eine AJAX-Anforderung an Ihre SignalR-Anwendung sendet. Darüber hinaus verhindert die Verwendung von SSL keinen CSRF-Angriff, da die bösartige Website eine "https://"-Anforderung senden kann.
In der Regel sind CSRF-Angriffe gegen Websites möglich, die Cookies für die Authentifizierung verwenden, da Browser alle relevanten Cookies an die Zielwebsite senden. CSRF-Angriffe sind jedoch nicht auf das Ausnutzen von Cookies beschränkt. Beispielsweise sind auch die Basic- und Digest-Authentifizierung anfällig. Nachdem sich ein Benutzer mit der Standard- oder Digestauthentifizierung angemeldet hat, sendet der Browser die Anmeldeinformationen automatisch, bis die Sitzung endet.
CSRF-Behebungen von SignalR
SignalR führt die folgenden Schritte aus, um zu verhindern, dass eine schädliche Website gültige Anforderungen an Ihre Anwendung erstellt. SignalR führt diese Schritte standardmäßig aus, Sie müssen keine Maßnahmen in Ihrem Code ausführen.
- Domänenübergreifende Anforderungen deaktivieren SignalR deaktiviert domänenübergreifende Anforderungen, um zu verhindern, dass Benutzer einen SignalR-Endpunkt von einer externen Domäne aufrufen. SignalR betrachtet jede Anforderung aus einer externen Domäne als ungültig und blockiert die Anforderung. Wir empfehlen, dieses Standardverhalten beizubehalten; andernfalls könnte eine böswillige Website Benutzer dazu verleiten, Befehle an Ihre Website zu senden. Wenn Sie domänenübergreifende Anforderungen verwenden müssen, erfahren Sie, wie Sie eine domänenübergreifende Verbindung herstellen .
- Verbindungstoken in Abfragezeichenfolge übergeben, kein Cookie SignalR übergibt das Verbindungstoken als Abfragezeichenfolgenwert anstelle eines Cookies. Das Speichern des Verbindungstokens in einem Cookie ist unsicher, da der Browser das Verbindungstoken versehentlich weiterleiten kann, wenn bösartiger Code auftritt. Außerdem verhindert das Übergeben des Verbindungstokens in der Abfragezeichenfolge, dass das Verbindungstoken über die aktuelle Verbindung hinaus beibehalten wird. Daher kann ein böswilliger Benutzer keine Anforderung unter den Authentifizierungsanmeldeinformationen eines anderen Benutzers stellen.
- Überprüfen des Verbindungstokens Wie im Abschnitt "Verbindungstoken " beschrieben, weiß der Server, welche Verbindungs-ID jedem authentifizierten Benutzer zugeordnet ist. Der Server verarbeitet keine Anforderung von einer Verbindungs-ID, die nicht mit dem Benutzernamen übereinstimmt. Es ist unwahrscheinlich, dass ein böswilliger Benutzer eine gültige Anforderung erraten könnte, da der böswillige Benutzer den Benutzernamen und die aktuelle zufällig generierte Verbindungs-ID kennen müsste. Diese Verbindungs-ID wird ungültig, sobald die Verbindung beendet wurde. Anonyme Benutzer sollten keinen Zugriff auf vertrauliche Informationen haben.
Empfehlungen zur SignalR-Sicherheit
Ssl-Protokoll (Secure Socket Layers)
Das SSL-Protokoll verwendet Verschlüsselung, um den Transport von Daten zwischen einem Client und einem Server zu sichern. Wenn Ihre SignalR-Anwendung vertrauliche Informationen zwischen dem Client und dem Server überträgt, verwenden Sie SSL für den Transport. Weitere Informationen zum Einrichten von SSL finden Sie unter Einrichten von SSL unter IIS 7.
Verwenden Sie Gruppen nicht als Sicherheitsmechanismus.
Gruppen sind eine bequeme Möglichkeit zum Sammeln verwandter Benutzer, aber sie sind kein sicherer Mechanismus zum Einschränken des Zugriffs auf vertrauliche Informationen. Dies gilt insbesondere, wenn Benutzer während einer erneuten Verbindung automatisch Gruppen erneut beitreten können. Erwägen Sie stattdessen, einer Rolle privilegierte Benutzer hinzuzufügen und den Zugriff auf eine Hubmethode nur auf Mitglieder dieser Rolle zu beschränken. Ein Beispiel zum Einschränken des Zugriffs basierend auf einer Rolle finden Sie unter Authentifizierung und Autorisierung für SignalR-Hubs. Ein Beispiel für die Überprüfung des Benutzerzugriffs auf Gruppen beim erneuten Verbinden finden Sie unter "Arbeiten mit Gruppen".
Sichere Verarbeitung von Eingaben von Clients
Um sicherzustellen, dass ein böswilliger Benutzer kein Skript an andere Benutzer sendet, müssen Sie alle Eingaben von Clients codieren, die für die Übertragung an andere Clients vorgesehen sind. Sie sollten Nachrichten auf den empfangenden Clients statt auf dem Server codieren, da Ihre SignalR-Anwendung möglicherweise viele verschiedene Arten von Clients aufweist. Daher funktioniert die HTML-Codierung für einen Webclient, aber nicht für andere Clienttypen. Beispielsweise würde eine Webclientmethode zum Anzeigen einer Chatnachricht den Benutzernamen und die Nachricht sicher verarbeiten, indem die html()
Funktion aufgerufen wird.
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>');
};
Abgleich einer Änderung des Benutzerstatus mit einer aktiven Verbindung
Wenn sich der Authentifizierungsstatus eines Benutzers ändert, während eine aktive Verbindung besteht, erhält der Benutzer eine Fehlermeldung, die besagt: "Die Benutzeridentität kann während einer aktiven SignalR-Verbindung nicht geändert werden." In diesem Fall sollte Ihre Anwendung eine erneute Verbindung mit dem Server herstellen, um sicherzustellen, dass die Verbindungs-ID und der Benutzername koordiniert sind. Wenn ihre Anwendung beispielsweise zulässt, dass sich der Benutzer abmeldet, während eine aktive Verbindung vorhanden ist, stimmt der Benutzername für die Verbindung nicht mehr mit dem Namen überein, der für die nächste Anforderung übergeben wird. Sie möchten die Verbindung beenden, bevor sich der Benutzer abmeldet, und dann erneut starten.
Beachten Sie jedoch, dass die meisten Anwendungen die Verbindung nicht manuell beenden und starten müssen. Wenn Ihre Anwendung Benutzer nach der Abmeldung zu einer separaten Seite umleitet, z. B. das Standardverhalten in einer Webanwendung oder MVC-Anwendung, oder aktualisiert die aktuelle Seite nach der Abmeldung, wird die aktive Verbindung automatisch getrennt und erfordert keine zusätzliche Aktion.
Das folgende Beispiel zeigt, wie Eine Verbindung beendet und gestartet wird, wenn sich der Benutzerstatus geändert hat.
<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>
Oder der Authentifizierungsstatus des Benutzers kann sich ändern, wenn Ihre Website eine gleitende Ablaufzeit mit der Formularauthentifizierung verwendet und es keine Aktivität gibt, um das Authentifizierungs-Cookie gültig zu halten. In diesem Fall wird der Benutzer abgemeldet, und der Benutzername stimmt nicht mehr mit dem Benutzernamen im Verbindungstoken überein. Sie können dieses Problem beheben, indem Sie ein Skript hinzufügen, das regelmäßig eine Ressource auf dem Webserver anfordert, um das Authentifizierungscookies gültig zu halten. Das folgende Beispiel zeigt, wie Eine Ressource alle 30 Minuten angefordert wird.
$(function () {
setInterval(function() {
$.ajax({
url: "Ping.aspx",
cache: false
});
}, 1800000);
});
Automatisch generierte JavaScript-Proxydateien
Wenn Sie nicht alle Hubs und Methoden in die JavaScript-Proxydatei für jeden Benutzer einschließen möchten, können Sie die automatische Generierung der Datei deaktivieren. Sie können diese Option auswählen, wenn Sie über mehrere Hubs und Methoden verfügen, aber nicht möchten, dass jeder Benutzer alle Methoden kennen kann. Sie deaktivieren die automatische Generierung, indem Sie "EnableJavaScriptProxies" auf "false" festlegen.
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableJavaScriptProxies = false;
app.MapSignalR(hubConfiguration);
Weitere Informationen zu den JavaScript-Proxydateien finden Sie unter Dem generierten Proxy und ihrer Funktionsweise.
Ausnahmen
Sie sollten das Übergeben von Ausnahmeobjekten an Clients vermeiden, da die Objekte möglicherweise vertrauliche Informationen für die Clients verfügbar machen. Rufen Sie stattdessen eine Methode auf dem Client auf, die die relevante Fehlermeldung anzeigt.
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.");
}
}