A final version of the report.

This commit is contained in:
Christos Choutouridis 2026-01-12 15:08:05 +02:00
parent 59692b7c05
commit c5a062d073
2 changed files with 173 additions and 158 deletions

Binary file not shown.

View File

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