% ============================================ % 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]}.