its-dokumentationen/01-Kittelberger_Carl_HTTP.md

327 lines
16 KiB
Markdown
Raw Normal View History

2018-03-01 08:20:16 +00:00
---
author: Carl Kittelberger
title: "ITS: Hypertext Transfer Protocol"
date: 2018-01-25
papersize: a4
documentclass: report
classoption: oneside
#classoption: draft
mainfont: Arial
sansfont: Arial
fontsize: 12pt
toc: true
header-includes:
# For \textcolor
- \usepackage{xcolor}
# Long tables (used by pandoc latex template itself)
- \usepackage{longtable}
# Localization to German for all package injections
- \usepackage[ngerman]{babel}
# Fancy header!
- \usepackage{fancyhdr}
- \usepackage{graphicx}
- \pagestyle{fancy}
- \fancyhf{}
- \fancyhead[L]{\large{\textit{\textbf{ITS} \\ Hypertext Transfer Protocol}}}
- \fancyhead[R]{\raisebox{-0.1\height}{\includegraphics[height=32pt]{img/steinbeis.png}}}
- \fancyfoot[L]{\textcolor{gray}{Carl Kittelberger}}
- \fancyfoot[R]{\textcolor{gray}{\bfseries{Seite \thepage}}}
- \renewcommand{\headrulewidth}{0.4pt}
- \renewcommand{\footrulewidth}{0.4pt}
- \setlength\headheight{36pt}
- \fancypagestyle{plain}{}
# monospace
- \lstset{basicstyle=\footnotesize\ttfamily,breaklines=true}
- \lstset{framextopmargin=50pt}
---
\newpage
# Definition
HTTP (*HyperText Transfer Protocol*) ist ein Standard, der festlegt wie
Webseiten über das Internet übertragen werden. Es definiert ein Protokoll auf
der Sitzungsschicht des OSI-Schichtenmodells, welches auf Basis des
TCP/IP-Stacks läuft.
Das Protokoll an sich definiert die Übertragung der Anfrage und der Antwort
im Klartext. Dies soll die konsistente Implementierung deutlich vereinfachen.
Jedoch wird HTTP heutzutage oft in anderen Protokollen eingebettet wie zum
Beispiel TLS für den sicheren, verschlüsselten Zugriff auf eine Website oder auch
Tor für dezentralisierte, anonymisierte Zugriffe auf Websites.
# Geschichte
Entwickelt wurde HTTP als Teil des Webprojekts an der Forschungseinrichtung
CERN von Tim Berners-Lee, Roy Fielding und anderen Teilnehmern. Die erste
bekannte Version von HTTP war die Version 0.9.
## HTTP/0.9
Diese frühe Version von HTTP definiert ein Subset des kompletten Protokolls
als Prototyp und wurde bereits so entworfen, dass zukünftige Versionen von HTTP
rückwärtskompatibel mit dieser sind.
Hier wurden bereits fundamentale Eigenschaften des Protokolls, wie dessen Abhängigkeit
vom TCP/IP-Stack, der Port 80 für Datenaustausch sowie das Nutzen von ASCII-Klartext
festgelegt. Nach jeder Anfrage, die verarbeitet wurde, wurde die Verbindung direkt
wieder geschlossen.
## HTTP/1.0
Diese Version von HTTP ist die meistgenutzte Version für die einfachsten Anfragen
zu Webservern und ist die erste mit einer vollständigen Spezifikation. Sie
unterstützt unter anderem die Kodierung von Inhalten mit GZip/Compress.
## HTTP/1.1
Die Version 1.1 von HTTP wurde 1999 unter der [RFC 2616](https://tools.ietf.org/html/rfc2616)
publiziert. Neuerungen in dieser Version sind unter anderem das Wiederverwenden
einer bereits aufgebauten HTTP-Verbindung über mehrere HTTP-Anfragen hinweg
erlaubt (siehe `Keep-Alive` Header später). Außerdem erlaubt diese Version
auch das Herunterladen von Teilen einer Datei anstatt die gesamte Datei
herunterladen zu müssen, um zum Beispiel bereits angefangene Übertragungen
nahtlos fortzusetzen.
Es werden auch weitere HTTP-Methoden neben `GET` und `POST` eingeführt, die
für das direkte Speichern, Löschen und Verwalten von Dateien auf einem Server
geeignet sind. Diese Methoden werden vor allem bei WebDAV eingesetzt.
Später wurden über mehrere RFCs hinweg (7230-7235) einige Aspekte von HTTP/1.1
noch einmal klarer spezifiziert um Unklarheiten zur Implementierung zu beseitigen.
## HTTP/2
Zu dieser im Mai 2015 von der IETF verabschiedeten Version von HTTP wurde maßgeblich
beigetragen von Google und Microsoft, die jeweils Versuche gemacht haben, HTTP
in Hinsicht auf Geschwindigkeit und Latenz zu verbessern. Ein bekannter und
grundgebender Vorgänger dieser Version war das von Google kreierte SPDY-Protokoll.
In dieser Version können mehrere Anfragen zusammengefasst werden ("Multiplex")
und dann zum Beispiel gemeinsam inklusive Headerdaten komprimiert werden, Inhalte
können binär kodiert übertragen werden und der Server kann von sich aus Inhalte
in den Client vorladen ("push"-Verfahren).
HTTP/2 funktioniert — obwohl die Spezifikation das mittlerweile nicht mehr
strikt einschränkt — so gut wie nur noch auf TLS-verschlüsselten Verbindungen
("HTTPS"). Hintergrund ist der Gedanke, dass Verbindungen grundsätzlich
verschlüsselt sein sollten um vor allem Man-In-The-Middle-Attacken (MITM)
und ähnliche unerlaubte Zugriffe auf Klartextbasis zu verhindern.
Diese Version von HTTP wird in der Analyse nicht behandelt, da die Verschlüsselung
und binäre Kodierung den Rahmen des Dokuments sprengt.
# Analyse
Die Analyse der Anfragen findet auf der obersten OSI-Schicht statt, also wird
nur der Inhalt der eigentlichen Anfrage analysiert, nicht die Daten auf TCP-,
IP- oder Ethernet-Schicht.
Zum Auslesen der Anfragen und Antworten wird die Software Wireshark verwendet,
die vorher wie im folgenden Screenshot konfiguriert wurde:
![](img/01-http/ss_config.png)
Jede HTTP-Anfrage wird in einer TCP-Verbindung gekapselt, entsprechend wird zuerst mit TCP jeweils eine Verbindung per SYN-/ACK-Paketaustausch aufgebaut bevor die eigentliche HTTP-Anfrage verschickt wird:
![](img/01-http/ss_log_tcp.png)
Wireshark kann die eigentlich HTTP-Anfrage aus dem Paketstrom wieder zusammensetzen, indem man per Rechtsklick, Auswahl von "Folgen" und "TCP Stream" den Inhalt verfolgt:
![](img/01-http/ss_follow.png)
Unten stehende Anfragen und Antworten sind jeweils zusammenhängend.
## `GET`-Anfrage
![](img/01-http/ss_browser_get.png)
### Anfrage
```http
GET / HTTP/1.1
Host: test.icedream.tech
Connection: keep-alive
Cache-Control: max-age=0
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
Upgrade-Insecure-Requests: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
DNT: 1
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
```
Die obige Anfrage wurde vom Chromium-Browser generiert, die Seite die hier aufgerufen
wurde ist http://test.icedream.tech.
Die erste Zeile enthält die Information, dass diese Anfrage eine `GET`-Anfrage
ist, also keine Daten hochlädt sondern nur Daten anfordert. Sie enthält außerdem
die Information, dass Daten vom Pfad `/`, also dem Wurzelverzeichnis angefragt
werden. Zum Schluss gibt der Browser an, dass er auf der HTTP-Version 1.1
kommuniziert.
Nach der ersten Zeile folgen die eigentlichen Kopf- bzw. Headerinformationen
zu der Anfrage:
- `Host` gibt an über welchen DNS-Hostnamen die Website erreicht wurde. Dies
erlaubt dem Webserver Seiten für verschiedene Domains anzubieten und über
den Hostnamen zu entscheiden welche Website ausgeliefert wird.
- `Connection` gibt an ob die Verbindung nach Verarbeitung dieser Anfrage und
Rückgabe der Antwort geschlossen wird oder nicht. Die meisten modernen
Browser wollen die TCP-Verbindung aus Leistungsgründen aufrecht erhalten
und geben daher hier den Wert `keep-alive` an. Ansonsten kann hier `close`
übergeben werden, dann schließt der Webserver nach Beantwortung diese
TCP-Verbindung.
- `Cache-Control` gibt Informationen zum Cachingverhalten des Browsers an.
Diese Information ist in der Regel irrelevant.
- `User-Agent` gibt einige Informationen über den Client an der genutzt wurde
um die HTTP-Anfrage zu generieren. In diesem Fall gibt der Browser an ein
Mozilla-kompatibler Browser zu sein (`Mozilla/5.0`). Die meisten modernen
Browser geben hier Mozilla aus historischen Gründen an und geben stattdessen
nebendran genauere Informationen an. In diesem Fall folgt, dass das
Betriebssystem des Browsers ein Linux-basiertes 64-Bit System mit einem
Desktop auf Basis von X11 ist, sowie dass der Browser die Apple WebKit-Engine
verwendet, sich wie Gecko verhält und es auch ein Chrome-Browser sowie
ein Safari-kompatibler Browser ist, da Safari eine ähnliche Engine verwendet.
- `Upgrade-Insecure-Requests` ist eine Anfrage die moderne Browser mitschicken
um den Webserver aus Sicherheitsgründen zu bitten, auf HTTPS umzuleiten,
wenn eine HTTPS-Alternative existiert.
- `Accept` enthält die Dateitypen, die der Browser von der Website akzeptieren
würde samt Präferenzwerten.
- `DNT` (*Do Not Track*) ist ein Header, der von modernen Browsern
mitgeschickt wird um anzudeuten, dass der Benutzer des Browsers sich ungerne
tracken lassen würde.
- `Accept-Encoding` gibt an, welche Kodierformate der Browser unterstützt um
den Inhalt wieder entziffern zu können, in diesem Fall akzeptiert der Browser
`gzip`- und `deflate`-kodierte Daten neben den bereits implizierten
Klartextdaten. Diese Information kann der Server nutzen um Traffic-sparenden
Inhalt zu liefern.
- `Accept-Language` gibt an, welche Sprachen der Browser vorzieht. Je nach
Sprache kann sich die Website dazu entscheiden, zum Beispiel die englische
Version einer Seite statt der deutschen auszuliefern.
### Antwort
```http
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 760
Content-Type: text/plain
Date: Mon, 22 Jan 2018 16:11:59 GMT
Server: Caddy
Server: Caddy
Server: Caddy
Vary: Accept-Encoding
............[s.8....)...j.T.....<.0..MeQ..G....o.EB..w.n..e.d..~..t.:+H.<..s.w.4T..2...-..Od.2A.JkH6P.P"y'.......u%v.B............/.
=...{(.Vj..F[(.=l.m...g./Q ?.Piru.7Z..@Q.i.tU.,.We...i.."/uuu."..le...'......r\.C:.72.b......b
.m.t..dQ$*.Z..q.....j.|.A..KK.2...6E3.E..>.....k.B.Y..z.../U...n...Uvfz..t...}^.-.N..a...,.|Op.Fq*..e..}N......S?8...D5."...9.\8..Y.z......}[.@./.[......T...J.i.H.}Xw:_.Le..:.......E..
6.J.........T.g-..;@.Dw.Gd..<.c.#m.....N...y+K.,;..u8....6.....!..F.......:m...H.t.^.g..|...S..w......w.........P..w.).nG#....!./i.q.u....b]..........j...,qnlT....J#.#...T....S.88M7*;K......I[...u/x..-.. .....Q.l......)..I...=.&z..[.SA....{..]|....p....)v.x.[r.y.....S_3....1.X.jw.N....9.C.A.../....6..7..k.Zu...r.-.".'berFq.?.....c3.?.....#1.-...
```
Die Header-Daten setzen sich hier wie folgt zusammen:
- Die erste Zeile gibt die HTTP-Version des Servers (`HTTP/1.1`) und den
Statuscode für die Anfrage same Bedeutungstext (`200 OK`) zurück.
- `Content-Encoding` gibt an, dass der angefragte Inhalt kodiert wurde, und
wie der Inhalt kodiert wurde (in diesem Fall GZip-kodiert).
- `Content-Length` gibt die Länge des Inhalts in Bytes zurück. Dieser Header
ist tatsächlich optional und kann für endlos streamende Daten, wie z. B.
Livemedien (Icecast/Shoutcast o. Ä.) weggelassen werden.
- `Content-Type` gibt den MIME-Typen des Inhalts an. In diesem Fall wird ein
Klartextinhalt zurückgegeben. Würde der Inhalt auf einer Festplatte gespeichert
werden, hätte die Datei üblicherweise die Dateierweiterung `.txt` gehabt.
Weitere Beispiele wären:
- `text/html` (HTML-Inhalte),
- `application/javascript` (JavaScript-Ressourcen)
- `audio/mpeg` (MP3-Audiodateien)
- `video/mp4` (MP4-Videodateien)
- oder `image/jpeg` (JPEG-Bilder).
- `Date` beinhaltet das aktuelle Datum und die aktuelle Uhrzeit auf dem Server.
- `Server` gibt die Software aus auf der der Webserver läuft. In diesem Fall
wurden aufgrund eines Proxysetups auf dem Webserver mehrere Server-Header
hintereinander verschickt.
- `Vary` gibt Header an, die ein Cachingserver, der vor dem Webserver stehen
könnte, auswerten kann um zu entscheiden, ob bereits zwischengespeicherter
Inhalt für die gegebene Anfrage verwendet werden kann oder ob der Inhalt
aktualisiert werden muss. Für einen Browser ist dieser Header in der Regel
irrelevant.
Der Inhalt ist in diesem Fall kodiert. Wurde kein `Content-Encoding` angegeben,
wäre der Inhalt im Klartext sichtbar. Die Seite hat zwar sogenannte AJAX-Kapabilitäten, sprich sie kann bereits im Hintergrund Informationen zur Suchanfrage abschicken, die hier dafür benutzt werden Suchanfragen vor dem Abschicken der eigentlichen Suche zu liefern, aber diese Anfragen ignorieren wir hier.
## `POST`-Anfrage
Für den Test einer solchen Frage bin ich auf die unverschlüsselte Version der Seite
http://wiki.selfhtml.org gegangen und habe das Loginformular dort verwendet mit diesen Eingaben:
- Username: `testuser`
- Passwort: `testpasswort`
- Angemeldet bleiben: ja
- Vorherige Aktion: Suche nach Artikeln mit Wort `test`
Natürlich sind diese Daten nicht in ihrer Nutzerdatenbank existent, wir verwenden sie hier nur zu Testzwecken.
![](img/01-http/ss_selfhtml_login.png)
```http
POST /index.php?title=Spezial:Anmelden&returnto=Spezial:Suche&returnquery=profile%3Ddefault%26fulltext%3DSearch%26search%3Dtest HTTP/1.1
Host: wiki.selfhtml.org
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: de,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://wiki.selfhtml.org/index.php?title=Spezial:Anmelden&returnto=Spezial:Suche&returnquery=profile%3Ddefault%26fulltext%3DSearch%26search%3Dtest
Content-Type: application/x-www-form-urlencoded
Content-Length: 204
Cookie: webwiki_session=0v7632i2prj2ugc7mfjn60cbmle378fl
Connection: keep-alive
Upgrade-Insecure-Requestüs: 1
wpName=testuser&wpPassword=testpasswort&wpRemember=1&wploginattempt=Anmelden&wpEditToken=%2B%5C&title=Spezial%3AAnmelden&authAction=login&force=&wpLoginToken=c36f62fc9e3043163962cbb7530e29e35a69764f%2B%5C
```
Der eigentliche Unterschied zur `GET`-Anfrage ist eigentlich nur die Anfrage selbst. Die Antwort wird ähnlich, wenn nicht genau gleich aufgebaut sein wie bei der `GET`-Anfrage, da auf diese Anfrage wieder nur ein Inhalt ausgeliefert wird, auch wenn er dynamisch als Reaktion zum Login generiert wurde.
- Die erste Zeile enthält jetzt als Methode `POST` statt `GET`.
- Der Client hat jetzt einen `Referer`-Header mitverschickt um anzudeuten von welcher Seite die Daten gekommen sind.
- Außerdem wurde ein `Cookie` mitverschickt, den der Client bei sich gespeichert hat um dem Server bei der Zuweisung von Sitzungsdaten zu helfen.
- Der Browser hat einen `Content-Length` Header verschickt. Wie bei der Antwort zu einer `GET`-Anfrage auch wird hier die Länge des verschickten Inhalts angegeben, in diesem Fall von dem Inhalt der mit der `POST`-Anfrage verschickt wurde.
Nach den Headerdaten folgt ein Query als Inhalt, so wie man ihn auch von dynamischen Seiten von der Addresszeile kennt. Dieser Inhalt wird zu keinem Zeitpunkt dem Nutzer direkt angezeigt, sondern der gesamte Inhalt wird direkt vom Server ausgewertet. Das ist der Sinn und Zweck einer `POST`-Anfrage, nämlich Daten beliebiger Länge direkt dem Server zur Verarbeitung zukommen zu lassen.
In diesem Query sind unter anderem folgende Daten enthalten (unklare oder unwichtige Daten habe ich hier weggelassen):
- `wpName` mit Wert `testuser` — unser Username.
- `wpPassword` mit Wert `testpasswort` — unser Passwort.
- `wpRemember` mit Wert `1` — unsere Checkbox die sagt ob wir angemeldet bleiben wollen. Dafür wird auch unser Cookie verwendet.
- `wploginattempt` — Der Inhalt dieses Wertes ist der Inhalt des Absenden-Knopfs, `Anmelden`. Der Browser kann sich zwischen mehreren Absendknöpfen entscheiden und nur den Wert schicken, den der Benutzer auch angeklickt hat.
- `authAction` mit Wert `login` — gibt dem Server die Aktion an, die vom Formular angetriggert wird.
- `wpLoginToken` — enthält den Token für das Formular zum Login. Jedes Formular wird per sogenanntem "CSRF"-Token abgesichert um das Versenden eines solchen Formulars von einer fremden Seite zu vermeiden und der muss genau mit dem übereinstimmen was der Server erwartet.
\clearpage
# Quellenangaben
Alle Quellen wurden zuletzt am 24.01.2018 geprüft.
- https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol
- https://wiki.selfhtml.org/wiki/HTTP/WebDAV
- https://www.w3.org/Protocols/HTTP/1.0/spec.html
- https://www.w3.org/Protocols/HTTP/AsImplemented.html
Analysen wurden erstellt auf Basis dieser Seiten
- http://test.icedream.tech
- http://wiki.selfhtml.org