bk99.de entertain the web since 1997

AcceptEx und die Tücken des Windows-Socket-API

Zusammenfassung

Felix von Leitner stieß 2008 beim Debuggen auf ein Problem mit der Linux-Socketoption TCP_DEFER_ACCEPT, das an eine früher beschriebene Schwäche von AcceptEx unter Windows erinnerte. Beide Mechanismen melden eine neue Verbindung erst, wenn der Client auch Daten geschickt hat. Unter Linux zählen solche schweigenden Verbindungen aber gegen die Warteschlange von listen(), und wenn diese voll ist, nimmt der Server keine neuen Verbindungen mehr an.

Worum es technisch geht

Ein Server ruft listen() mit einer maximalen Länge der Warteschlange auf, dem Backlog, und holt neue Verbindungen mit accept() ab. TCP_DEFER_ACCEPT ist eine Optimierung: Der Kernel weckt den Server erst, wenn tatsächlich Daten da sind, was bei Webservern Arbeit spart. Unter Windows erfüllt AcceptEx mit überlappendem I/O einen ähnlichen Zweck, und dort genügte ein einziger schweigender Client, um den Server zu blockieren.

Von Leitner sah in netstat 16 halbe Verbindungen, genau so viele wie das Backlog von 16. Die schweigenden Verbindungen belegten die Warteschlange, ohne dass der Server sie annehmen konnte. Das Muster ähnelt einem SYN-Flood: Ein Angreifer muss nur genug Verbindungen öffnen und nichts senden.

Was man daraus lernt

Optimierungen im Kernel ändern das Verhalten unter Angriffsbedingungen. Was im Normalbetrieb Rechenzeit spart, kann einen einfachen Denial-of-Service ermöglichen. Wer solche Optionen einsetzt, sollte großzügige Backlogs und Zeitlimits wählen und das Verhalten mit schweigenden Clients testen.

Ideen

  • TCP_DEFER_ACCEPT weckt den Server erst, wenn ein Client Daten gesendet hat.
  • Schweigende Verbindungen können die listen-Warteschlange füllen.
  • Ähnliche Optimierungen unter Windows und Linux zeigen ähnliche Schwächen.

Einsichten

  • Performance-Optimierungen müssen auch unter Angriffsbedingungen geprüft werden.
  • Ein kleines Backlog macht einen Server anfällig für einfache Denial-of-Service-Angriffe.

Fakten

  • Das Backlog im Test betrug 16 Verbindungen.
  • TCP_DEFER_ACCEPT ist eine Linux-spezifische Socketoption.
  • Von Leitner nutzt die Option über libowfat im Webserver gatling.

Referenzen

Bemerkungen

  • Der Beitrag schildert eine Beobachtung beim Debuggen, keine vollständige Analyse des Kernelverhaltens.

Empfehlungen

  • Setze das Backlog von listen() für öffentlich erreichbare Server großzügig.
  • Teste Server auch mit Clients, die Verbindungen öffnen und nichts senden.

Originalbeitrag lesen →

Im Webarchiv suchen