diff --git a/report/report.pdf b/report/report.pdf index 3e1bd40..989afd4 100644 Binary files a/report/report.pdf and b/report/report.pdf differ diff --git a/report/report.tex b/report/report.tex index 82f5306..28b7602 100755 --- a/report/report.tex +++ b/report/report.tex @@ -70,9 +70,12 @@ \usepackage{amsmath, amssymb, amsfonts} \usepackage{graphicx} +\usepackage{caption} \usepackage{subcaption} \usepackage{float} +\captionsetup[figure]{name=Εικόνα} + % Requires: -shell-escape compile argument \usepackage{minted} \usepackage{xcolor} % @@ -84,10 +87,11 @@ baselinestretch=1.1, tabsize=2, numbersep=8pt, + startinline, gobble=0 } -\setminted[σ;λ]{ +\setminted[sql]{ fontsize=\small, breaklines, autogobble, @@ -126,8 +130,8 @@ Τα παραδοτέα της εργασίας αποτελούνται από: \begin{itemize} \item Την παρούσα αναφορά. - \item Τον κατάλογο - \item Το \href{\repo}{σύνδεσμο} με το αποθετήριο που περιέχει όλο το project με τον κώδικα της εφαρμογής, τον κώδικα της αναφοράς, τις διορθώσεις και τα παραδοτέα. + \item Τον κατάλογο \textit{passman-dev/} με τον κώδικα της εφαρμογής μετά τις αλλαγές. + \item Το \href{\repo}{σύνδεσμο} με το αποθετήριο που περιέχει όλο το project με τον κώδικα της εφαρμογής, τον κώδικα της αναφοράς, τα branch των διορθώσεων και τα παραδοτέα. \end{itemize} \section{Περιγραφή της εφαρμογής} @@ -160,17 +164,18 @@ \section{Περιβάλλον δοκιμών και μεταφορά σε Docker} -Πριν την ανάλυση των κενών ασφάλειας κρίθηκε απαραίτητο να δημιουργηθεί ένα ελεγχόμενο και αναπαραγώγιμο περιβάλλον δοκιμών. -Αντί της χρήσης του προτεινόμενου περιβάλλοντος XAMPP, επιλέχθηκε η μεταφορά (porting) της εφαρμογής σε περιβάλλον Docker, το οποίο θεωρείται πιο σύγχρονη και ευέλικτη λύση. +Πριν την ανάλυση των κενών ασφάλειας κρίθηκε απαραίτητο να δημιουργηθεί ένα \textbf{ελεγχόμενο και αναπαραγώγιμο} περιβάλλον δοκιμών. +Αντί της χρήσης του προτεινόμενου περιβάλλοντος XAMPP, επιλέχθηκε η μεταφορά (porting) της εφαρμογής σε περιβάλλον \textbf{Docker}, το οποίο θεωρείται πιο σύγχρονη και ευέλικτη λύση. Η επιλογή του Docker επιτρέπει την ακριβή καθοδήγηση των εκδόσεων λογισμικού που χρησιμοποιούνται, την εύκολη αναπαραγωγή του περιβάλλοντος σε διαφορετικά συστήματα και τον σαφή διαχωρισμό των επιμέρους υπηρεσιών. -Συγκεκριμένα, η εφαρμογή διαχωρίστηκε σε δύο containers: -έναν web server (Apache με PHP) και έναν database server (MariaDB). +Συγκεκριμένα, η εφαρμογή διαχωρίστηκε αρχικά σε δύο containers: έναν web server (Apache με PHP) και έναν database server (MariaDB). +Τον MariaDB τον χρησιμοποιούμε από το επίσημο αποθετήριο, αλλά τον web, τον χτίζουμε με δικό μας Dockerfile. +Στο τέλος της διαδικασίας προστέθηκε ένας ακόμα (caddy) που αναλαμβάνει το reverse proxy για το https. Κατά τη διαδικασία μεταφοράς απαιτήθηκαν ορισμένες στοχευμένες αλλαγές: \begin{itemize} \item \textbf{Διαχείριση HTTP headers και sessions}: - Σε αντίθεση με το XAMPP, το περιβάλλον Docker χρησιμοποιεί αυστηρότερες ρυθμίσεις όσον αφορά την αποστολή HTTP headers. + Σε αντίθεση με το XAMPP, το περιβάλλον του Apache-php στο Docker χρησιμοποιεί αυστηρότερες ρυθμίσεις όσον αφορά την αποστολή HTTP headers. Αυτό αποκάλυψε προβλήματα στη ροή του κώδικα, όπου HTML output προηγούνταν κλήσεων όπως \textit{session\_start()} και \textit{header()}. Η λύση ήταν η αναδιάταξη του κώδικα, ώστε όλη η λογική ελέγχου και ανακατεύθυνσης να εκτελείται πριν από οποιοδήποτε HTML output. @@ -199,7 +204,8 @@ docker compose up -d --build Τα δεδομένα της βάσης αποθηκεύονται σε Docker named volume, εξασφαλίζοντας τη διατήρησή τους μεταξύ επανεκκινήσεων των containers. Μετά την επιτυχή εκκίνηση, η εφαρμογή είναι προσβάσιμη μέσω web browser στη διεύθυνση:\\ -\texttt{http://localhost/passman} +\texttt{http://localhost/passman}.\\ +Για περισσότερες πληροφορίες μπορείτε να επισκεφτείτε το \href{\repo}{αποθετήριο} της εφαρμογής. Για λόγους δοκιμών και ανάλυσης, είναι επίσης δυνατή η απευθείας πρόσβαση στη βάση δεδομένων μέσω τερματικού, χρησιμοποιώντας την εντολή: \begin{minted}[fontsize=\small]{bash} @@ -212,20 +218,17 @@ docker compose exec db mariadb -uroot -prootpass \label{sec:sqli} Το πρώτο κενό ασφάλειας που εξετάζεται αφορά την ευπάθεια σε επιθέσεις SQL Injection. -Η ευπάθεια αυτή προκύπτει όταν δεδομένα που παρέχονται από τον χρήστη ενσωματώνονται απευθείας σε SQL εντολές, χωρίς κατάλληλη επικύρωση ή χρήση μηχανισμών παραμετροποίησης (prepared statements). +Η ευπάθεια αυτή προκύπτει όταν δεδομένα που παρέχονται από τον χρήστη \textbf{ενσωματώνονται απευθείας} σε SQL εντολές, χωρίς κατάλληλη επικύρωση ή χρήση μηχανισμών παραμετροποίησης (prepared statements). Αποτέλεσμα είναι ο επιτιθέμενος να μπορεί να αλλοιώσει τη λογική του SQL query, οδηγώντας σε μη εξουσιοδοτημένη πρόσβαση ή/και διαρροή δεδομένων. -Στην εφαρμογή, η ευπάθεια εντοπίζεται σε πολλά σημεία και παρότι θα τα λύσουμε όλα εδώ παραθέτουμε ως παράδειγμα την ευπάθεια στο \textit{login.php}, καθώς αυτό είναι ίσως οτ πιο σοβαρό. +Στην εφαρμογή, η ευπάθεια εντοπίζεται σε πολλά σημεία και παρότι θα τα λύσουμε όλα, εδώ παραθέτουμε ως παράδειγμα την ευπάθεια στο \textit{login.php}, καθώς αυτό είναι ίσως οτ πιο σοβαρό. Η είσοδος του χρήστη (username/password), όπως φαίνεται στο απόσπασμα παρακάτω, εισάγεται απευθείας στο query αυθεντικοποίησης μέσω string concatenation. \begin{minted}{php} $sql_query = "SELECT * FROM login_users WHERE username='{$username}' AND password='{$password}';"; -// The SQL query is constructed by directly concatenating user-controlled input. -// This enables SQL injection, because the attacker can break out of the quoted string -// and inject additional SQL conditions (e.g., OR 1=1), bypassing authentication. \end{minted} \label{lst:sqli-login-query} -Στο συγκεκριμένο σημείο, το περιεχόμενο των μεταβλητών \textit{\$username} και \textit{\$password} δεν υφίσταται κανέναν έλεγχο ή escaping. +Στο συγκεκριμένο σημείο, το περιεχόμενο των μεταβλητών \textit{\$username} και \textit{\$password} \textbf{δεν υφίσταται κανέναν έλεγχο ή escaping}. Επομένως, ένας επιτιθέμενος μπορεί να εισάγει ειδικούς χαρακτήρες (π.χ. \texttt{'}) και SQL τελεστές (π.χ. \texttt{OR}) ώστε να παρακάμψει τη συνθήκη αυθεντικοποίησης. \begin{figure}[!ht] @@ -271,18 +274,17 @@ $sql_query = \label{fig:sqli_db_users} \end{figure} -Η συγκεκριμένη ευπάθεια θεωρείται ιδιαίτερα σοβαρή, καθώς υπονομεύει πλήρως τον μηχανισμό αυθεντικοποίησης και επιτρέπει μη εξουσιοδοτημένη πρόσβαση σε ευαίσθητα δεδομένα. -Στα επόμενα τμήματα παρουσιάζεται η αντιμετώπισή της με χρήση prepared statements, ώστε τα δεδομένα του χρήστη να μην μπορούν να επηρεάσουν τη σύνταξη της SQL εντολής. +Η συγκεκριμένη ευπάθεια θεωρείται \textbf{ιδιαίτερα σοβαρή}, καθώς υπονομεύει πλήρως τον μηχανισμό αυθεντικοποίησης και \textbf{επιτρέπει μη εξουσιοδοτημένη πρόσβαση σε ευαίσθητα δεδομένα}. \subsection{Αντιμετώπιση SQL Injection} \label{sec:sqli_fix} Η αντιμετώπιση του SQL Injection βασίζεται στη θεμελιώδη αρχή του διαχωρισμού \textit{δεδομένων} από \textit{εντολές}. -Το πρόβλημα στην αρχική υλοποίηση προέκυπτε επειδή το SQL query κατασκευαζόταν μέσω απλής συνένωσης (string concatenation) με δεδομένα που παρείχε ο χρήστης. +Το πρόβλημα στην αρχική υλοποίηση προέκυπτε επειδή το SQL query κατασκευαζόταν μέσω \textbf{απλής συνένωσης (string concatenation)} με δεδομένα που παρείχε ο χρήστης. Έτσι, ειδικοί χαρακτήρες και τελεστές SQL μπορούσαν να εισαχθούν ως μέρος της συμβολοσειράς, με αποτέλεσμα να αλλοιώνεται η σύνταξη και η λογική της SQL εντολής. -Η καθιερωμένη πρακτική αντιμετώπισης, η οποία προτείνεται τόσο από τις επίσημες οδηγίες ασφαλούς κωδικοποίησης (secure coding guidelines) όσο και από τον οργανισμό OWASP (Open Worldwide Application Security Project), είναι η χρήση \textit{prepared statements} με παραμέτρους (parameterized queries). -Με τη χρήση prepared statements, ο SQL server λαμβάνει πρώτα το statement (template) και στη συνέχεια τις παραμέτρους ως δεδομένα, χωρίς να επιτρέπεται η ερμηνεία τους ως τμήμα της SQL σύνταξης. +Η καθιερωμένη πρακτική αντιμετώπισης, η οποία προτείνεται τόσο από τις επίσημες οδηγίες ασφαλούς κωδικοποίησης (secure coding guidelines) όσο και από τον οργανισμό OWASP (Open Worldwide Application Security Project), είναι η χρήση \textbf{prepared statements} με παραμέτρους (parameterized queries). +Με τη χρήση prepared statements, ο SQL server λαμβάνει πρώτα το statement (template) και στη συνέχεια τις \textbf{παραμέτρους ως δεδομένα}, χωρίς να επιτρέπεται η ερμηνεία τους ως τμήμα της SQL σύνταξης. Ως αποτέλεσμα, οποιαδήποτε κακόβουλη είσοδος αντιμετωπίζεται ως απλό κείμενο (data) και όχι ως εκτελέσιμο SQL. \subsection{Υλοποίηση της διόρθωσης} @@ -350,55 +352,46 @@ $sql_query = \subsection{Περαιτέρω σημεία ευπάθειας σε SQL Injection} -Πέρα από το αρχικό κενό ασφάλειας στον μηχανισμό αυθεντικοποίησης, εντοπίστηκαν επιπλέον σημεία στην εφαρμογή όπου SQL εντολές κατασκευάζονταν δυναμικά μέσω συνένωσης συμβολοσειρών με δεδομένα προερχόμενα από τον χρήστη ή από session μεταβλητές. +Πέρα από το αρχικό κενό ασφάλειας στον μηχανισμό αυθεντικοποίησης, εντοπίστηκαν \textbf{επιπλέον σημεία} στην εφαρμογή όπου SQL εντολές κατασκευάζονταν δυναμικά μέσω συνένωσης συμβολοσειρών με δεδομένα προερχόμενα από τον χρήστη ή από session μεταβλητές. Τα σημεία αυτά δημιουργούν πρόσθετες επιφάνειες επίθεσης και καθιστούν την εφαρμογή ευάλωτη σε άμεσες ή έμμεσες (second-order) επιθέσεις SQL Injection. \subsubsection{Εγγραφή νέων χρηστών (\textit{register.php})} Στο αρχείο \textit{register.php}, η εγγραφή νέου χρήστη υλοποιούνταν με απευθείας ενσωμάτωση των πεδίων \textit{username} και \textit{password} σε εντολή \texttt{INSERT}. -Το Απόσπασμα~\ref{lst:sqli-register} παρουσιάζει τον προβληματικό κώδικα. - +Το Απόσπασμα παρακάτω παρουσιάζει τον προβληματικό κώδικα: \begin{minted}{php} // Vulnerable SQL construction: user-controlled input is concatenated directly. $sql_query = "INSERT INTO login_users (username,password) - VALUES ('{$new_username}','{$new_password}');"; + VALUES ('{$new_username}','{$new_password}');"; $result = $conn->query($sql_query); \end{minted} \label{lst:sqli-register} -Η πρακτική αυτή επιτρέπει την αλλοίωση της SQL σύνταξης μέσω κατάλληλης εισόδου, καθιστώντας δυνατή την εκτέλεση αυθαίρετων SQL εντολών. -Η διόρθωση πραγματοποιήθηκε με χρήση prepared statements και δεσμευμένων παραμέτρων. - \subsubsection{Αποθήκευση σημειώσεων (\textit{notes.php})} Στο \textit{notes.php}, η αποθήκευση νέων σημειώσεων πραγματοποιούνταν με δυναμική κατασκευή εντολής \texttt{INSERT}, η οποία περιλάμβανε τόσο το περιεχόμενο της σημείωσης όσο και το \textit{username} του συνδεδεμένου χρήστη. -Ο προβληματικός κώδικας φαίνεται στο Απόσπασμα~\ref{lst:sqli-notes}. - +Ο προβληματικός κώδικας φαίνεται στο Απόσπασμα εδώ: \begin{minted}{php} // Vulnerable SQL construction: note content and session data are injected into SQL. $sql_query = "INSERT INTO notes (login_user_id, note) - VALUES ((SELECT id FROM login_users - WHERE username='{$username}'), '{$new_note}')"; + VALUES ((SELECT id FROM login_users WHERE username='{$username}'), '{$new_note}')"; $result = $conn->query($sql_query); \end{minted} \label{lst:sqli-notes} Παρότι το \textit{username} προέρχεται από session μεταβλητή, δεν μπορεί να θεωρηθεί έμπιστο, καθώς μπορεί να αλλοιωθεί σε σενάρια XSS ή session hijacking. -Η διόρθωση βασίστηκε στη χρήση prepared statements τόσο για το υποερώτημα όσο και για το περιεχόμενο της σημείωσης. \subsubsection{Διαχείριση διαπιστευτηρίων ιστοσελίδων (\textit{dashboard.php})} Στο αρχείο \textit{dashboard.php} εντοπίστηκαν πολλαπλά σημεία SQL Injection που αφορούν την εισαγωγή, διαγραφή και προβολή αποθηκευμένων διαπιστευτηρίων. -Ενδεικτικά, το Απόσπασμα~\ref{lst:sqli-dashboard-insert} δείχνει τον τρόπο εισαγωγής νέας εγγραφής. - +Ενδεικτικά, το Απόσπασμα παρακάτω δείχνει τον τρόπο εισαγωγής νέας εγγραφής: \begin{minted}{php} // Vulnerable SQL construction: multiple user-controlled fields concatenated. $sql_query = "INSERT INTO websites (login_user_id,web_url,web_username,web_password) - VALUES ((SELECT id FROM login_users - WHERE username='{$username}'), - '{$new_website}','{$new_username}','{$new_password}');"; + VALUES ((SELECT id FROM login_users WHERE username='{$username}'), + '{$new_website}','{$new_username}','{$new_password}');"; $result = $conn->query($sql_query); \end{minted} \label{lst:sqli-dashboard-insert} -Αντίστοιχα, η διαγραφή εγγραφών βασιζόταν σε δυναμικά κατασκευασμένη εντολή \texttt{DELETE}, όπως φαίνεται στο Απόσπασμα~\ref{lst:sqli-dashboard-delete}. +Αντίστοιχα, η διαγραφή εγγραφών βασιζόταν σε δυναμικά κατασκευασμένη εντολή \texttt{DELETE}, όπως φαίνεται στο επόμενο Απόσπασμα. \begin{minted}{php} // Vulnerable DELETE statement: identifier injected directly into SQL. @@ -411,14 +404,13 @@ $sql_query = \begin{minted}{php} // Vulnerable SELECT statement: session data treated as trusted input. $sql_query = "SELECT * FROM websites - INNER JOIN login_users - ON websites.login_user_id=login_users.id - WHERE login_users.username='{$username}';"; + INNER JOIN login_users ON websites.login_user_id=login_users.id + WHERE login_users.username='{$username}';"; $result = $conn->query($sql_query); \end{minted} \label{lst:sqli-dashboard-select} -Η συνολική αντιμετώπιση των παραπάνω σημείων βασίστηκε στην ίδια αρχή με το αρχικό SQL Injection, ότι καμία τιμή που επηρεάζει τη σύνταξη SQL εντολής δεν ενσωματώνεται πλέον απευθείας στο query. +Η συνολική αντιμετώπιση των παραπάνω σημείων βασίστηκε στην ίδια αρχή με το αρχικό SQL Injection, ότι \textbf{καμία τιμή που επηρεάζει τη σύνταξη SQL εντολής δεν ενσωματώνεται πλέον απευθείας στο query}. Όλα τα παραπάνω αντικαταστάθηκαν με prepared statements και δεσμευμένες παραμέτρους, εξαλείφοντας τόσο άμεσα όσο και έμμεσα σενάρια SQL Injection. Ο αναγνώστης μπορεί \href{\fixsqlitag}{εδώ} να βρει το branch με όλες τις αλλαγές. @@ -436,10 +428,9 @@ $sql_query = Η ευπάθεια προκύπτει όταν περιεχόμενο που εισάγει ο χρήστης αποθηκεύεται στη βάση δεδομένων και στη συνέχεια προβάλλεται -- πιθανόν σε άλλους χρήστες -- χωρίς κατάλληλη κωδικοποίηση εξόδου (output encoding). Ως αποτέλεσμα, κακόβουλος κώδικας JavaScript μπορεί να εκτελεστεί στον browser του θύματος με τα δικαιώματα του αντίστοιχου session. -\subsection{Root cause στον κώδικα} +\subsection{XSS στο \textit{notes.php}} Στο \textit{notes.php}, οι αποθηκευμένες σημειώσεις προβάλλονται απευθείας μέσα σε HTML με χρήση \texttt{echo}, χωρίς escaping. -Ενδεικτικά, το Απόσπασμα~\ref{lst:xss-notes-echo} δείχνει το προβληματικό σημείο: το \texttt{\$row["note"]} (δεδομένο από τη βάση) θεωρείται ως έμπιστο και εισάγεται αυτούσιο στο DOM. - +Ενδεικτικά, το Απόσπασμα παρακάτω δείχνει το προβληματικό σημείο: το \texttt{\$row["note"]} (δεδομένο από τη βάση) θεωρείται ως έμπιστο και εισάγεται αυτούσιο στο DOM. \begin{minted}{php} while ($row = $result -> fetch_assoc()) { echo "
"; @@ -521,7 +512,7 @@ $sql_query = \subsubsection{Session hijacking demonstration μέσω \textit{usecookie.php}} \label{sec:xss_hijack} -Ο αντίκτυπος της ευπάθειας είναι ιδιαίτερα σοβαρός, καθώς το session cookie μπορεί να χρησιμοποιηθεί για πλαστοπροσωπία (session hijacking). +Ο αντίκτυπος της ευπάθειας είναι ιδιαίτερα σοβαρός, καθώς το \textbf{session cookie μπορεί να χρησιμοποιηθεί για πλαστοπροσωπία} (session hijacking). Στην Εικόνα~\ref{fig:xss_usecookie} φαίνεται η χρήση του \textit{usecookie.php} με παράμετρο το κλεμμένο \texttt{PHPSESSID}. Στη συνέχεια, η πρόσβαση σε προστατευμένη σελίδα της εφαρμογής (π.χ. \textit{dashboard.php}) είναι εφικτή ως ο χρήστης-θύμα, όπως φαίνεται στην Εικόνα~\ref{fig:xss_dashboard_after_hijack}. @@ -543,15 +534,13 @@ $sql_query = \end{figure} Με βάση τα παραπάνω, επιβεβαιώνεται ότι η εφαρμογή επιτρέπει αποθήκευση και εκτέλεση κακόβουλου JS κώδικα μέσω του μηχανισμού σημειώσεων, με αποτέλεσμα τόσο την εξαγωγή cookies όσο και την πρακτική επίδειξη πλαστοπροσωπίας. -Στα επόμενα τμήματα παρουσιάζεται η αντιμετώπιση της ευπάθειας με \textit{context-aware output encoding}, ώστε το περιεχόμενο της βάσης να αντιμετωπίζεται ως μη-έμπιστο και να προβάλλεται με ασφάλεια. - \subsection{Αντιμετώπιση Stored XSS στο \textit{notes.php}} \label{sec:xss_fix} -Η αντιμετώπιση του Stored XSS βασίζεται στην αρχή ότι \textit{οποιοδήποτε περιεχόμενο προέρχεται από τον χρήστη ή/και τη βάση δεδομένων πρέπει να θεωρείται μη-έμπιστο}. +Η αντιμετώπιση του Stored XSS βασίζεται στην αρχή ότι \textbf{οποιοδήποτε περιεχόμενο προέρχεται από τον χρήστη ή/και τη βάση δεδομένων πρέπει να θεωρείται μη-έμπιστο}. Στην αρχική υλοποίηση, το περιεχόμενο των σημειώσεων εμφανιζόταν απευθείας στο HTML, με αποτέλεσμα ο browser να το ερμηνεύει ως markup και να εκτελεί τυχόν ενσωματωμένο JavaScript. -Η καθιερωμένη πρακτική για την αποτροπή XSS σε \textit{HTML body context} είναι το \textit{context-aware output encoding}, δηλαδή η κωδικοποίηση ειδικών χαρακτήρων (π.χ. \texttt{<}, \texttt{>}, \texttt{"}, \texttt{'}) πριν από την προβολή τους. +Η καθιερωμένη πρακτική για την αποτροπή XSS σε \textit{HTML body context} είναι το \textbf{context-aware output encoding}, δηλαδή η κωδικοποίηση ειδικών χαρακτήρων (π.χ. \texttt{<}, \texttt{>}, \texttt{"}, \texttt{'}) πριν από την προβολή τους. Με αυτόν τον τρόπο, ακόμη και αν στη βάση υπάρχουν αποθηκευμένα payloads, αυτά προβάλλονται ως απλό κείμενο και δεν είναι δυνατόν να εκτελεστούν. \subsubsection{Υλοποίηση της διόρθωσης} @@ -588,11 +577,11 @@ $sql_query = \label{fig:xss_fix_weblogs} \end{figure} -Συνεπώς, η εφαρμογή \textit{context-aware output encoding} στο σημείο προβολής εξαλείφει την εκτέλεση αποθηκευμένων XSS payloads στο συγκεκριμένο context, διατηρώντας αμετάβλητη τη λειτουργικότητα της εφαρμογής. +Συνεπώς, η εφαρμογή \textit{context-aware output encoding} στο σημείο προβολής \textbf{εξαλείφει την εκτέλεση αποθηκευμένων XSS payloads} στο συγκεκριμένο context, διατηρώντας αμετάβλητη τη λειτουργικότητα της εφαρμογής. \subsection{Επέκταση της αντιμετώπισης XSS στα επιπλέον σημεία} -Η ευπάθεια Stored XSS που παρουσιάστηκε μέσω της λειτουργίας σημειώσεων δεν αποτελεί μεμονωμένο περιστατικό, αλλά ενδεικτικό ενός γενικότερου προγραμματιστικού μοτίβου στην εφαρμογή. +Η ευπάθεια Stored XSS που παρουσιάστηκε μέσω της λειτουργίας σημειώσεων \textbf{δεν αποτελεί μεμονωμένο περιστατικό}, αλλά ενδεικτικό ενός γενικότερου προγραμματιστικού μοτίβου στην εφαρμογή. Δεδομένα προερχόμενα από χρήστες ή από τη βάση δεδομένων προβάλλονταν απευθείας στο HTML χωρίς κατάλληλη κωδικοποίηση εξόδου. Για τον λόγο αυτό πραγματοποιήθηκε εκτενέστερη ανάλυση και εντοπίστηκαν επιπλέον σημεία με δυνητική ή άμεση ευπάθεια σε XSS. @@ -607,7 +596,7 @@ $sql_query = \end{minted} Η πρακτική αυτή επιτρέπει την αποθήκευση και εκτέλεση κακόβουλου HTML ή JavaScript κώδικα (\textit{Stored XSS}), με εκτέλεση του payload κάθε φορά που προβάλλεται η σελίδα. -Η αντιμετώπιση πραγματοποιήθηκε με εφαρμογή \textit{context-aware output encoding} σε όλα τα αντίστοιχα πεδία. + \subsubsection{Εμφάνιση ονόματος χρήστη από session (\textit{dashboard.php})} Στην ίδια σελίδα, το όνομα του συνδεδεμένου χρήστη εμφανιζόταν στο header της σελίδας. @@ -619,7 +608,7 @@ $sql_query = Παρότι τα session δεδομένα συχνά θεωρούνται έμπιστα, στην πράξη μπορούν να αλλοιωθούν σε σενάρια XSS, session hijacking ή cookie tampering. -Η συγκεκριμένη περίπτωση αποτελεί χαρακτηριστικό παράδειγμα \textit{second-order XSS}. +Η συγκεκριμένη περίπτωση αποτελεί χαρακτηριστικό παράδειγμα \textbf{second-order XSS}. Η αντιμετώπιση βασίστηκε στην κωδικοποίηση της τιμής πριν την εμφάνιση της. \subsubsection{Reflected XSS σε μηνύματα σφάλματος (\textit{login.php}, \textit{register.php})} @@ -631,8 +620,8 @@ $sql_query = \end{minted} -Στην παρούσα υλοποίηση, οι μεταβλητές αυτές λαμβάνουν μόνο στατικές συμβολοσειρές και δεν ενσωματώνουν δεδομένα εισόδου χρήστη. -Ως εκ τούτου, δεν είναι πρακτικά εκμεταλλεύσιμες για Reflected XSS στην τρέχουσα μορφή της εφαρμογής. +Στην παρούσα υλοποίηση, οι μεταβλητές αυτές λαμβάνουν μόνο \textbf{στατικές συμβολοσειρές} και δεν ενσωματώνουν δεδομένα εισόδου χρήστη. +Ως εκ τούτου, δεν είναι πρακτικά εκμεταλλεύσιμες για \textit{reflected XSS} στην τρέχουσα μορφή της εφαρμογής. Για τον λόγο αυτό, δεν πραγματοποιήθηκε περαιτέρω εκμετάλλευση, αλλά το σημείο καταγράφεται ως θεωρητικό σενάριο που θα απαιτούσε αντιμετώπιση σε μελλοντική επέκταση της εφαρμογής. Ο αναγνώστης μπορεί \href{\fixxsstag}{εδώ} να βρει το branch με όλες τις αλλαγές. @@ -644,34 +633,31 @@ $sql_query = \section{Αποθήκευση κωδικών αυθεντικοποίησης σε απλό κείμενο} \label{subsec:plaintext-auth} -Η εφαρμογή, στην αρχική της υλοποίηση, διαχειριζόταν τους κωδικούς αυθεντικοποίησης των χρηστών (login passwords) ως απλό κείμενο (plaintext). +Η εφαρμογή, στην αρχική της υλοποίηση, διαχειριζόταν τους \textbf{κωδικούς} αυθεντικοποίησης των χρηστών (login passwords) ως \textbf{απλό κείμενο (plaintext)}. Το πρόβλημα αυτό εμφανίζεται σε περισσότερα του ενός σημεία της εφαρμογής: \begin{enumerate} \item \textbf{Πίνακας βάσης δεδομένων \texttt{login\_users}:} Οι κωδικοί πρόσβασης αποθηκεύονταν αυτούσιοι στη βάση δεδομένων, γεγονός που μπορεί να επιβεβαιωθεί με απευθείας ερώτημα SQL. + Η αποθήκευση του κωδικού σε απλό κείμενο είναι άμεσα ορατή και στο περιεχόμενο της βάσης δεδομένων, όπως φαίνεται στην Εικόνα~\ref{fig:pltxt_vuln_logins}. + \begin{figure}[!ht] + \centering + \includegraphics[width=0.7\textwidth]{img/pltxt-VulnLogins.png} + \caption{Κωδικοί χρηστών σε απλό κείμενο.} + \label{fig:pltxt_vuln_logins} + \end{figure} \item \textbf{Διαδικασία εγγραφής χρήστη (\texttt{register.php}):} Ο κωδικός που εισάγεται από τον χρήστη αποθηκευόταν στη βάση χωρίς καμία μορφή μετασχηματισμού (hashing). + \begin{minted}{php} + $sql_query = "INSERT INTO login_users (username,password) VALUES + ('{$new_username}','{$new_password}');"; + $result = $conn->query($sql_query); + \end{minted} \item \textbf{Διαδικασία σύνδεσης χρήστη (\texttt{login.php}):} - Η αυθεντικοποίηση πραγματοποιούνταν με άμεση σύγκριση του κωδικού που εισάγει ο χρήστης με τον αποθηκευμένο κωδικό, μέσω της SQL εντολής \texttt{WHERE username = ? AND password = ?}. - - \item \textbf{Αποθήκευση κωδικών τρίτων ιστοσελίδων (\texttt{dashboard.php}):} - Οι κωδικοί πρόσβασης ιστοσελίδων αποθηκεύονται και εμφανίζονται επίσης ως απλό κείμενο. Το συγκεκριμένο ζήτημα αναλύεται ξεχωριστά σε επόμενη ενότητα, καθώς απαιτεί διαφορετική προσέγγιση (κρυπτογράφηση αντί για hashing). -\end{enumerate} - -\subsection{Επιπτώσεις ασφάλειας και σενάρια εκμετάλλευσης} - -Η αποθήκευση κωδικών αυθεντικοποίησης σε απλό κείμενο αυξάνει δραματικά τον αντίκτυπο οποιασδήποτε παραβίασης της βάσης δεδομένων. -Σε περίπτωση που ένας επιτιθέμενος αποκτήσει πρόσβαση ανάγνωσης στη βάση (π.χ. μέσω SQL Injection, διαρροής backup ή εσφαλμένων δικαιωμάτων), μπορεί να ανακτήσει άμεσα όλους τους κωδικούς χρηστών χωρίς καμία επιπλέον προσπάθεια. - -Επιπλέον, επειδή η αυθεντικοποίηση βασιζόταν σε σύγκριση plaintext τιμών εντός της SQL εντολής, η διαρροή του πίνακα \texttt{login\_users} οδηγεί άμεσα σε πλήρη παραβίαση όλων των λογαριασμών, χωρίς να απαιτείται σπάσιμο (cracking) κωδικών ή hashes. - -\subsection{Ευάλωτη υλοποίηση} -Στην αρχική υλοποίηση, η σύγκριση του κωδικού πραγματοποιούνταν απευθείας μέσα στη SQL εντολή αυθεντικοποίησης. - -\begin{minted}{php} + Η αυθεντικοποίηση πραγματοποιούνταν μέσω της SQL εντολής \texttt{WHERE username = ? AND password = ?}, με άμεση σύγκριση του κωδικού που εισάγει ο χρήστης με τον αποθηκευμένο κωδικό. + \begin{minted}{php} $sql_query = "SELECT * FROM login_users WHERE username='{$username}' AND password='{$password}';"; $result = $conn->query($sql_query); @@ -681,31 +667,49 @@ $sql_query = $_SESSION['loggedin'] = true; // ... } -\end{minted} + \end{minted} -Αντίστοιχα, κατά την εγγραφή νέου χρήστη, ο κωδικός αποθηκευόταν αυτούσιος στη βάση δεδομένων. -\begin{minted}{php} - $sql_query = "INSERT INTO login_users (username,password) VALUES - ('{$new_username}','{$new_password}');"; - $result = $conn->query($sql_query); -\end{minted} + \item \textbf{Αποθήκευση κωδικών τρίτων ιστοσελίδων (\texttt{dashboard.php}):} + Οι κωδικοί πρόσβασης ιστοσελίδων αποθηκεύονται και εμφανίζονται επίσης ως απλό κείμενο. + Η λύση του συγκεκριμένου ζητήματος απαιτεί τη δημιουργία επιπλέον κώδικα για την κωδικοποίηση και αποκωδικοποίηση των δεδομένων, αλλά και αρκετές αλλαγές σε επίπεδο αρχητεκτονικής. + Για παράδειγμα πρέπει να αποφασιστεί που θα αποθηκεύονται τα κλειδιά κωδικοποίησης, πως θα γίνει η αναδιάρθρωση του κώδικα για να αρχικοποιούνται τα κλειδιά κλπ. + Για το λόγο αυτό \textbf{η υλοποίησή κρίθηκε εκτός ορίων για τη συγκεκριμένη εργασία}. -Η αποθήκευση του κωδικού σε απλό κείμενο είναι άμεσα ορατή και στο περιεχόμενο -της βάσης δεδομένων, όπως φαίνεται στο αντίστοιχο στιγμιότυπο οθόνης. -\begin{figure}[!ht] - \centering - \includegraphics[width=0.7\textwidth]{img/pltxt-VulnLogins.png} - \caption{Κωδικοί χρηστών σε απλό κείμενο.} - \label{fig:pltxt_vuln_logins} -\end{figure} + Αν όμως θα υλοποιούσαμε τέτοια αλλαγή, η λύση θα έπρεπε να προσθέσει ένα νέο αρχείο, π.χ. \textit{crypto.php}, το οποίο θα περιείχε βοηθητικές συναρτήσεις συμμετρικής κρυπτογράφησης με authenticated encryption (π.χ. AES-256-GCM). + Ενδεικτικά: + \begin{enumerate} + \item \textbf{\texttt{pm\_get\_key()}}: ανάκτηση του μυστικού κλειδιού από environment variable (π.χ. \texttt{APP\_ENC\_KEY}) και παραγωγή σταθερού 32-byte key (π.χ. με \texttt{hash('sha256', ... , true)}), ώστε το κλειδί να μην βρίσκεται ποτέ hard-coded στο repository. + + \item \textbf{\texttt{pm\_encrypt(\$plaintext)}}: κρυπτογράφηση του password πριν την αποθήκευση, με τυχαίο IV (\texttt{random\_bytes}) και παραγωγή authentication tag, και επιστροφή ενός base64 blob (π.χ. \texttt{base64(iv || tag || cipher)}) κατάλληλου για αποθήκευση σε \texttt{VARCHAR}. + + \item \textbf{\texttt{pm\_decrypt(\$blob)}}: αποκρυπτογράφηση του αποθηκευμένου blob κατά την προβολή, με έλεγχο εγκυρότητας (base64 + μήκος + tag), και (προαιρετικά) fallback σε plaintext για παλαιές εγγραφές ώστε να διευκολυνθεί η μετάβαση (migration). + \end{enumerate} + + Στη συνέχεια, θα έπρεπε να γίνουν στοχευμένες αλλαγές στο \textit{dashboard.php}: + \begin{enumerate} + \item Στο σημείο εισαγωγής νέας εγγραφής, να γίνεται \texttt{require\_once 'crypto.php'} και να αντικαθίσταται η αποθήκευση του \texttt{\$new\_password} με \texttt{\$enc\_password = pm\_encrypt(\$new\_password)} πριν το \texttt{INSERT} (ώστε στη βάση να καταλήγει μόνο ciphertext), και + + \item Στο σημείο προβολής της λίστας, να γίνεται \texttt{\$plain\_pass = pm\_decrypt(\$row['web\_password'])} πριν το \texttt{htmlspecialchars} και την εκτύπωση στο HTML (ώστε να εμφανίζεται στον χρήστη το πραγματικό password, αλλά να παραμένει κρυπτογραφημένο στην αποθήκευση). + + \item Τέλος, θα απαιτούνταν μία διαδικασία migration (π.χ. προσωρινό script) για να κρυπτογραφηθούν οι ήδη αποθηκευμένοι plaintext κωδικοί στο \texttt{websites} table, καθώς και ρύθμιση του container/compose ώστε να ορίζεται το \texttt{APP\_ENC\_KEY} ως secret μέσω environment variables. + \end{enumerate} + +\end{enumerate} + +\subsection{Επιπτώσεις ασφάλειας και σενάρια εκμετάλλευσης} + +Η αποθήκευση κωδικών αυθεντικοποίησης σε απλό κείμενο αυξάνει δραματικά τον αντίκτυπο οποιασδήποτε παραβίασης της βάσης δεδομένων. +Σε περίπτωση που ένας επιτιθέμενος αποκτήσει πρόσβαση ανάγνωσης στη βάση (π.χ. μέσω SQL Injection, διαρροής backup ή εσφαλμένων δικαιωμάτων), μπορεί να ανακτήσει άμεσα όλους τους κωδικούς χρηστών χωρίς καμία επιπλέον προσπάθεια. + +Επιπλέον, επειδή η αυθεντικοποίηση βασιζόταν σε σύγκριση plaintext τιμών εντός της SQL εντολής, η διαρροή του πίνακα \texttt{login\_users} οδηγεί άμεσα σε πλήρη παραβίαση όλων των λογαριασμών, χωρίς να απαιτείται σπάσιμο (cracking) κωδικών ή hashes. \subsection{Προσέγγιση αντιμετώπισης} -Για την ασφαλή διαχείριση κωδικών αυθεντικοποίησης, οι κωδικοί δεν πρέπει ποτέ να αποθηκεύονται σε απλό κείμενο. +Για την ασφαλή διαχείριση κωδικών αυθεντικοποίησης, \textbf{οι κωδικοί δεν πρέπει ποτέ να αποθηκεύονται σε απλό κείμενο}. Η καθιερωμένη πρακτική είναι: \begin{itemize} - \item χρήση συναρτήσεων hashing με ενσωματωμένο salt κατά την εγγραφή, - \item επαλήθευση του κωδικού κατά τη σύνδεση μέσω σύγκρισης hash και όχι μέσω SQL. + \item χρήση συναρτήσεων \textbf{hashing} με ενσωματωμένο salt κατά την εγγραφή, + \item \textbf{επαλήθευση} του κωδικού κατά τη σύνδεση μέσω σύγκρισης hash και \textbf{όχι μέσω SQL}. \end{itemize} Στην παρούσα εργασία χρησιμοποιούνται οι συναρτήσεις \texttt{password\_hash()} και \texttt{password\_verify()} της PHP, οι οποίες θεωρούνται βέλτιστη πρακτική για την αποθήκευση κωδικών. @@ -713,14 +717,26 @@ $sql_query = \subsection{Διορθωμένη υλοποίηση} -Στη διορθωμένη υλοποίηση οι κωδικοί πλέον δεν εισάγονται στη βάση αυτούσιοι, αλλά περνούν πρώτα από: +Στη διορθωμένη υλοποίηση οι κωδικοί πλέον δεν εισάγονται στη βάση απευθείας από τη μεταβλητή του UI \textit{new\_password}, αλλά \textbf{περνά πρώτα από hashing}: \begin{minted}{php} + $sql_query = "INSERT INTO login_users (username, password) VALUES (?, ?)"; + $stmt = $conn->prepare($sql_query); + // ... $password_hash = password_hash($new_password, PASSWORD_DEFAULT); + $stmt->bind_param("ss", $new_username, $password_hash); + $result = $stmt->execute(); \end{minted} -Ομοίως κατά το login, η επαλήθευση γίνεται με την: +Ομοίως κατά το login (\textit{login.php}), η επαλήθευση στον κωδικό γίνεται με την \textit{password\_verify}. \begin{minted}{php} - password_verify($password, $stored_hash); + $stmt = $conn->prepare("SELECT id, password FROM login_users WHERE username = ?"); + $stmt->bind_param("s", $username)->execute(); + $result = $stmt->get_result(); + if ($result && $result->num_rows === 1) { + if (password_verify($password, $result->fetch_assoc()["password"])) { + // succesful password verification + } + } \end{minted} \subsection{Απαιτούμενες αλλαγές περιβάλλοντος και βάσης δεδομένων} @@ -728,17 +744,17 @@ $sql_query = Για τον προ-εγκατεστημένο χρήστη δοκιμών (\texttt{u1/p1}), η διαδικασία πραγματοποιήθηκε χειροκίνητα στο περιβάλλον Docker, ως εξής: Αρχικά δημιουργήσαμε ένα hashed κωδικό για τον υπάρχον χρήστη: -\begin{verbatim} +\begin{minted}{bash} $ docker compose exec web bash root@ee33aeda3931:/var/www/html# php -r \ 'echo password_hash("p1", PASSWORD_DEFAULT), PHP_EOL;' $2y$10$L18u5/PyVkDgsce/DsUOQu0sKhTzh854Euhog3cVb1W4YAfgRzY8W root@ee33aeda3931:/var/www/html# exit -\end{verbatim} +\end{minted} Έπειτα αλλάξαμε των κωδικό χειροκίνητα στη βάση: -\begin{verbatim} +\begin{minted}{sql} MariaDB [pwd_mgr]> SELECT * FROM login_users; +----+----------+----------+ | id | username | password | @@ -756,22 +772,25 @@ $sql_query = +----+----------+--------------------------------------------------------------+ | 1 | u1 | $2y$10$L18u5/PyVkDgsce/DsUOQu0sKhTzh854Euhog3cVb1W4YAfgRzY8W | +----+----------+--------------------------------------------------------------+ -\end{verbatim} +\end{minted} Η παραπάνω διαδικασία επιβεβαιώνει την επιτυχή αντικατάσταση του plaintext κωδικού με ασφαλές hash, διασφαλίζοντας τη συμβατότητα της βάσης δεδομένων με τη νέα υλοποίηση αυθεντικοποίησης. -Τέλος ενημερώσαμε τον ίδιο κωδικό και στο αρχείο αρχικοποίησης της βάσης στον container. +Τέλος ενημερώσαμε τον ίδιο κωδικό και στο αρχείο αρχικοποίησης (\textit{01-create-pwd\_mgr-db-withData.sql}) της βάσης στον container. +\begin{minted}{sql} + -- php -r 'echo password_hash("p1", PASSWORD_DEFAULT), PHP_EOL;' + INSERT INTO `login_users` (`id`, `username`, `password`) VALUES + (1, 'u1', '$2y$10$L18u5/PyVkDgsce/DsUOQu0sKhTzh854Euhog3cVb1W4YAfgRzY8W'); +\end{minted} -\begin{figure}[H] +Στην Εικόνα~\ref{fig:pltxt_successful_login} φαίνεται η επιτυχής σύνδεση του υπάρχον χρήστη μετά την αλλαγή του κωδικού στην βάση. +\begin{figure}[!ht] \centering \includegraphics[width=0.45\textwidth]{img/pltxt-SuccessfulLogin.png} \caption{Επιτυχής σύνδεση χρήστη μετά την αλλαγή κωδικού.} \label{fig:pltxt_successful_login} \end{figure} -Στην Εικόνα~\ref{fig:pltxt_successful_login} φαίνεται η επιτυχής σύνδεση του υπάρχον χρήστη μετά την αλλαγή του κωδικού στην βάση. - - % ===================================================================== % DB admin credentials (root) used by the web app + mitigation @@ -780,11 +799,8 @@ $sql_query = \section{Χρήση διαπιστευτηρίων διαχειριστή (root)} \label{subsec:db-root-user} -Ένα επιπλέον σημαντικό πρόβλημα ασφάλειας της εφαρμογής είναι ότι η σύνδεση προς τη βάση δεδομένων -πραγματοποιείται με διαπιστευτήρια διαχειριστή (\textit{administrator credentials}, χρήστης \texttt{root}). -Η πρακτική αυτή παραβιάζει τη θεμελιώδη αρχή του \textit{least privilege} (ελάχιστα απαραίτητα προνόμια), -διότι οποιοσδήποτε επιτιθέμενος αποκτήσει δυνατότητα εκτέλεσης SQL εντολών (π.χ. μέσω SQL injection ή -μέσω πρόσβασης στη βάση) δεν περιορίζεται από δικαιώματα και μπορεί να πραγματοποιήσει καταστροφικές +Ένα επιπλέον σημαντικό πρόβλημα ασφάλειας της εφαρμογής είναι ότι η \textbf{σύνδεση} προς τη βάση δεδομένων πραγματοποιείται με \textbf{διαπιστευτήρια διαχειριστή} (\textit{administrator credentials}, χρήστης \texttt{root}). +Η πρακτική αυτή παραβιάζει τη θεμελιώδη αρχή του \textit{least privilege} (ελάχιστα απαραίτητα προνόμια), διότι οποιοσδήποτε επιτιθέμενος αποκτήσει δυνατότητα εκτέλεσης SQL εντολών (π.χ. μέσω SQL injection ή μέσω πρόσβασης στη βάση) δεν περιορίζεται από δικαιώματα και μπορεί να πραγματοποιήσει καταστροφικές ενέργειες. Το πρόβλημα εντοπίζεται στα ακόλουθα σημεία. @@ -792,26 +808,26 @@ $sql_query = \item config.php (defaults σε root). Στο αρχείο \textit{config.php}, οι παράμετροι της βάσης διαβάζονται από environment variables, αλλά αν δεν υπάρχουν τιμές, γίνεται fallback σε \texttt{root/rootpass}. -\begin{minted}{php} - $DB_HOST = getenv('DB_HOST') ?: 'db'; - $DB_USER = getenv('DB_USER') ?: 'root'; - $DB_PASS = getenv('DB_PASS') ?: 'rootpass'; - $DB_NAME = getenv('DB_NAME') ?: 'pwd_mgr'; -\end{minted} + \begin{minted}{php} + $DB_HOST = getenv('DB_HOST') ?: 'db'; + $DB_USER = getenv('DB_USER') ?: 'root'; + $DB_PASS = getenv('DB_PASS') ?: 'rootpass'; + $DB_NAME = getenv('DB_NAME') ?: 'pwd_mgr'; + \end{minted} \label{lst:db-root-config} \item docker-compose.yml (η web υπηρεσία τρέχει ως root στη DB). Στο \textit{docker-compose.yml} τα environment variables της web υπηρεσίας ορίζονται ρητά ως \texttt{root/rootpass}, οπότε ακόμη και αν αλλάζαμε μόνο το \textit{config.php}, η εφαρμογή θα συνέχιζε να συνδέεται ως root. -\begin{minted}{yaml} - services: - web: - environment: - DB_HOST: db - DB_USER: root - DB_PASS: rootpass - DB_NAME: pwd_mgr -\end{minted} + \begin{minted}{yaml} + services: + web: + environment: + DB_HOST: db + DB_USER: root + DB_PASS: rootpass + DB_NAME: pwd_mgr + \end{minted} \label{lst:compose-web-root} \item SQL init (δεν υπάρχει dedicated χρήστης εφαρμογής). @@ -827,8 +843,7 @@ $sql_query = \item είναι πιθανή \textbf{μόνιμη παραβίαση} (π.χ. αλλαγές σε grants/χρήστες), ανάλογα με τη ρύθμιση του DB server. \end{itemize} -Με άλλα λόγια, ακόμη και αν διορθωθούν SQLi σε επίπεδο κώδικα, η χρήση root αυξάνει σημαντικά το \textit{impact} -(impact amplification) οποιασδήποτε επιτυχούς επίθεσης. +Με άλλα λόγια, ακόμη και αν διορθωθούν SQLi σε επίπεδο κώδικα, η χρήση root αυξάνει σημαντικά τον αντίκτυπο (impact amplification) οποιασδήποτε επιτυχούς επίθεσης. \subsection{Αντιμετώπιση: least privilege χρήστης βάσης δεδομένων} @@ -836,7 +851,7 @@ $sql_query = στον οποίο εκχωρούνται μόνο τα απολύτως απαραίτητα δικαιώματα στο schema \texttt{pwd\_mgr}. \begin{itemize} - \item Αλλαγή στο SQL init: δημιουργία χρήστη και GRANT. + \item Αλλαγή στο \textbf{SQL init}: δημιουργία χρήστη και GRANT. Στο αρχείο \textit{01-create-pwd\_mgr-db-withData.sql} που φορτώνεται από \texttt{/docker-entrypoint-initdb.d}) προστέθηκαν οι παρακάτω εντολές: \begin{minted}{sql} -- Create a dedicated DB user for the web application (least privilege). @@ -847,9 +862,9 @@ $sql_query = \end{minted} \label{lst:db-create-app-user} Με αυτόν τον τρόπο, η εφαρμογή μπορεί να λειτουργήσει κανονικά, - ενώ παράλληλα δεν επιτρέπονται επικίνδυνα δικαιώματα όπως \texttt{DROP}, \texttt{ALTER}, \texttt{CREATE USER}, \texttt{GRANT OPTION}. + ενώ παράλληλα \textbf{δεν επιτρέπονται επικίνδυνα δικαιώματα} όπως \texttt{DROP}, \texttt{ALTER}, \texttt{CREATE USER}, \texttt{GRANT OPTION}. - \item Αλλαγή στο docker-compose.yml: web συνδέεται ως passman\_app. + \item Αλλαγή στο docker-compose.yml: web \textbf{συνδέεται ως passman\_app}. Στη συνέχεια, στο \textit{docker-compose.yml} αλλάχθηκαν τα credentials της web υπηρεσίας ώστε να χρησιμοποιείται ο νέος χρήστης: \begin{minted}{yaml} services: @@ -882,9 +897,8 @@ $sql_query = \label{lst:db-config-fixed} \end{itemize} -Με τις παραπάνω αλλαγές, η εφαρμογή λειτουργεί με περιορισμένα δικαιώματα στη βάση δεδομένων, -μειώνοντας σημαντικά τον αντίκτυπο (impact reduction) πιθανών επιθέσεων. -Η πρακτική αυτή αποτελεί βασικό μέτρο \textit{defense-in-depth} και ευθυγραμμίζεται με θεμελιώδεις αρχές secure design. +Με τις παραπάνω αλλαγές, \textbf{η εφαρμογή λειτουργεί με περιορισμένα δικαιώματα στη βάση δεδομένων}, μειώνοντας σημαντικά τον αντίκτυπο (impact reduction) πιθανών επιθέσεων. +Η πρακτική αυτή αποτελεί βασικό μέτρο \textbf{defense-in-depth} και ευθυγραμμίζεται με θεμελιώδεις αρχές secure design. Ένα παράδειγμα φαίνεται και στο στιγμιότυπο παρακάτω, όπου η βάση απορρίπτει τη διαγραφή πίνακα, στον χρήστη passman\_app: \begin{minted}{sql} @@ -912,13 +926,13 @@ MariaDB [(none)]> \label{subsec:http-https} Η εφαρμογή αρχικά λειτουργεί αποκλειστικά μέσω του μη ασφαλούς πρωτοκόλλου HTTP. -Όπως αναφέρεται και στην εκφώνηση, η χρήση HTTP επιτρέπει σε έναν επιτιθέμενο που παρακολουθεί την κίνηση του δικτύου (\textit{network observer / man-in-the-middle}) να υποκλέψει τις πληροφορίες που εμφανίζονται στον χρήστη και τα δεδομένα που αυτός αποστέλλει (π.χ. username/password στα forms). +Όπως αναφέρεται και στην εκφώνηση, η χρήση HTTP επιτρέπει σε έναν επιτιθέμενο που παρακολουθεί την κίνηση του δικτύου (\textit{network observer / man-in-the-middle}) \textbf{να υποκλέψει τις πληροφορίες} που εμφανίζονται στον χρήστη και τα δεδομένα που αυτός αποστέλλει (π.χ. username/password στα forms). Σε πραγματικό περιβάλλον, αυτό σημαίνει ότι: \begin{itemize} - \item τα credentials μπορούν να διαρρεύσουν σε plaintext, - \item το session cookie μπορεί να υποκλαπεί, - \item το περιεχόμενο σελίδων (π.χ. αποθηκευμένοι κωδικοί ιστοσελίδων) μπορεί να αναγνωστεί από τρίτους. + \item τα \textbf{credentials} μπορούν να διαρρεύσουν σε \textbf{plaintext}, + \item το \textbf{session cookie} μπορεί να \textbf{υποκλαπεί}, + \item το περιεχόμενο σελίδων (π.χ. αποθηκευμένοι κωδικοί ιστοσελίδων) μπορεί να \textbf{αναγνωστεί από τρίτους}. \end{itemize} \subsection{Πού εμφανίζεται στην υλοποίηση} @@ -936,6 +950,7 @@ MariaDB [(none)]> Επιπλέον, στο \textit{index.html} υπάρχουν hard-coded σύνδεσμοι προς \texttt{http://localhost/...}, οι οποίοι επιβάλλουν τη χρήση HTTP από τον browser. \begin{minted}{html} Login Page + // ... Dashboard Notes \end{minted} @@ -946,13 +961,12 @@ MariaDB [(none)]> \label{subsec:https-fix} Για να επιτευχθεί ασφαλής μεταφορά δεδομένων (\textit{transport security}), απαιτείται η χρήση HTTPS. -Σε περιβάλλον Docker, ένας πρακτικός και καθαρός τρόπος είναι να προστεθεί ένα reverse proxy -(π.χ. Caddy / NGINX) μπροστά από τον Apache web server. +Σε περιβάλλον Docker, ένας πρακτικός και καθαρός τρόπος είναι να προστεθεί ένα reverse proxy (π.χ. Caddy / NGINX) μπροστά από τον Apache web server. Το reverse proxy αναλαμβάνει: \begin{itemize} - \item TLS termination (διαπραγμάτευση κρυπτογράφησης), - \item αυτόματη ανακατεύθυνση από HTTP σε HTTPS, - \item προώθηση (proxying) της κίνησης προς το εσωτερικό container της εφαρμογής. + \item \textbf{TLS termination} (διαπραγμάτευση κρυπτογράφησης), + \item αυτόματη \textbf{ανακατεύθυνση} από HTTP σε HTTPS, + \item \textbf{προώθηση} (proxying) \textbf{της κίνησης} προς το εσωτερικό container της εφαρμογής. \end{itemize} Με αυτή την αρχιτεκτονική, το container \texttt{web} \textbf{δεν εκτίθεται πλέον} απευθείας προς τα έξω. @@ -982,11 +996,11 @@ MariaDB [(none)]> \label{lst:https-compose-after} \subsection{Ρύθμιση reverse proxy -- Caddyfile} -Για χρήση σε τοπικό περιβάλλον (\texttt{localhost}), επιλέχθηκε self-signed / internal TLS (\texttt{tls internal}). +Για χρήση σε τοπικό περιβάλλον (\texttt{localhost}), \textbf{επιλέχθηκε self-signed} (\texttt{tls internal}). Αυτό είναι κατάλληλο για demo/testing, καθώς δεν απαιτεί domain name ή δημόσιο πιστοποιητικό. Το \textit{Caddyfile} είναι: -\begin{minted}{text} +\begin{minted}{nginx} # HTTP site: redirect everything to HTTPS http://localhost { redir https://{host}{uri} permanent @@ -1008,7 +1022,7 @@ https://localhost { \label{lst:caddyfile} \paragraph{Σημείωση για τοπικά πιστοποιητικά (browser warning).} -Η χρήση \texttt{tls internal} δημιουργεί self-signed πιστοποιητικό, το οποίο ενδέχεται να προκαλέσει warning στον browser. +Η χρήση \texttt{tls internal} δημιουργεί self-signed πιστοποιητικό, το οποίο ενδέχεται να προκαλέσει \textbf{warning στον browser}. Το γεγονός αυτό είναι αναμενόμενο σε τοπικό demo περιβάλλον και δεν αναιρεί τη λειτουργία κρυπτογράφησης. Σε παραγωγικό περιβάλλον θα χρησιμοποιούνταν έγκυρο πιστοποιητικό (π.χ. μέσω Let's Encrypt) και domain name. @@ -1023,7 +1037,8 @@ https://localhost { \label{lst:https-index-after} \subsection{Επαλήθευση} -Όπως φαίνεται και στην Εικόνα~\ref{fig:https-sample}, μετά τις αλλαγές, η εφαρμογή είναι διαθέσιμη μέσω: \texttt{https://localhost/passman},. +Όπως φαίνεται και στην Εικόνα~\ref{fig:https-sample}, μετά τις αλλαγές, η εφαρμογή είναι διαθέσιμη μέσω:\\ +\texttt{https://localhost/passman}. \begin{figure}[!ht] \centering \includegraphics[width=0.55\textwidth]{img/https-Sample.png} @@ -1033,13 +1048,13 @@ https://localhost { Επιπλέον, η πρόσβαση σε \texttt{http://localhost/passman} οδηγεί σε αυτόματη ανακατεύθυνση προς HTTPS, επιβεβαιώνοντας ότι η μεταφορά δεδομένων προστατεύεται σε επίπεδο δικτύου. -\begin{verbatim} - $ curl -I http://localhost/passman - HTTP/1.1 301 Moved Permanently - Location: https://localhost/passman - Server: Caddy - Date: Sun, 11 Jan 2026 20:01:49 GMT -\end{verbatim} +\begin{minted}{bash} +$ curl -I http://localhost/passman + HTTP/1.1 301 Moved Permanently + Location: https://localhost/passman + Server: Caddy + Date: Sun, 11 Jan 2026 20:01:49 GMT +\end{minted} Με την εισαγωγή reverse proxy και την ενεργοποίηση HTTPS, μειώνεται σημαντικά ο κίνδυνος υποκλοπής δεδομένων (\textit{eavesdropping}) και επιτυγχάνεται προστασία στο επίπεδο μεταφοράς (transport layer), ενισχύοντας τη συνολική ασφάλεια της εφαρμογής. @@ -1047,18 +1062,18 @@ https://localhost { \section{Συμπεράσματα} -Στην παρούσα εργασία μελετήθηκε μια απλή διαδικτυακή εφαρμογή διαχείρισης κωδικών πρόσβασης, με στόχο την ανάδειξη και αντιμετώπιση κρίσιμων κενών ασφάλειας που προκύπτουν από μη ασφαλείς προγραμματιστικές πρακτικές. +Στην παρούσα εργασία μελετήθηκε μια απλή διαδικτυακή εφαρμογή διαχείρισης κωδικών πρόσβασης, με στόχο την \textbf{ανάδειξη και αντιμετώπιση κρίσιμων κενών ασφάλειας} που προκύπτουν από μη ασφαλείς προγραμματιστικές πρακτικές. Η προσέγγιση που ακολουθήθηκε ήταν πειραματική και βασισμένη σε πραγματικά σενάρια επίθεσης. Αρχικά εντοπίστηκαν ευπάθειες όπως SQL Injection, Stored Cross-Site Scripting, αποθήκευση κωδικών σε απλό κείμενο, χρήση διαπιστευτηρίων διαχειριστή για τη βάση δεδομένων και απουσία κρυπτογράφησης στο επίπεδο μεταφοράς (HTTP). -Για κάθε περίπτωση παρουσιάστηκε ο τρόπος εκμετάλλευσης, τεκμηριώθηκαν οι επιπτώσεις και στη συνέχεια εφαρμόστηκαν στοχευμένα διορθωτικά μέτρα, με ελάχιστη αλλά ουσιαστική παρέμβαση στον κώδικα και στη συνολική αρχιτεκτονική. +Για κάθε περίπτωση \textit{παρουσιάστηκε ο τρόπος εκμετάλλευσης, τεκμηριώθηκαν οι επιπτώσεις και στη συνέχεια εφαρμόστηκαν στοχευμένα διορθωτικά μέτρα}, με \textbf{ελάχιστη αλλά ουσιαστική παρέμβαση στον κώδικα} και στη συνολική αρχιτεκτονική. -Οι διορθώσεις υλοποιήθηκαν με βάση θεμελιώδεις αρχές ασφαλούς σχεδίασης, όπως ο διαχωρισμός δεδομένων και εντολών (prepared statements), η αντιμετώπιση κάθε εισόδου ως μη έμπιστης (output encoding), η ασφαλής αποθήκευση κωδικών μέσω hashing, η αρχή του least privilege στη διαχείριση της βάσης δεδομένων και η προστασία της επικοινωνίας μέσω HTTPS. -Ιδιαίτερη έμφαση δόθηκε όχι μόνο στη «διόρθωση» μεμονωμένων σφαλμάτων, αλλά και στη μείωση του συνολικού αντίκτυπου πιθανών επιθέσεων (impact reduction), υιοθετώντας μια προσέγγιση defense-in-depth. -Μέσα από τη διαδικασία αυτή κατέστη σαφές ότι πολλές σοβαρές ευπάθειες δεν οφείλονται σε πολύπλοκα σφάλματα, αλλά σε απλές παραλείψεις και λανθασμένες παραδοχές κατά την ανάπτυξη της εφαρμογής. +Οι διορθώσεις υλοποιήθηκαν με βάση θεμελιώδεις αρχές ασφαλούς σχεδίασης, όπως ο \textbf{διαχωρισμός δεδομένων και εντολών} (prepared statements), η \textbf{αντιμετώπιση κάθε εισόδου ως μη έμπιστης} (output encoding), η \textbf{ασφαλής αποθήκευση κωδικών μέσω hashing}, η αρχή του \textbf{least privilege} στη διαχείριση της βάσης δεδομένων και η προστασία της επικοινωνίας μέσω \textbf{HTTPS}. +Ιδιαίτερη έμφαση δόθηκε όχι μόνο στη «διόρθωση» μεμονωμένων σφαλμάτων, αλλά και στη μείωση του συνολικού αντίκτυπου πιθανών επιθέσεων (impact reduction), υιοθετώντας μια προσέγγιση \textbf{defense-in-depth}. +Μέσα από τη διαδικασία αυτή κατέστη σαφές ότι \textit{πολλές σοβαρές ευπάθειες δεν οφείλονται σε πολύπλοκα σφάλματα, αλλά σε απλές παραλείψεις και λανθασμένες παραδοχές} κατά την ανάπτυξη της εφαρμογής. Συνολικά, η εργασία ανέδειξε τη σημασία της ασφάλειας ως αναπόσπαστο μέρος του σχεδιασμού λογισμικού και όχι ως μεταγενέστερη προσθήκη. Η κατανόηση των μηχανισμών επίθεσης και η εφαρμογή βασικών πρακτικών secure coding επιτρέπουν τη δραστική βελτίωση της ασφάλειας ακόμη και σε απλές εφαρμογές. -Η εμπειρία που αποκομίστηκε υπογραμμίζει ότι η συστηματική σκέψη, η σωστή αρχιτεκτονική και η επίγνωση των κινδύνων είναι καθοριστικοί παράγοντες για την ανάπτυξη αξιόπιστων και ασφαλών πληροφοριακών συστημάτων. +Η εμπειρία που αποκομίστηκε υπογραμμίζει ότι η \textbf{συστηματική σκέψη}, η \textbf{σωστή αρχιτεκτονική} και η \textbf{επίγνωση των κινδύνων} είναι καθοριστικοί παράγοντες για την ανάπτυξη αξιόπιστων και ασφαλών πληροφοριακών συστημάτων. \end{document}