Leseprobe
Inhaltsverzeichnis
Abbildungsverzeichnis
Tabellenverzeichnis
1 Einführung
1.1 Sicherheitsupdates
2 Allgemeines
2.1 Injektion
2.1.1 Request Validation Mode
2.1.2 AntiXss
2.1.3 Validator Controls
3 Authentifizierung
3.1 SSL
3.2 Web.config
3.3 ViewState
3.4 Cookies & Session
3.4.1 Cookieless
3.5 Bilder & CAPTCHA
3.6 Upload
3.7 Fehlerbehandlung
3.8 Logging
4 Code Access Security
5 Statische Variablen
6 Web API in Forms Websites
7 CSRF bei Web Api, Update Panel, Ajax und co
8 Security Tools
8.1 Websiteverwaltungs-Tool
8.2 UrlScan
8.3 Lens
9 Pragmatische ASP.MVC Sicherheit
9.1 Einleitung
9.2 Injektionen
9.3 Authentifizierung
9.3.1 OpenID & Oauth
9.3.2 Claims
9.4 XSRF/CSRF Prevention in ASP.NET MVC
9.5 SSL
9.6 Json
9.7 SignalR
9.7.1 Authentifizierung
9.7.2 Validation
9.8 Web API
9.8.1 Web API Pipeline
9.8.2 Authentifizierung in Web API
9.8.3 Firewalls umgehen
9.8.4 Caching Probleme
10 Literaturverzeichnis
Abbildungsverzeichnis
Figure 1: DotNet Konfiguration im IIS
Figure 2: web.config
Figure 3: ValidateRequest
Figure 4: Beispiel AntiXss im Textbox Control
Figure 5: Postback des Login Controls
Figure 6: Testzertifikat im IIS
Figure 7: Öffentliche web.config
Figure 8: Verschlüsselter ConnectionString
Figure 9: OWASP ZAP Warnungen
Figure 10: cookieless SessionIDs bei Google
Figure 11: ASP.NET Fehlermeldung
Figure 12: IIS statusCodes
Figure 13: Fehlermeldung beim DDOS Angriff
Figure 14: Beispiel Logeintrag in der Ereignisanzeige
Figure 15: ISS Log Analyse
Figure 16: Vererbungshierarchie
Figure 17: Log
Figure 18: Beispiel Bild
Figure 19: CSRF Angriff
Figure 20: Rollenverwaltung von Visual Studio
Figure 21: Rollenverwaltung von Visual Studio 2
Figure 22: Lens
Figure 23: PEX
Figure 24: Inhalt des Dokuments . Blau(Pragmatische ASP.NET Forms Sicherheit), Gelb(Pragmatische ASP.MVC Sicherheit)
Figure 25: Windows Authentifizierung
Figure 26: Manipulation eines HTTP POST Paketes
Figure 27:Angreifer nutzt XSS Schwachstelle um einen Benutzer mit SignalR über HTTP zu überwachen
Figure 28: Filter Konzept
Alle Bilder und Screenshots die nicht explizit mit Quellenangaben versehen sind wurden im Rahmen dieser Arbeit vom Autor erstellt.
Tabellenverzeichnis
Table 1: sicherheitskritische Attribute
Table 2: Code Security
Table 3: Authorize
1 Einführung
Dieses Dokument bietet eine praktische Einführung in das sichere Erstellen von Websites mit ASP.NET. Die im Folgenden vorgestellten Einstellungen und Snippets wurden mit der Version 4.0 vom DotNet Framework getestet.
1.1 Sicherheitsupdates
Zuerst ist es wichtig je eine aktuelle Version vom IIS und DotNet Frameworks mit Sicherheitsupdates zu installieren. Sie verhindern zum Beispiel Angriffe auf die vom DotNet Framework verwendete Verschlüsselung.
Ein solcher Angriff ist zum Beispiel der 2010 gefundene „Padding oracle“ Angriff[1]. Dieser ist in der Lage, Dateien vom Server herunterzuladen. Betroffen sind DotNet Versionen bis 4.0 auf Betriebssystemen bis Windows 7[2].
Beim DotNet Framework reicht nicht allein das Installieren der neusten Version. Es muss geprüft werden, ob der verwendete Anwendungspool auch die aktuelle DotNet Version verwendet.
Abbildung in dieser Leseprobe nicht enthalten
Figure 1: DotNet Konfiguration im IIS
2 Allgemeines
Neuere Versionen von Asp.Net unterstützen „precompilation“. Dabei wird die Website erstellt, bevor ein User diese aufruft. Dies war früher anders, was zu längeren Wartezeiten beim ersten Aufruf geführt hat. Ändert sich der Quellcode einer Page, so muss die gesamte Applikation neu erstellt werden, beim „precompilation“ nur die geänderte Page. Dies hat Auswirkungen auf viele Sicherheitseinstellungen, da diese oft tief in der Applikation verankert sind. Deswegen kann es passieren, dass einige Einstellungen nicht in der Produktivumgebung greifen, da nur eine Page geändert wurde. Es ist empfehlenswert, nach dem Ändern von sicherheitskritischen Einstellungen die gesamte Applikation neu zu compilieren.
Ist eine Website fertig für den produktiven Einsatz, sollten die Ordner nicht manuell kopiert werden, sondern über die Veröffentlichungsfunktion von Visual Studio deployed werden. Dies verhindert, dass unnötige Dateien auf den Server geladen werden. Das Deployen der Website sollte im Release Modus geschehen, da der Compiler dadurch Optimierungen in Bereichen wie Geschwindigkeit und Sicherheit vornehmen kann. Der Entwickler kann auch selbst für weitere Optimierungen sorgen, indem unnötige oder unfertige Funktionen nicht in das Release der Website gelangen.
Abbildung in dieser Leseprobe nicht enthalten
unnötigen Code verstecken
Zusätzlich unterstützt auch die web.config die Trennung zwischen Debug und Release. Dieses Feature sollte auch genutzt werden.
Abbildung in dieser Leseprobe nicht enthalten
Figure 2: web.config
2.1 Injektion
Eine der größten Gefahren für Websites sind Codeinjektions. Bei einem solchen Vorgang sind alle Schichten betroffen, die Code zur Laufzeit interpretieren, zum Beispiel: JavaScript, SQL, HTML... . Aufgrund der breiten Angriffsfläche und der enormen Verbreitung stuft die OWASP Injektionen als die größte Bedrohung für Websites ein. Ist ein Injektionsangriff erfolgreich, können die Auswirkungen von leicht bis schwer variieren. Deswegen ist es wichtig diese Art von Angriffen beim Design der Anwendung zu berücksichtigen. In ASP.NET wurde dies sogar schon noch früher gemacht, nämlich beim Design des DotNet Frameworks.
2.1.1 Request Validation Mode
Ruft ein User eine Website im Browser auf, kann er als Ziel eine ASP.NET Page wählen. Standardmäßig ist für alle Eingaben, die im Kontext dieser Page laufen, eine automatische „requestValidation“ eingeschaltet. Diese filtert zum Beispiel gefährliche Zeichen wie den Anfang eines HTML Tags „
Abbildung in dieser Leseprobe nicht enthalten
Figure 3: ValidateRequest
Dieser Grundschutz sollte möglichst aktiviert bleiben. In seltenen Fällen kann es sein, dass man diesen ausschalten muss, um zum Beispiel das Posten von HTML-Code zu erlauben. In diesem Fall sollte das Deaktivieren lokal in der Page-Direktive passieren und nicht global in der web.config.
Abbildung in dieser Leseprobe nicht enthalten
Deaktivieren von Page Validation
Wenn möglich sollte die Validierung aber aktiv sein und nur sehr gezielt ausgeschaltet werden. Dies ist möglich mit Hilfe des „ValidateInput“-Tags.
[AllowHtml]
[HttpPost]
[ValidateInput(false)]
Deaktivieren der Validierung für eine bestimmte Methode[3].
Grundsätzlich sollte die Fehlermeldung, die das „requestValidation“ auswirft, vor dem Anwender versteckt werden. Dies kann über das allgemeine Fehlerhandling in der web.config passieren, oder aber explizit im Code-Behind.
public override void ProcessRequest(HttpContext context)
{
try
{
base.ProcessRequest(context);
}
catch (HttpRequestValidationException ex)
{
context.Response.Redirect("HandleValidationError.aspx");
}
}
Abfangen von Sicherheitsfehlern
Durch das Erstellen eines zusätzlichen Sicherheitslayers zwischen der Pageklasse des Frameworks und der „*.aspx“ Webpage kann anwendungsweit ein einheitliches Verhalten implementiert werden.
Controls, deren ID mit „__“ beginnen, wie zum Beispiel der ViewState, werden nicht validiert.
Trotz des guten Schutzes durch die „requestValidation“ hat ein Angreifer die Möglichkeit einen erfolgreichen XSS Angriff durchzuführen. Dies ist dann der Fall, wenn er seine Eingabe ebenfalls kodiert. So würde der Filter bei diesem URL Parameter: „&two= “ erkennen, dass Code eingeschleust wird. Auch wenn dieser Parameter kodiert wird „&two=%3Cb%3E“, erkennt der Filter den Angriff. Kodiert der Angreifer den Parameter doppelt „&two=%253Cb%253E“, so wird der Angriff nicht mehr erkannt. Im Code-Behind wird aus der kodierten Zeichenkette wieder der ursprüngliche Schadcode „ “.
Server.UrlDecode(Request["two"])
Double Encoding Angriffe
Der Fehler liegt darin, dass die obige Codezeile ein double Decode macht. Das „Request“ Objekt decodiert die URL Parameter automatisch. Die Methode „UrlDecode“ wiederholt den Vorgang erneut und ermöglicht damit den XSS Angriff.
2.1.2 AntiXss
Da Page Validation in einigen Fällen zu aggressiv ist und deswegen ausgeschaltet wird, greift noch ein weiteres Features um speziell Cross-Site-Scripting zu verhindern. Microsoft hat die meisten seiner Standard ASP.NET Controls mit HTML-Encoding ausgestattet. Das heißt, alle nicht alphanumerischen Zeichen werden als Sonderzeichen behandelt und durch einen speziellen Ausdruck ersetzt. So wird zum Beispiel ein „ä“ durch „ä“ repräsentiert. Eine List aller Platzhalter ist im HTML Standard definiert[4]. Dieses Feature lässt sich nicht ausschalten und sorgt dafür, dass der Client keine Eingaben semantisch interpretiert.
Abbildung in dieser Leseprobe nicht enthalten
Figure 4: Beispiel AntiXss im Textbox Control
Problematisch ist, dass nicht alle Controls und alle Properties diese Eigenschaft enthalten. So kann zum Beispiel das Literal Control dazu genutzt werden um dynamisch HTML Code in eine Page einzubetten. Dies wird möglich, weil das Literal Control kein Encoding vornimmt.
this.txtOnline.Text = "Online: ";
this.txtOnline.Text += string.Join(", ", (
from MembershipUser x in
Membership.GetAllUsers()
where x.IsOnline
select new StringBuilder("")
.Append(Server.HtmlEncode(x.UserName))
.Append("").ToString())
);
Erstellung einer Leiste mit den aktiven Users und Links mittels des Literal Controls
Deswegen kann der Entwickler sich nicht blind auf die Sicherheit der Controls verlassen, sondern muss prüfen, ob das Encoding funktioniert. Eine Liste mit allen Properties, die das Encoding unterstützen, findet sich hier[5]. Ebenfalls muss dem Entwickler bewusst sein, dass die Daten ohne Kodierung im Code-Behind übergeben werden. So kann folgende Zeile schnell sicherheitskritisch werden:
falsch:
public void btnSend_Click(object sender, EventArgs e)
{
Context.Response.Redirect(
new StringBuilder("default.aspx?ID=")
.Append(this.TxtKomm.Text).ToString()
);
}
richtig:
public void btnSend_Click(object sender, EventArgs e)
{
Context.Response.Redirect(
new StringBuilder("default.aspx?ID=")
.Append(Server.HtmlEncode(this.TxtKomm.Text)).ToString()
);
}
Wie das obige Beispiel zeigt, bietet das DotNet Framework Methoden zum manuellen Kodieren von Zeichenketten. Diese befinden sich in der Klasse „Server“. Die von Server gestellten Methoden zum Kodieren sind die gleichen, welche durch die „requestValidation“ von Controls aufgerufen werden. Besonders beim DataBinding ist Vorsicht geboten. Denn auch dort müssen die Eingaben codiert werden, wenn das Control diese nicht selbst macht. Im folgenden Beispiel werden vier Informationen automatisch gebunden. Eine dieser Informationen kann erfolgreich für einen XSS Angriff genutzt werden.
Abbildung in dieser Leseprobe nicht enthalten
XSS beim Databinding
1 Da die Textbox ihre Daten kodiert, besteht hier keine Gefahr.
2 Da Custom Controls, wie in diesem Fall, immer ihre Properties kodieren sollten, besteht hier auch keine Gefahr.
3 Da das Label die Daten im Klartext verschickt, besteht hier die Möglichkeit einen XSS Angriff zu versuchen.
4 Hier besteht keine Gefahr, da der Benutzer keinen Einfluss auf den Wert hat.
Will man die Sicherheit noch weiter erhöhen, kann man den Microsoft AntiXSS-Encoder verwenden. Herunterladen lässt dieser sich auf der Microsoft Website[6]. Nach dem Installieren muss der Namespace und die DLL noch in das Projekt hinzugefügt werden. Danach können die Encoder der AntiXss Library verwendet werden. Damit auch die Controls den Encoder verwenden, muss die web.config wie folgt angepasst werden:
"Microsoft.Security.Application.AntiXssEncoder, AntiXssLibrary"/>
Microsoft AntiXss Encoder
In Projekten mit älteren Versionen des DotNet Frameworks(unter 4.0) sollte immer die AntiXSS Library verwendet werden, da die Server Klasse nicht alle kritischen Zeichen behandelt[7].
In seltenen Fällen kann es vorkommen, dass das Verhalten des automatischen Encodings angepasst werden muss, da es zu aggressiv ist. Das kann erreicht werden, indem man eine neue Methode für das Encoding in der web.config festlegt.
public class HtmlAttributeEncodingNot : System.Web.Util.HttpEncoder
{
protected override void HtmlAttributeEncode(string value,
System.IO.TextWriter output)
{
output.Write(value);
}
}
Custom HttpEncoder
2.1.3 Validator Controls
Eine sehr gute Möglichkeit Injektionangriffe auszuschließen, ist das Verwenden von Validator Controls. Diese prüfen jeweils ein Eingabefeld auf Korrektheit der Werte. Die Prüfung findet dabei auf dem Clienten und auf dem Server statt. Dies hat den Vorteil, dass unter Verwendung von JavaScript falsche Eingaben nicht zum Server geschickt werden. Controls, die eine solche Prüfung durchführen, gibt es einige, eines davon ist der „RegularExpressionValidator“.
id="RegularExpressionValidator1"
runat="server"
ErrorMessage="RegularExpressionValidator"
ValidationExpression="^[a-zA-Z'.\s]{1,40}$"
ControlToValidate="TxtKomm" />
Beispiel eines Validator Controls
Beachtet werden muss, dass die serverseitige Validierung im Pageload stattfindet und unter Umständen nicht aufgerufen wird, wenn nur ein Postback erfolgt. Deswegen ist es sinnvoll bei Events die serverseitige Validierung manuell anzustoßen und zu prüfen.
public void btnSend_Click(object sender, EventArgs e)
{
Page.Validate();
if (Page.IsValid)
DataSource.Add(
new NestedClass(this.TxtKomm.Text,
Context.User.Identity.Name,
(Role)this.ddlRole.SelectedIndex)
);
}
serverseitige Page-Validierung
3 Authentifizierung
Im Normalfall, muss ein Websitebesucher nicht authentifiziert sein. Dies ändert sich, wenn die Website zum Beispiel im Intranet läuft oder schützenswerte Bereiche enthält. Für diese Fälle enthält ASP.NET einige Features, die eine Authentifizierung erlauben. So kann man zum Beispiel einfach im IIS die anonyme Authentifizierung verbieten und in der web.config die Windows- Authentifizierung konfigurieren.
Abbildung in dieser Leseprobe nicht enthalten
Windows Authentifizierung
Danach kann im Code-Behind die Windows Identity abgefragt werden (siehe „serverseitige Page-Validierung“). Beachtet werden muss, dass bei automatischer Authentifizierung die Digest Authentifizierung im IIS eingestellt wird. Im Unterschied zur Basic Authentifizierung wird dabei nicht das Passwort im Klartext übertragen.
Der wohl häufigste Fall ist es aber, dass die Website sowohl öffentliche als auch private Bereiche enthält. Für diesen Fall ist ein Login erforderlich, welches mit der Authentifizierungsmethode „Forms“ konfiguriert wird.
Abbildung in dieser Leseprobe nicht enthalten
Das obige Beispiel zeigt eine ASP.NET Forms Authentifizierung. Der Ordner „Login“ ist für alle Besucher freigegeben, alle anderen Pages können nur nach der Authentifizierung besucht werden. Problematisch an diesem Beispiel ist, dass der Loginname direkt in der web.config steht. Zwar kann das Passwort, wie im Beispiel gezeigt, durch einen Hashwert geschützt werden, ist allerdings immer noch gefährdet. Der im Beispiel verwendet Hash-Wert kann in weniger als einer Sekunde geknackt werden[8]. Besser ist es die aspnetdb zu verwenden. Dies ist ein vordefiniertes Datenbankschema, welches mit Hilfe des „Aspnet_regsql“[9] Tools auf eine beliebige Datenbank gespielt werden kann. Dieses Schema enthält Tabellen zur Benutzer-, Rechte- und Rollenverwaltung. Um dieses Feature im vollen Umfang nutzen zu können, muss ein Membership- und Role-Provider in der web.config konfiguriert werden.
Abbildung in dieser Leseprobe nicht enthalten
Einstellungen bei Verwendung von aspnetdb
Im obigen Beispiel sind alle sicherheitsrelevanten Einstellungen rot markiert. Wie man sieht, gibt es davon einige. Wichtig ist zu verstehen, dass die Provider das Sicherheitsgrundgerüst für moderne ASP.NET Anwendungen stellen. Im Folgenden sind wichtigsten Properties mit Beschreibung aufgelistet.
Table 1: sicherheitskritische Attribute
Abbildung in dieser Leseprobe nicht enthalten
Der Wert dieser Properties muss in jedem Sicherheitskonzept einer Website spezifiziert werden. Besetzt man die Werte nicht explizit mit eigenen Werten, greifen die Standardeinstellungen, was zu unerwartetem Verhalten führen kann. Nicht betrachtet wird der Benutzername. Somit ist es dem Entwickler selbst überlassen die Menge der Benutzernamen einzuschränken. Dies kann zum Beispiel durch ein Validation Control geschehen(siehe Validator Controls).
Um die Authentifizierung durchführen zu können, stellt ASP.NET das Login Control zur Verfügung. Dieses implementiert den Loginbereich der Website und bietet ein Event(LoginUser_Authenticate) zum Authentifizieren des Benutzers an.
Abbildung in dieser Leseprobe nicht enthalten
Benutzer Authentifizierung mit Membership und Login
Nachdem der Benutzer erkannt wurde, wird er direkt zu einer vordefinierten Page geschickt. Dieses Verhalten verhindert ungewollte Umleitungen. Eine andere Möglichkeit ist, den Benutzer zu der URL zu schicken, die vor dem Login angefordert wurde. Um das zu ermöglichen, merkt sich das Login Control in der URL, woher der Benutzer gekommen ist. Dies kann zu Sicherheitsproblemen innerhalb der Anwendung führen, besonders wenn die „EnableCrossAppRedirects“ Eigenschaft aktiviert ist. Aber auch Umleitungen auf beliebige Pages innerhalb des aktuellen Anwendungsverzeichnisse können zu Problemen führen, wie folgende URL verdeutlicht:
Abbildung in dieser Leseprobe nicht enthalten
Weiterleiten von Benutzer innerhalb der Website
Nach dem Konfigurieren der Authentifizierung sind alle Daten geschützt. Allerdings gelten für Daten wie zum Beispiel Bilder oder PDF die gleichen Regeln wie für ASPX Pages. Das heißt, ein eingeloggter Benutzer kann sich alle Dateien direkt im Browser anfordern. Um Bilder und andere statische Daten zu schützen und den direkten Zugriff zu verweigern, können sie in ein spezielles Verzeichnis gelegt werden. Auf die folgenden sechs Verzeichnisse hat der Browser keinen Zugriff:
- App_Code
- App_Data
- App_WebReferences
- App_Browsers
- App_GlobalResources
- App_LocalResources
3.1 SSL
Das Fundament des Sicherheitskonzeptes einer Website ist die Art der Verbindung zwischen Client und Server. Viele Einstellungen, die sicherheitsrelevant sind, können durch das Abhören oder Manipulieren der Verbindung zwischen Server und Client umgangen werden. So können zum Beispiel die Login Informationen abgefangen werden, wenn kein HTTPS verwendet wird.
Abbildung in dieser Leseprobe nicht enthalten
[...]
[1] http://www.skullsecurity.org/blog/2013/padding-oracle-attacks-in-depth
[2] http://technet.microsoft.com/en-ca/security/Bulletin/MS10-070
[3] http://msdn.microsoft.com/en-us/library/hh882339.aspx
[4] http://www.ascii.cl/htmlcodes.htm
[5] http://www.google.de/url?sa=t&rct=j&q=&esrc=s&frm=1&source=web&cd=1&cad=rja&ved=0CC8QFjAA&url=http%3A%2F%2Fblogs.msdn.com%2Fcfs-filesystemfile.ashx%2F__key%2Fcommunityserver-components-postattachments%2F00-08-91-89-96%2Fasp.net_5F00_control_5F00_encoding.htm&ei=X2hSUsHuC6an0AXrloH4Bw&usg=AFQjCNGWzt8K6itxpl9of3_8QKB-tY2vlw
[6] http://www.microsoft.com/en-us/download/details.aspx?id=28589
[7] http://caught-in-a-web.blogspot.de/2007/01/httputilityhtmlencode-and-server.html
[8] http://www.md5decrypter.co.uk/sha1-decrypt.aspx
[9] %windir%\Microsoft.NET\Framework\{version}\Aspnet_regsql.exe