Windows XP SP2 und Server 2003 enthalten einen Kernel-Treiber für HTTP Verkehr mit Namen HTTP.SYS. Anwendungen, die an HTTP Daten interessiert sind, registrieren einen URI Namensraum (z.b. „/foo“) an diesem Treiber, und wenn HTTP Requests für diesen Namensraum am System ankommen, werden diese automatisch an die interessierte Anwendung weitergeleitet. Dieser API wird z.B. von IIS6, SQL Server 2005 oder auch dem WCF ServiceHost für die gesamte HTTP Kommunikation benutzt.
In .NET 2.0 kann man gegen HTTP.SYS mit Hilfe der HttpListener Klasse im System.Net Namensraum programmieren. Dies hat folgende Vorteile gegenüber einer direkten Socket-Kommunikation:
- Low-Level TCP/IP Details werden abstrahiert und man erhält direkten Zugriff auf das HTTP Protokoll
- Automatisches Port-Sharing, d.h. mehrer Anwendungen können über den gleichen Port kommunizieren, solange sie verschiedene URIs registriert haben
- HTTP.SYS liefert Basic, Digest und integrierte Authentifizierung (Kerberos und NTLM) sowie Unterstützung für SSL frei Haus. Dafür ist kein Code notwendig
So lassen sich mit diesen wenigen Zeilen Code ein sehr einfacher Web Server realisieren:
class Program
{
static void Main(string[] args)
{
HttpListener listener = new HttpListener();
// URI registrieren
listener.Prefixes.Add(“http://localhost/HttpListener/”);
listener.Start();
// requests entgegenehmen
while (true)
{
HttpListenerContext ctx = listener.GetContext();
ProcessContext(ctx);
}
}
// requests verarbeiten
private static void ProcessContext(HttpListenerContext ctx)
{
string response = “<h1>Hello from HttpListener</h2>”;
byte[] responseBytes = Encoding.UTF8.GetBytes(response);
ctx.Response.OutputStream.Write(
responseBytes, 0, responseBytes.Length);
ctx.Response.Close();
}
}
Nur wenige Zeilen Code mehr sind notwendig, um zum Beispiel ASP.NET Unterstützung zu integrieren (das gilt auch für .asmx).
Dies ist ein sehr attraktives Programmier-Modell. Es gibt allerdings eine Sache hier zu beachten – das Registrieren von URIs ist eine äußerst privilegierte Operation. Ansonsten wäre es für Viren oder andere Malware sehr einfach sich hinter bereits geöffneten Ports zu “verstecken”.
Mit anderen Worten, Sie benötigen Administrator-Rechte, und wenn während der Entwicklung kein normaler Benutzer-Account zum Testen verwendet wurde, kann es sein, das diese Restriktion erst beim Deployment auffällt. Dies führt im einfachsten Fall zu Problemen und im schlimmsten Fall dazu, dass Ihre Anwendung/Dienst mit administrativen Rechten in der Produktion läuft. Und das dies nicht erwünscht ist, wissen wir ja alle.
Es gibt einen Ausweg aus dieser Situation. Sie können URI Namensräume mit administrativen Rechten „vor-reservieren“ und einen ACL setzen, der es der eigentlichen Anwendung erlaubt, den Namensraum ohne spezielle Privilegien zu registrieren. Für diesen Zweck gibt es das “etwas umständliche” Tool httpcfg.exe, das ein weiteres Mal unsere SDDL Kenntnisse auf die Probe stellt. So würde ein typischer Aufruf um einen ACL für einen Account zu vergeben etwa so aussehen:
httpcfg set urlacl /u http://*:80/HttpListener/ /a D:(A;;GX;;;S-1-5-21-1144070942-1563683482-3278297161-1114)
Schön? Nicht wirklich. Aus diesem Grund habe ich ein kleines Tool geschrieben, dass einen interaktiv durch den ACL-Vergabe Vorgang führt, und es erlaubt sowohl Benutzer/Gruppen Konten sowie well-known SIDs zu konfigurieren.
Wenn Sie HTTP.SYS verwenden möchten, machen Sie sich mit den Tools vertraut. Es gibt keine Entschuldigung für Dienste, die mit zu hohen Rechten laufen.