Add step 02: Configure firewall with UFW

This commit is contained in:
2026-05-06 15:36:33 +02:00
parent 0b454fb114
commit 2f2cbed5bd
9 changed files with 303 additions and 22 deletions
+191
View File
@@ -0,0 +1,191 @@
% ============================================
% STEP 02: FIREWALL MIT UFW
% ============================================
\section{Firewall mit UFW einrichten}
\label{sec:step02}
In diesem Schritt konfigurieren wir die Firewall des Servers mit \textbf{UFW} (Uncomplicated Firewall). UFW ist eine benutzerfreundliche Schnittstelle für \texttt{iptables}, die seit Ubuntu 8.04 standardmäßig installiert ist.
\subsection{Was ist eine Firewall und warum brauchen wir sie?}
Eine Firewall ist wie ein \textbf{Türsteher vor einem Club}: Sie entscheidet, welche Datenpakete (Gäste) hereinkommen und welche draußen bleiben. Ohne Firewall steht der Server "nackt" im Internet und jeder kann an jede Tür (Port) klopfen.
\textbf{Das Prinzip der minimalen Angriffsfläche:}
\begin{itemize}
\item Jeder offene Port ist eine potenzielle \textbf{Eintrittspforte} für Angreifer
\item Je weniger Ports offen sind, desto weniger Möglichkeiten gibt es für einen Angriff
\item Standard-Dienste haben oft \textbf{bekannte Sicherheitslücken} selbst wenn wir sie nicht aktiv nutzen
\end{itemize}
\subsection{Die 65.535 Ports: Ein kurzer Überblick}
Ein Server hat 65.535 TCP-Ports und 65.535 UDP-Ports. Jeder Netzwerkdienst lauscht auf einem bestimmten Port. Hier sind die bekanntesten:
\begin{table}[h]
\centering
\caption{Bekannte Ports und ihre Dienste}
\begin{tabular}{@{}cll@{}}
\toprule
\textbf{Port} & \textbf{Dienst} & \textbf{Risiko/Bemerkung} \\
\midrule
21 & FTP & Uralt, Passwörter im Klartext -- niemals offen lassen \\
22 & SSH & Unser Verwaltungszugang -- MUSS offen sein \\
23 & Telnet & Wie SSH, aber unverschlüsselt -- Todesurteil für Server \\
25 & SMTP & Mail-Versand -- Angreifer könnten Spam verschicken \\
53 & DNS & Namensauflösung -- Ziel für DDoS-Angriffe \\
80 & HTTP & Standard-Webport -- für unsere Fitness-App \\
110 & POP3 & E-Mail-Abruf -- veraltet, unsicher \\
143 & IMAP & E-Mail-Abruf -- veraltet \\
443 & HTTPS & Verschlüsselter Webport -- PFLICHT für PWAs! \\
3306 & MySQL & Datenbank -- beliebtes Bruteforce-Ziel \\
5432 & PostgreSQL & Datenbank -- ebenso populär bei Angreifern \\
6379 & Redis & Oft ohne Passwort vorkonfiguriert -- sehr gefährlich \\
8080 & HTTP-Alt & Häufig für Entwicklertools mit schwacher Absicherung \\
27017& MongoDB & Bekannt für katastrophale Standardkonfigurationen \\
\bottomrule
\end{tabular}
\end{table}
\textbf{Merksatz:} Alles, was du nicht explizit brauchst, wird blockiert. Das ist keine Paranoia, sondern Best Practice im Server-Management.
\subsection{Die drei Ports, die wir öffnen}
Wir öffnen nur drei Ports das absolute Minimum für einen Webserver:
\begin{table}[h]
\centering
\caption{Geöffnete Ports und ihre Begründung}
\begin{tabular}{@{}clp{5cm}@{}}
\toprule
\textbf{Port} & \textbf{Dienst} & \textbf{Warum offen?} \\
\midrule
22 & SSH & Unser \textbf{einziger Verwaltungszugang}. Ohne Port 22 könnten wir den Server nicht mehr fernsteuern -- wir wären ausgesperrt. \\
80 & HTTP & \textbf{Standard-Webport} für alle Browser. Wenn jemand deine Domain aufruft, landet er zuerst hier. Leitet später automatisch auf HTTPS (Port 443) um. \\
443 & HTTPS & \textbf{Verschlüsselte Webseiten}. Seit 2018 Pflicht für moderne Web-Apps! Ohne HTTPS verweigern Browser Funktionen wie PWA-Installation, Kamera-Zugriff oder Standort. \\
\bottomrule
\end{tabular}
\end{table}
\subsection{Warum HTTPS für PWAs Pflicht ist}
Eine Progressive Web App (PWA) \textbf{kann ohne HTTPS nicht installiert werden}. Das ist eine Sicherheitsanforderung von Google und Apple:
\begin{itemize}
\item Der \textbf{Service Worker} (das Herzstück einer PWA) benötigt zwingend HTTPS
\item Nur so kann der Browser garantieren, dass die App nicht manipuliert wurde
\item HTTP-Verbindungen können von Angreifern verändert werden (Man-in-the-Middle)
\end{itemize}
\textbf{Praxis-Beispiel:} Wenn du \texttt{http://deine-domain.de} aufrufst und dort die PWA installieren willst, verweigert Chrome die Installation. Erst mit \texttt{https://deine-domain.de} und einem gültigen SSL-Zertifikat funktioniert es.
\subsection{Durchführung}
\subsubsection{Standardrichtlinien setzen}
Zuerst definieren wir die grundlegenden Regeln: Alles Eingehende wird blockiert, alles Ausgehende erlaubt.
\textbf{Auf dem Server:}
\begin{lstlisting}[language=Bash, caption={Firewall-Standardregeln definieren}]
ufw default deny incoming
ufw default allow outgoing
\end{lstlisting}
\textbf{Erklärung der Befehle:}
\begin{itemize}
\item \texttt{ufw} -- das Firewall-Programm (Uncomplicated Firewall)
\item \texttt{default} -- setzt die Standardregel für alle Ports, die nicht explizit konfiguriert sind
\item \texttt{deny incoming} -- alle eingehenden Verbindungen werden \textbf{abgelehnt} (geblockt)
\item \texttt{allow outgoing} -- alle ausgehenden Verbindungen sind \textbf{erlaubt} (Server kann selbst ins Internet)
\end{itemize}
\textbf{Warum outgoing erlauben?} Der Server muss Updates herunterladen können (\texttt{apt update}), auf externe APIs zugreifen und im Internet kommunizieren. Das sind alles ausgehende Verbindungen -- die der Server selbst initiiert.
\subsubsection{Benötigte Ports öffnen}
Jetzt geben wir gezielt die drei Ports frei, die von außen erreichbar sein sollen.
\begin{lstlisting}[language=Bash, caption={Ports 22, 80, 443 für TCP freigeben}]
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
\end{lstlisting}
\textbf{Erklärung der Befehle:}
\begin{itemize}
\item \texttt{allow} -- dieser Port wird geöffnet
\item \texttt{22/tcp} -- Port 22, nur TCP-Protokoll (nicht UDP)
\item \texttt{80/tcp} -- Port 80 (HTTP), nur TCP
\item \texttt{443/tcp} -- Port 443 (HTTPS), nur TCP
\end{itemize}
\textbf{Warum nur TCP?} SSH, HTTP und HTTPS verwenden ausschließlich das TCP-Protokoll. UDP wird von diesen Diensten nicht benötigt. Würden wir nur \texttt{ufw allow 80} (ohne \texttt{/tcp}) schreiben, wäre auch UDP offen -- unnötige Angriffsfläche.
\subsubsection{Firewall aktivieren}
Die Firewall wurde bisher nur konfiguriert, ist aber noch nicht aktiv. Erst mit dem Enable-Befehl greifen die Regeln.
\begin{lstlisting}[language=Bash, caption={Firewall aktivieren}]
ufw --force enable
\end{lstlisting}
\textbf{Erklärung:}
\begin{itemize}
\item \texttt{enable} -- schaltet die Firewall ein
\item \texttt{--force} -- überspringt die Sicherheitsabfrage ("Bist du sicher?") und führt den Befehl direkt aus
\end{itemize}
\textbf{Achtung:} Wenn du Port 22 vergessen hättest, wärst du jetzt vom Server ausgesperrt! Die Firewall würde deine aktuelle SSH-Verbindung zwar nicht sofort trennen, aber ein erneuter Login wäre unmöglich. Deshalb prüfen wir im nächsten Schritt die Konfiguration.
\subsubsection{Konfiguration überprüfen}
\begin{lstlisting}[language=Bash, caption={Firewall-Status mit Details anzeigen}]
ufw status verbose
\end{lstlisting}
\textbf{Erklärung:}
\begin{itemize}
\item \texttt{status} -- zeigt an, ob die Firewall aktiv ist und welche Regeln gelten
\item \texttt{verbose} -- erweiterte Ausgabe mit zusätzlichen Details wie Logging-Einstellungen und Standardrichtlinien
\end{itemize}
Die erwartete Ausgabe:
\begin{lstlisting}[language=Bash, caption={Erwartete Firewall-Ausgabe (gekürzt)}]
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN Anywhere (v6)
80/tcp (v6) ALLOW IN Anywhere (v6)
443/tcp (v6) ALLOW IN Anywhere (v6)
\end{lstlisting}
\textbf{Wichtige Details der Ausgabe:}
\begin{itemize}
\item \texttt{Status: active} -- die Firewall läuft und blockt unerwünschten Traffic
\item \texttt{Default: deny (incoming)} -- alle nicht explizit erlaubten eingehenden Verbindungen werden geblockt
\item \texttt{Anywhere} -- diese Ports sind von \textbf{jeder} IP-Adresse aus erreichbar (für Webseiten notwendig)
\item \texttt{(v6)} -- die Regeln gelten identisch für IPv6, sodass auch moderne Netzwerke geschützt sind
\end{itemize}
\subsection{Zusammenfassung}
Nach diesem Schritt ist die Firewall aktiv und schützt den Server:
\begin{itemize}
\item \textbf{65.532 Ports sind dicht} -- nur 3 sind offen
\item \textbf{SSH} (22) bleibt als einziger Verwaltungszugang offen
\item \textbf{HTTP/HTTPS} (80/443) sind für die spätere Web-App vorbereitet
\item \textbf{IPv4 und IPv6} werden beide geschützt
\item Die Firewall startet automatisch bei jedem Server-Neustart
\end{itemize}
\textbf{Praxis-Tipp:} Mit dem Befehl \texttt{ufw status numbered} kannst du jederzeit alle Regeln mit Nummern anzeigen. Eine einzelne Regel löschst du dann mit \texttt{ufw delete [Nummer]}.