diff --git a/report/img/https-Sample.png b/report/img/https-Sample.png new file mode 100644 index 0000000..a2fa329 Binary files /dev/null and b/report/img/https-Sample.png differ diff --git a/report/img/pltxt-SuccessfulLogin.png b/report/img/pltxt-SuccessfulLogin.png new file mode 100644 index 0000000..46b26aa Binary files /dev/null and b/report/img/pltxt-SuccessfulLogin.png differ diff --git a/report/img/pltxt-VulnLogins.png b/report/img/pltxt-VulnLogins.png new file mode 100644 index 0000000..8d52a68 Binary files /dev/null and b/report/img/pltxt-VulnLogins.png differ diff --git a/report/img/pltxt-VulnWebsites.png b/report/img/pltxt-VulnWebsites.png new file mode 100644 index 0000000..c07be1f Binary files /dev/null and b/report/img/pltxt-VulnWebsites.png differ diff --git a/report/img/sqli-DBquery.png b/report/img/sqli-DBquery.png new file mode 100644 index 0000000..c650cf5 Binary files /dev/null and b/report/img/sqli-DBquery.png differ diff --git a/report/img/sqli-DBqueryFix.png b/report/img/sqli-DBqueryFix.png new file mode 100644 index 0000000..3b70dd0 Binary files /dev/null and b/report/img/sqli-DBqueryFix.png differ diff --git a/report/img/sqli-DBusers.png b/report/img/sqli-DBusers.png new file mode 100644 index 0000000..c07c329 Binary files /dev/null and b/report/img/sqli-DBusers.png differ diff --git a/report/img/sqli-LoginProof.png b/report/img/sqli-LoginProof.png new file mode 100644 index 0000000..5cb4a60 Binary files /dev/null and b/report/img/sqli-LoginProof.png differ diff --git a/report/img/sqli-LoginProofFix.png b/report/img/sqli-LoginProofFix.png new file mode 100644 index 0000000..0eacf5c Binary files /dev/null and b/report/img/sqli-LoginProofFix.png differ diff --git a/report/img/sqli-LoginScreen.png b/report/img/sqli-LoginScreen.png new file mode 100644 index 0000000..4b15e86 Binary files /dev/null and b/report/img/sqli-LoginScreen.png differ diff --git a/report/img/sqli-LoginScreenFix.png b/report/img/sqli-LoginScreenFix.png new file mode 100644 index 0000000..8825fd6 Binary files /dev/null and b/report/img/sqli-LoginScreenFix.png differ diff --git a/report/img/xss-ScA-ListCookie.png b/report/img/xss-ScA-ListCookie.png new file mode 100644 index 0000000..9d30b5b Binary files /dev/null and b/report/img/xss-ScA-ListCookie.png differ diff --git a/report/img/xss-ScA-NoteEntry.png b/report/img/xss-ScA-NoteEntry.png new file mode 100644 index 0000000..45c6856 Binary files /dev/null and b/report/img/xss-ScA-NoteEntry.png differ diff --git a/report/img/xss-ScA-NoteSubmited.png b/report/img/xss-ScA-NoteSubmited.png new file mode 100644 index 0000000..00c7caf Binary files /dev/null and b/report/img/xss-ScA-NoteSubmited.png differ diff --git a/report/img/xss-ScA-WebLogs.png b/report/img/xss-ScA-WebLogs.png new file mode 100644 index 0000000..3b0fca4 Binary files /dev/null and b/report/img/xss-ScA-WebLogs.png differ diff --git a/report/img/xss-ScB-ListCookie.png b/report/img/xss-ScB-ListCookie.png new file mode 100644 index 0000000..0725c37 Binary files /dev/null and b/report/img/xss-ScB-ListCookie.png differ diff --git a/report/img/xss-ScB-NoteEntry.png b/report/img/xss-ScB-NoteEntry.png new file mode 100644 index 0000000..283bc76 Binary files /dev/null and b/report/img/xss-ScB-NoteEntry.png differ diff --git a/report/img/xss-ScB-NoteSubmited.png b/report/img/xss-ScB-NoteSubmited.png new file mode 100644 index 0000000..0da6f92 Binary files /dev/null and b/report/img/xss-ScB-NoteSubmited.png differ diff --git a/report/img/xss-ScB-WebLogs.png b/report/img/xss-ScB-WebLogs.png new file mode 100644 index 0000000..84a71b1 Binary files /dev/null and b/report/img/xss-ScB-WebLogs.png differ diff --git a/report/img/xss-ScX-MySQLEntries.png b/report/img/xss-ScX-MySQLEntries.png new file mode 100644 index 0000000..2ebd661 Binary files /dev/null and b/report/img/xss-ScX-MySQLEntries.png differ diff --git a/report/img/xss-ScX-UseCookie.png b/report/img/xss-ScX-UseCookie.png new file mode 100644 index 0000000..6e1504e Binary files /dev/null and b/report/img/xss-ScX-UseCookie.png differ diff --git a/report/img/xss-SxX-NotesSubmitedFix.png b/report/img/xss-SxX-NotesSubmitedFix.png new file mode 100644 index 0000000..e01ff91 Binary files /dev/null and b/report/img/xss-SxX-NotesSubmitedFix.png differ diff --git a/report/img/xss-SxX-NotesSubmitedFix2.png b/report/img/xss-SxX-NotesSubmitedFix2.png new file mode 100644 index 0000000..c02974c Binary files /dev/null and b/report/img/xss-SxX-NotesSubmitedFix2.png differ diff --git a/report/img/xss-SxX-StolenSession.png b/report/img/xss-SxX-StolenSession.png new file mode 100644 index 0000000..4aaa82f Binary files /dev/null and b/report/img/xss-SxX-StolenSession.png differ diff --git a/report/img/xss-SxX-WebLogsFix.png b/report/img/xss-SxX-WebLogsFix.png new file mode 100644 index 0000000..36d25b8 Binary files /dev/null and b/report/img/xss-SxX-WebLogsFix.png differ diff --git a/report/report.pdf b/report/report.pdf new file mode 100644 index 0000000..3e1bd40 Binary files /dev/null and b/report/report.pdf differ diff --git a/report/report.tex b/report/report.tex new file mode 100755 index 0000000..82f5306 --- /dev/null +++ b/report/report.tex @@ -0,0 +1,1064 @@ +% +% !TEX TS-program = xelatex +% !TEX encoding = UTF-8 Unicode +% !TEX spellcheck = el-GR +% +% Information Systems Security assignment report +% +% Requires compilation with XeLaTeX +% +% authors: +% Χρήστος Χουτουρίδης ΑΕΜ 8997 +% cchoutou@ece.auth.gr + + +% Options: +% +% 1) mainlang= +% Default: english +% Set the default language of the document which affects hyphenations, +% localization (section, dates, etc...) +% +% example: \documentclass[mainlang=greek]{AUThReport} +% +% 2) +% Add hyphenation and typesetting support for other languages +% Currently supports: english, greek, german, frenc +% +% example: \documentclass[english, greek]{AUThReport} +% +% 3) short: Requests a shorter title for the document +% Default: no short +% +% example: \documentclass[short]{AUThReport} +% +\documentclass[a4paper, 11pt, mainlang=greek, english]{AUThReport/AUThReport} + +\CurrentDate{\today} + +% Greek report document setup suggestions +%--------------------------------- +% Document configuration +\AuthorName{Χρήστος Χουτουρίδης} +\AuthorAEM{8997} +\AuthorMail{cchoutou@ece.auth.gr} + +%\CoAuthorName{CoAuthor Name} +%\CoAuthorAEM{AEM} +%\CoAuthorMail{CoAuthor Mail} + +% \WorkGroup{Ομάδα Χ} + +\DocTitle{Εργασία Εξαμήνου} +\DocSubTitle{Ανάδειξη προβλημάτων ασφάλειας σε δικτυακή εφαρμογή αποθήκευσης κωδικών πρόσβασης (password manager) και αντιμετώπισή τους} + +\Department{Τμήμα ΗΜΜΥ. Τομέας Ηλεκτρονικής} +\ClassName{Ασφάλεια Υπολογιστικών Συστημάτων} + +\InstructorName{Γεώργιος Πάγκαλος} +\InstructorMail{pangalos@ece.auth.gr} + +\CoInstructorName{Αθανάσιος Σιαχούδης} +\CoInstructorMail{asiach@ece.auth.gr} + + +% Local package requirements +%--------------------------------- +%\usepackage{tabularx} +%\usepackage{array} +%\usepackage{commath} + +\usepackage{amsmath, amssymb, amsfonts} +\usepackage{graphicx} +\usepackage{subcaption} +\usepackage{float} + +% Requires: -shell-escape compile argument +\usepackage{minted} +\usepackage{xcolor} % + +\setminted[php]{ + fontsize=\small, + breaklines, + autogobble, + baselinestretch=1.1, + tabsize=2, + numbersep=8pt, + gobble=0 +} + +\setminted[σ;λ]{ + fontsize=\small, + breaklines, + autogobble, + baselinestretch=1.1, + tabsize=2, + numbersep=8pt, + gobble=0 +} + +\newcommand{\repo}{https://git.hoo2.net/hoo2/InformationSystemsSecurity} +\newcommand{\fixsqlitag}{https://git.hoo2.net/hoo2/InformationSystemsSecurity/releases/tag/fix-sqli} +\newcommand{\fixxsstag}{https://git.hoo2.net/hoo2/InformationSystemsSecurity/releases/tag/fix-xss} + + +\begin{document} + +% Request a title page or header +\InsertTitle + +\section{Εισαγωγή} + +Η ασφάλεια των πληροφοριακών συστημάτων αποτελεί κρίσιμο παράγοντα στον σχεδιασμό και τη λειτουργία σύγχρονων δικτυακών εφαρμογών. +Ιδιαίτερα εφαρμογές που διαχειρίζονται ευαίσθητα δεδομένα, όπως κωδικούς πρόσβασης, προσωπικές πληροφορίες και διαπιστευτήρια πρόσβασης, αποτελούν συχνό στόχο επιθέσεων. +Η εκμετάλλευση ευπαθειών σε τέτοιες εφαρμογές μπορεί να οδηγήσει σε σοβαρές παραβιάσεις εμπιστευτικότητας, ακεραιότητας και διαθεσιμότητας των δεδομένων. + +Σκοπός της παρούσας εργασίας είναι η μελέτη, ανάδειξη και αντιμετώπιση κενών ασφάλειας σε μία απλή διαδικτυακή εφαρμογή διαχείρισης κωδικών πρόσβασης (password manager). +Η εφαρμογή αυτή, αν και λειτουργικά επαρκής, υλοποιεί βασικές λειτουργίες χωρίς να λαμβάνει υπόψη θεμελιώδεις αρχές ασφάλειας λογισμικού. +Μέσα από την ανάλυση πραγματικών σεναρίων επίθεσης, η εργασία στοχεύει να καταδείξει πώς φαινομενικά μικρές παραλείψεις στον κώδικα μπορούν να οδηγήσουν σε σοβαρές ευπάθειες. + +Η προσέγγιση που ακολουθείται είναι πρακτική και πειραματική. +Αρχικά δημιουργείται ένα ελεγχόμενο περιβάλλον εκτέλεσης της εφαρμογής. +Στη συνέχεια εντοπίζονται και εκμεταλλεύονται συγκεκριμένα κενά ασφάλειας, τεκμηριώνονται οι επιπτώσεις τους και τέλος προτείνονται και υλοποιούνται διορθωτικά μέτρα. +Με τον τρόπο αυτό επιτυγχάνεται τόσο η κατανόηση των μηχανισμών επίθεσης όσο και η εμπέδωση καλών πρακτικών ασφαλούς ανάπτυξης λογισμικού. + +\subsection{Παραδοτέα} +Τα παραδοτέα της εργασίας αποτελούνται από: +\begin{itemize} + \item Την παρούσα αναφορά. + \item Τον κατάλογο + \item Το \href{\repo}{σύνδεσμο} με το αποθετήριο που περιέχει όλο το project με τον κώδικα της εφαρμογής, τον κώδικα της αναφοράς, τις διορθώσεις και τα παραδοτέα. +\end{itemize} + +\section{Περιγραφή της εφαρμογής} + +Η εφαρμογή που μελετάται αποτελεί ένα απλό web-based password manager, υλοποιημένο σε PHP και με χρήση σχεσιακής βάσης δεδομένων MySQL. +Η βασική της λειτουργία περιλαμβάνει τη δημιουργία λογαριασμών χρηστών, την αυθεντικοποίησή τους και την αποθήκευση διαπιστευτηρίων πρόσβασης σε τρίτους διαδικτυακούς τόπους. +Η εφαρμογή βασίζεται σε session management για τη διαχείριση της κατάστασης σύνδεσης και σε απλές SQL εντολές για την αλληλεπίδραση με τη βάση δεδομένων. + +Η δομή της εφαρμογής είναι απλή και αποτελείται από διακριτά αρχεία PHP, καθένα εκ των οποίων είναι υπεύθυνο για συγκεκριμένη λειτουργικότητα: + +\begin{itemize} + \item \textit{index.html}: + Αρχική σελίδα της εφαρμογής, η οποία παρέχει συνδέσμους προς τις επιμέρους λειτουργίες (εγγραφή, σύνδεση, πίνακας ελέγχου, σημειώσεις). + \item \textit{register.php}: + Υλοποιεί τη διαδικασία εγγραφής νέων χρηστών στη βάση δεδομένων. + Δέχεται στοιχεία από φόρμα και τα αποθηκεύει στον πίνακα χρηστών. + \item \textit{login.php}: + Υλοποιεί τη διαδικασία αυθεντικοποίησης χρηστών. + Ελέγχει τα παρεχόμενα διαπιστευτήρια και δημιουργεί session σε περίπτωση επιτυχούς σύνδεσης. + \item \textit{dashboard.php}: + Αποτελεί την κεντρική σελίδα μετά τη σύνδεση. + Παρέχει τη δυνατότητα προβολής, εισαγωγής και διαγραφής αποθηκευμένων διαπιστευτηρίων για ιστοσελίδες. + \item \textit{notes.php}: + Επιτρέπει την αποθήκευση και προβολή σημειώσεων ή ανακοινώσεων που σχετίζονται με τον χρήστη. + \item \textit{logout.php}: + Τερματίζει τη συνεδρία χρήστη και καταστρέφει τα δεδομένα session. + \item \textit{config.php}: + Περιέχει τις ρυθμίσεις σύνδεσης με τη βάση δεδομένων και χρησιμοποιείται από τα υπόλοιπα αρχεία μέσω include. +\end{itemize} + +\section{Περιβάλλον δοκιμών και μεταφορά σε Docker} + +Πριν την ανάλυση των κενών ασφάλειας κρίθηκε απαραίτητο να δημιουργηθεί ένα ελεγχόμενο και αναπαραγώγιμο περιβάλλον δοκιμών. +Αντί της χρήσης του προτεινόμενου περιβάλλοντος XAMPP, επιλέχθηκε η μεταφορά (porting) της εφαρμογής σε περιβάλλον Docker, το οποίο θεωρείται πιο σύγχρονη και ευέλικτη λύση. + +Η επιλογή του Docker επιτρέπει την ακριβή καθοδήγηση των εκδόσεων λογισμικού που χρησιμοποιούνται, την εύκολη αναπαραγωγή του περιβάλλοντος σε διαφορετικά συστήματα και τον σαφή διαχωρισμό των επιμέρους υπηρεσιών. +Συγκεκριμένα, η εφαρμογή διαχωρίστηκε σε δύο containers: +έναν web server (Apache με PHP) και έναν database server (MariaDB). + +Κατά τη διαδικασία μεταφοράς απαιτήθηκαν ορισμένες στοχευμένες αλλαγές: +\begin{itemize} + \item \textbf{Διαχείριση HTTP headers και sessions}: + Σε αντίθεση με το XAMPP, το περιβάλλον Docker χρησιμοποιεί αυστηρότερες ρυθμίσεις όσον αφορά την αποστολή HTTP headers. + Αυτό αποκάλυψε προβλήματα στη ροή του κώδικα, όπου HTML output προηγούνταν κλήσεων όπως \textit{session\_start()} και \textit{header()}. + Η λύση ήταν η αναδιάταξη του κώδικα, ώστε όλη η λογική ελέγχου και ανακατεύθυνσης να εκτελείται πριν από οποιοδήποτε HTML output. + + \item \textbf{Συμβατότητα χαρακτήρων και collation βάσης δεδομένων}: + Η αρχική βάση δεδομένων χρησιμοποιούσε \textit{latin1} encoding, το οποίο προκάλεσε σφάλματα σε σύγχρονες εκδόσεις MariaDB. + Η λύση που επιλέχθηκε ήταν η ελάχιστη τροποποίηση του αρχείου αρχικοποίησης της βάσης ώστε να χρησιμοποιείται \textit{utf8mb4}, διατηρώντας κατά τα λοιπά το αρχικό schema. + + \item \textbf{Αποθήκευση δεδομένων βάσης}: + Για την αποφυγή δημιουργίας πλήθους αρχείων στον κατάλογο του project, χρησιμοποιήθηκε Docker named volume για το data directory της MariaDB. + Με τον τρόπο αυτό επιτυγχάνεται καθαρή δομή έργου και μόνιμη αποθήκευση δεδομένων. +\end{itemize} + +Οι παραπάνω αλλαγές ήταν απολύτως αναγκαίες για τη σωστή λειτουργία της εφαρμογής σε σύγχρονο περιβάλλον, χωρίς να αλλοιώνουν τη λογική ή τη δομή της αρχικής υλοποίησης. + +\subsection{Δημιουργία και εκτέλεση της εφαρμογής} + +Για την εκτέλεση και δοκιμή της εφαρμογής στο περιβάλλον Docker απαιτείται η ύπαρξη εγκατεστημένου Docker και Docker Compose στο σύστημα. +Αφού ληφθεί ο πηγαίος κώδικας της εφαρμογής από το αποθετήριο, η διαδικασία εκκίνησης είναι πλήρως αυτοματοποιημένη. + +Η δημιουργία των απαραίτητων images και η εκκίνηση των containers πραγματοποιείται με την εντολή: +\begin{minted}[fontsize=\small]{bash} +docker compose up -d --build +\end{minted} + +Με την παραπάνω εντολή δημιουργείται το image του web server (Apache με PHP), εκκινείται η υπηρεσία της βάσης δεδομένων MariaDB και εκτελείται αυτόματα το αρχείο αρχικοποίησης της βάσης δεδομένων. +Τα δεδομένα της βάσης αποθηκεύονται σε Docker named volume, εξασφαλίζοντας τη διατήρησή τους μεταξύ επανεκκινήσεων των containers. + +Μετά την επιτυχή εκκίνηση, η εφαρμογή είναι προσβάσιμη μέσω web browser στη διεύθυνση:\\ +\texttt{http://localhost/passman} + +Για λόγους δοκιμών και ανάλυσης, είναι επίσης δυνατή η απευθείας πρόσβαση στη βάση δεδομένων μέσω τερματικού, χρησιμοποιώντας την εντολή: +\begin{minted}[fontsize=\small]{bash} +docker compose exec db mariadb -uroot -prootpass +\end{minted} + +Μέσω της παραπάνω πρόσβασης είναι δυνατή η εκτέλεση SQL εντολών για την επιβεβαίωση της κατάστασης της βάσης δεδομένων, καθώς και η τεκμηρίωση των επιπτώσεων επιθέσεων και διορθωτικών παρεμβάσεων που παρουσιάζονται στα επόμενα τμήματα της εργασίας. + +\section{SQL Injection} +\label{sec:sqli} + +Το πρώτο κενό ασφάλειας που εξετάζεται αφορά την ευπάθεια σε επιθέσεις SQL Injection. +Η ευπάθεια αυτή προκύπτει όταν δεδομένα που παρέχονται από τον χρήστη ενσωματώνονται απευθείας σε SQL εντολές, χωρίς κατάλληλη επικύρωση ή χρήση μηχανισμών παραμετροποίησης (prepared statements). +Αποτέλεσμα είναι ο επιτιθέμενος να μπορεί να αλλοιώσει τη λογική του SQL query, οδηγώντας σε μη εξουσιοδοτημένη πρόσβαση ή/και διαρροή δεδομένων. + +Στην εφαρμογή, η ευπάθεια εντοπίζεται σε πολλά σημεία και παρότι θα τα λύσουμε όλα εδώ παραθέτουμε ως παράδειγμα την ευπάθεια στο \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. +Επομένως, ένας επιτιθέμενος μπορεί να εισάγει ειδικούς χαρακτήρες (π.χ. \texttt{'}) και SQL τελεστές (π.χ. \texttt{OR}) ώστε να παρακάμψει τη συνθήκη αυθεντικοποίησης. + +\begin{figure}[!ht] + \centering + \begin{subfigure}{.48\textwidth} + \centering + \includegraphics[width=\linewidth]{img/sqli-LoginScreen.png} + \caption{Φόρμα σύνδεσης με εισαγωγή κακόβουλου payload στο πεδίο username.} + \label{fig:sqli_login_screen} + \end{subfigure} + \hfill + \begin{subfigure}{.48\textwidth} + \centering + \includegraphics[width=\linewidth]{img/sqli-LoginProof.png} + \caption{Επιτυχής πρόσβαση στον πίνακα ελέγχου μετά από SQL injection.} + \label{fig:sqli_login_proof} + \end{subfigure} + \caption{SQL Injection.} +\end{figure} + +Στην Εικόνα~\ref{fig:sqli_login_screen} παρουσιάζεται η φόρμα σύνδεσης, στην οποία εισάγεται payload της μορφής +\texttt{u1' OR '1'='1} στο πεδίο username, με αυθαίρετη τιμή στο password. +Με τον τρόπο αυτό, η συνθήκη του \texttt{WHERE} αλλοιώνεται ώστε να επιστρέφει εγγραφές ανεξάρτητα από το πραγματικό password. +Στη συνέχεια, ο χρήστης αποκτά πρόσβαση στον πίνακα ελέγχου (dashboard), όπως φαίνεται στην Εικόνα~\ref{fig:sqli_login_proof}. + +Η επιτυχής εκμετάλλευση της ευπάθειας μπορεί να τεκμηριωθεί και σε επίπεδο βάσης δεδομένων, μέσω του \textit{general\_log} της MariaDB, όπου καταγράφεται το τελικό query που εκτελέστηκε από την εφαρμογή. +\begin{figure}[!ht] + \centering + \includegraphics[width=1.0\textwidth]{img/sqli-DBquery.png} + \caption{Καταγραφή του τελικού SQL query στη MariaDB (\textit{general\_log}), όπου φαίνεται η αλλοίωση της συνθήκης αυθεντικοποίησης από το injected input.} + \label{fig:sqli_db_query} +\end{figure} +Η Εικόνα~\ref{fig:sqli_db_query} δείχνει ότι το query αυθεντικοποίησης πλέον περιέχει την πρόσθετη συνθήκη \texttt{OR '1'='1'}, +με αποτέλεσμα η αυθεντικοποίηση να μπορεί να παρακαμφθεί. + +Τέλος, στην Εικόνα~\ref{fig:sqli_db_users} παρουσιάζονται τα περιεχόμενα του πίνακα \texttt{login\_users}, επιβεβαιώνοντας ότι +η πρόσβαση αποκτήθηκε χωρίς να τροποποιηθούν τα δεδομένα της βάσης (δηλαδή πρόκειται για bypass του μηχανισμού αυθεντικοποίησης και όχι για αλλαγή/εισαγωγή δεδομένων). + +\begin{figure}[!ht] + \centering + \includegraphics[width=0.70\textwidth]{img/sqli-DBusers.png} + \caption{Περιεχόμενα του πίνακα \texttt{login\_users} στη βάση δεδομένων (επιβεβαίωση ότι τα credentials παραμένουν αμετάβλητα).} + \label{fig:sqli_db_users} +\end{figure} + +Η συγκεκριμένη ευπάθεια θεωρείται ιδιαίτερα σοβαρή, καθώς υπονομεύει πλήρως τον μηχανισμό αυθεντικοποίησης και επιτρέπει μη εξουσιοδοτημένη πρόσβαση σε ευαίσθητα δεδομένα. +Στα επόμενα τμήματα παρουσιάζεται η αντιμετώπισή της με χρήση prepared statements, ώστε τα δεδομένα του χρήστη να μην μπορούν να επηρεάσουν τη σύνταξη της SQL εντολής. + +\subsection{Αντιμετώπιση SQL Injection} +\label{sec:sqli_fix} + +Η αντιμετώπιση του SQL Injection βασίζεται στη θεμελιώδη αρχή του διαχωρισμού \textit{δεδομένων} από \textit{εντολές}. +Το πρόβλημα στην αρχική υλοποίηση προέκυπτε επειδή το SQL query κατασκευαζόταν μέσω απλής συνένωσης (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 σύνταξης. +Ως αποτέλεσμα, οποιαδήποτε κακόβουλη είσοδος αντιμετωπίζεται ως απλό κείμενο (data) και όχι ως εκτελέσιμο SQL. + +\subsection{Υλοποίηση της διόρθωσης} +Στο αρχείο \textit{login.php} αντικαταστάθηκε η δυναμική δημιουργία του SQL query με prepared statement και bind παραμέτρων. +Στο Απόσπασμα~\ref{lst:sqli-fix-login} παρουσιάζεται ο διορθωμένος κώδικας. +Η SQL εντολή ορίζεται με placeholders (\texttt{?}) και οι τιμές \textit{\$username} και \textit{\$password} περνούν μέσω \textit{bind\_param()}, ώστε να μην μπορούν να επηρεάσουν τη δομή της εντολής. + +\begin{minted}{php} + // SQL injection mitigation: use a prepared statement with bound parameters. + // User input is treated strictly as data, not as part of the SQL syntax. + $stmt = $conn->prepare("SELECT id FROM login_users WHERE username = ? AND password = ?"); + if ($stmt === false) { + die("Prepare failed."); + } + $stmt->bind_param("ss", $username, $password); + $stmt->execute(); + $stmt->store_result(); + // Authentication succeeds only if exactly one row matches. + if ($stmt->num_rows >= 1) { + $_SESSION['loggedin'] = true; + $_SESSION['username'] = $username; + + $stmt->close(); + $conn->close(); + // ... + } +\end{minted} +\label{lst:sqli-fix-login} + +\subsection{Επαλήθευση της διόρθωσης} +Η αποτελεσματικότητα της διόρθωσης επιβεβαιώθηκε πειραματικά με το ίδιο payload που χρησιμοποιήθηκε στην επίδειξη της ευπάθειας. +Στην Εικόνα~\ref{fig:sqli_fix_login_screen} φαίνεται η προσπάθεια σύνδεσης με το injection string στο πεδίο username. +Η εφαρμογή πλέον απορρίπτει την προσπάθεια σύνδεσης και εμφανίζει μήνυμα αποτυχίας, όπως φαίνεται στην Εικόνα~\ref{fig:sqli_fix_login_proof}. + +\begin{figure}[!ht] + \centering + \begin{subfigure}{.48\textwidth} + \centering + \includegraphics[width=\linewidth]{img/sqli-LoginScreenFix.png} + \caption{Δοκιμή του ίδιου SQLi payload μετά τη διόρθωση.} + \label{fig:sqli_fix_login_screen} + \end{subfigure}% + \hfill + \begin{subfigure}{.48\textwidth} + \centering + \includegraphics[width=\linewidth]{img/sqli-LoginProofFix.png} + \caption{Αποτυχία σύνδεσης μετά τη διόρθωση.} + \label{fig:sqli_fix_login_proof} + \end{subfigure}% + \caption{SQL Injection: Fixed.} +\end{figure} + +Περαιτέρω επιβεβαίωση παρέχεται από τα logs της βάσης (general log), όπου φαίνεται ότι η εντολή εκτελείται ως παραμετροποιημένο statement με placeholders και όχι ως query που περιέχει ενσωματωμένο το injected payload. +Στην Εικόνα~\ref{fig:sqli_fix_db_query} παρατηρείται η παρουσία της μορφής \texttt{username = ? AND password = ?}, γεγονός που υποδηλώνει ότι ο server λαμβάνει το statement ανεξάρτητα από τα δεδομένα εισόδου. + +\begin{figure}[!ht] + \centering + \includegraphics[width=1.0\textwidth]{img/sqli-DBqueryFix.png} + \caption{Καταγραφή στη MariaDB μετά τη διόρθωση: εκτέλεση παραμετροποιημένου statement (\texttt{?}) αντί για δυναμικά κατασκευασμένο query.} + \label{fig:sqli_fix_db_query} +\end{figure} + +Συνεπώς, η χρήση prepared statements εξαλείφει το συγκεκριμένο κενό ασφάλειας στο σημείο αυθεντικοποίησης, διατηρώντας παράλληλα αμετάβλητη τη λειτουργικότητα της εφαρμογής. + + +\subsection{Περαιτέρω σημεία ευπάθειας σε SQL Injection} + +Πέρα από το αρχικό κενό ασφάλειας στον μηχανισμό αυθεντικοποίησης, εντοπίστηκαν επιπλέον σημεία στην εφαρμογή όπου 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}');"; + $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}')"; + $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}');"; + $result = $conn->query($sql_query); +\end{minted} +\label{lst:sqli-dashboard-insert} + +Αντίστοιχα, η διαγραφή εγγραφών βασιζόταν σε δυναμικά κατασκευασμένη εντολή \texttt{DELETE}, όπως φαίνεται στο Απόσπασμα~\ref{lst:sqli-dashboard-delete}. + +\begin{minted}{php} + // Vulnerable DELETE statement: identifier injected directly into SQL. + $sql_query = "DELETE FROM websites WHERE webid='{$webid}';"; + $result = $conn->query($sql_query); +\end{minted} +\label{lst:sqli-dashboard-delete} + +Τέλος, ακόμη και η προβολή της λίστας διαπιστευτηρίων βασιζόταν σε SQL εντολή με απευθείας ενσωμάτωση session μεταβλητών. +\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}';"; + $result = $conn->query($sql_query); +\end{minted} +\label{lst:sqli-dashboard-select} + +Η συνολική αντιμετώπιση των παραπάνω σημείων βασίστηκε στην ίδια αρχή με το αρχικό SQL Injection, ότι καμία τιμή που επηρεάζει τη σύνταξη SQL εντολής δεν ενσωματώνεται πλέον απευθείας στο query. +Όλα τα παραπάνω αντικαταστάθηκαν με prepared statements και δεσμευμένες παραμέτρους, εξαλείφοντας τόσο άμεσα όσο και έμμεσα σενάρια SQL Injection. +Ο αναγνώστης μπορεί \href{\fixsqlitag}{εδώ} να βρει το branch με όλες τις αλλαγές. + + +% ===================================================================== +% Stored XSS +% ===================================================================== + +\section{Stored XSS} +\label{sec:xss_notes} + +Η συγκεκριμένη εφαρμογή είναι ευάλωτη σε \textit{Stored Cross-Site Scripting (Stored XSS)} σε αρκετά σημεία. +Όπως και πριν, αρχικά θα επικεντρωθούμε σε ένα και πιο συγκεκριμένα σε αυτό μέσω της λειτουργίας σημειώσεων (\textit{notes}), ώστε να παρουσιάσουμε το πρόβλημα και τη τεχνική αντιμετώπισης, και έπειτα θα αναφέρουμε και τα υπόλοιπα σημεία. + +Η ευπάθεια προκύπτει όταν περιεχόμενο που εισάγει ο χρήστης αποθηκεύεται στη βάση δεδομένων και στη συνέχεια προβάλλεται -- πιθανόν σε άλλους χρήστες -- χωρίς κατάλληλη κωδικοποίηση εξόδου (output encoding). +Ως αποτέλεσμα, κακόβουλος κώδικας JavaScript μπορεί να εκτελεστεί στον browser του θύματος με τα δικαιώματα του αντίστοιχου session. + +\subsection{Root cause στον κώδικα} +Στο \textit{notes.php}, οι αποθηκευμένες σημειώσεις προβάλλονται απευθείας μέσα σε HTML με χρήση \texttt{echo}, χωρίς escaping. +Ενδεικτικά, το Απόσπασμα~\ref{lst:xss-notes-echo} δείχνει το προβληματικό σημείο: το \texttt{\$row["note"]} (δεδομένο από τη βάση) θεωρείται ως έμπιστο και εισάγεται αυτούσιο στο DOM. + +\begin{minted}{php} + while ($row = $result -> fetch_assoc()) { + echo "
"; + echo "
" . $row["note"] . "
"; + echo "
by " . $row["username"] . "
"; + // ... +\end{minted} +\label{lst:xss-notes-echo} + +\subsection{Attacker-side υποδομή} +Για την τεκμηρίωση της επίθεσης, χρησιμοποιήθηκε ο υποκατάλογος \textit{xss/} ως ``attacker side''. +Το \textit{getcookie.php} δέχεται μία τιμή μέσω παραμέτρου \texttt{v} και την αποθηκεύει στο \textit{stolencookies.txt}. +Στη συνέχεια, το \textit{listcookies.php} εμφανίζει τα ``κλεμμένα'' cookies, ενώ το \textit{usecookie.php} επιτρέπει την επαναχρησιμοποίησή τους (session hijacking demonstration). + +\subsection{Σενάριο A: Stored XSS με άμεση εξαγωγή cookie} +\label{sec:xss_scn_a} + +Στο πρώτο σενάριο εισήχθη σημείωση που περιείχε JavaScript payload, το οποίο αποστέλλει το document.cookie στον attacker-side logger, όπως φαίνεται παρακάτω: +\begin{verbatim} + +\end{verbatim} + +Στην Εικόνα~\ref{fig:xss_scn_a_listcookies} εμφανίζεται το αποθηκευμένο session cookie (\texttt{PHPSESSID}) στη λίστα κλεμμένων cookies. +\begin{figure}[!ht] + \centering + \includegraphics[width=0.55\textwidth]{img/xss-ScA-ListCookie.png} + \caption{Σενάριο A: Εμφάνιση του ``κλεμμένου'' session cookie (\texttt{PHPSESSID}) μέσω \textit{listcookies.php}.} + \label{fig:xss_scn_a_listcookies} +\end{figure} + + +Κατά την προβολή της σελίδας, ο browser εκτελεί το payload και πραγματοποιεί HTTP request προς \textit{getcookie.php}, όπως τεκμηριώνεται στα logs του web server (Εικόνα~\ref{fig:xss_scn_a_weblogs}). +\begin{figure}[!ht] + \centering + \includegraphics[width=\textwidth]{img/xss-ScA-WebLogs.png} + \caption{Σενάριο A: Καταγραφή στο web server που δείχνει HTTP request προς \textit{/passman/xss/getcookie.php} με παράμετρο \texttt{v=PHPSESSID=...}.} + \label{fig:xss_scn_a_weblogs} +\end{figure} + +\subsection{Σενάριο B: Παραλλαγή payload με obfuscation} +\label{sec:xss_scn_b} + +Στο δεύτερο σενάριο χρησιμοποιήθηκε παραλλαγή payload που επιτυγχάνει την ίδια λειτουργία (εξαγωγή cookie) αλλά με διαφορετική μορφή (obfuscation), ώστε να καταδειχθεί ότι το πρόβλημα δεν περιορίζεται σε ένα συγκεκριμένο ``μοτίβο'' εισαγωγής. +Η σημείωση που χρησιμοποιήθηκες είναι: +\begin{verbatim} + +\end{verbatim} + +Στην Εικόνα~\ref{fig:xss_scn_b_listcookies} φαίνεται ότι το cookie αποθηκεύεται επιτυχώς και σε αυτήν την περίπτωση. + +\begin{figure}[!ht] + \centering + \includegraphics[width=0.55\textwidth]{img/xss-ScB-ListCookie.png} + \caption{Σενάριο B: Καταγραφή session cookie στη λίστα κλεμμένων cookies.} + \label{fig:xss_scn_b_listcookies} +\end{figure} + +Στα logs (Εικόνα~\ref{fig:xss_scn_b_weblogs}) παρατηρείται και πάλι request προς \textit{getcookie.php}. +\begin{figure}[!ht] + \centering + \includegraphics[width=\textwidth]{img/xss-ScB-WebLogs.png} + \caption{Σενάριο B: Καταγραφή στο web server που δείχνει την επιτυχή κλήση του \textit{getcookie.php} από το payload.} + \label{fig:xss_scn_b_weblogs} +\end{figure} + +\paragraph{Επιβεβαίωση αποθήκευσης payload στη βάση} +Επειδή πρόκειται για \textit{stored} XSS, το payload αποθηκεύεται στη βάση δεδομένων και εκτελείται κάθε φορά που προβάλλεται η σελίδα. +Στην Εικόνα~\ref{fig:xss_db_entries} φαίνεται ότι οι κακόβουλες σημειώσεις αποθηκεύτηκαν στον πίνακα \texttt{notes}. + +\begin{figure}[!ht] + \centering + \includegraphics[width=0.92\textwidth]{img/xss-ScX-MySQLEntries.png} + \caption{Καταγραφή στη βάση: αποθηκευμένες σημειώσεις που περιέχουν τα XSS payloads (persistent storage).} + \label{fig:xss_db_entries} +\end{figure} + +\subsubsection{Session hijacking demonstration μέσω \textit{usecookie.php}} +\label{sec:xss_hijack} + +Ο αντίκτυπος της ευπάθειας είναι ιδιαίτερα σοβαρός, καθώς το session cookie μπορεί να χρησιμοποιηθεί για πλαστοπροσωπία (session hijacking). +Στην Εικόνα~\ref{fig:xss_usecookie} φαίνεται η χρήση του \textit{usecookie.php} με παράμετρο το κλεμμένο \texttt{PHPSESSID}. +Στη συνέχεια, η πρόσβαση σε προστατευμένη σελίδα της εφαρμογής (π.χ. \textit{dashboard.php}) είναι εφικτή ως ο χρήστης-θύμα, όπως φαίνεται στην Εικόνα~\ref{fig:xss_dashboard_after_hijack}. + +\begin{figure}[!ht] + \begin{subfigure}{.48\textwidth} + \centering + \includegraphics[width=\linewidth]{img/xss-ScX-UseCookie.png} + \caption{Επαναχρησιμοποίηση του κλεμμένου \texttt{PHPSESSID} μέσω \textit{usecookie.php}.} + \label{fig:xss_usecookie} + \end{subfigure} + \hfill + \begin{subfigure}{.48\textwidth} + \centering + \includegraphics[width=\linewidth]{img/xss-SxX-StolenSession.png} + \caption{Πρόσβαση στο \textit{dashboard.php} μετά την επαναχρησιμοποίηση του session cookie.} + \label{fig:xss_dashboard_after_hijack} + \end{subfigure} + \caption{Session hijacking demonstration.} +\end{figure} + +Με βάση τα παραπάνω, επιβεβαιώνεται ότι η εφαρμογή επιτρέπει αποθήκευση και εκτέλεση κακόβουλου JS κώδικα μέσω του μηχανισμού σημειώσεων, με αποτέλεσμα τόσο την εξαγωγή cookies όσο και την πρακτική επίδειξη πλαστοπροσωπίας. +Στα επόμενα τμήματα παρουσιάζεται η αντιμετώπιση της ευπάθειας με \textit{context-aware output encoding}, ώστε το περιεχόμενο της βάσης να αντιμετωπίζεται ως μη-έμπιστο και να προβάλλεται με ασφάλεια. + + +\subsection{Αντιμετώπιση Stored XSS στο \textit{notes.php}} +\label{sec:xss_fix} + +Η αντιμετώπιση του Stored XSS βασίζεται στην αρχή ότι \textit{οποιοδήποτε περιεχόμενο προέρχεται από τον χρήστη ή/και τη βάση δεδομένων πρέπει να θεωρείται μη-έμπιστο}. +Στην αρχική υλοποίηση, το περιεχόμενο των σημειώσεων εμφανιζόταν απευθείας στο HTML, με αποτέλεσμα ο browser να το ερμηνεύει ως markup και να εκτελεί τυχόν ενσωματωμένο JavaScript. +Η καθιερωμένη πρακτική για την αποτροπή XSS σε \textit{HTML body context} είναι το \textit{context-aware output encoding}, δηλαδή η κωδικοποίηση ειδικών χαρακτήρων (π.χ. \texttt{<}, \texttt{>}, \texttt{"}, \texttt{'}) πριν από την προβολή τους. +Με αυτόν τον τρόπο, ακόμη και αν στη βάση υπάρχουν αποθηκευμένα payloads, αυτά προβάλλονται ως απλό κείμενο και δεν είναι δυνατόν να εκτελεστούν. + +\subsubsection{Υλοποίηση της διόρθωσης} +Η διόρθωση πραγματοποιήθηκε με ελάχιστη αλλαγή στο \textit{notes.php}, στο σημείο προβολής των σημειώσεων. +Συγκεκριμένα, πριν την εκτύπωση του περιεχομένου, εφαρμόστηκε \texttt{htmlspecialchars()} με επιλογές \texttt{ENT\_QUOTES} και \texttt{UTF-8}, έτσι ώστε να γίνεται ασφαλής απόδοση των δεδομένων στο HTML. +Το Απόσπασμα παρακάτω παρουσιάζει τον διορθωμένο κώδικα: +\begin{minted}{php} + // Escape output to prevent stored XSS (DB content must be treated as untrusted). + $safe_note = htmlspecialchars($row["note"], ENT_QUOTES | ENT_SUBSTITUTE, "UTF-8"); + $safe_user = htmlspecialchars($row["username"], ENT_QUOTES | ENT_SUBSTITUTE, "UTF-8"); + + echo "
" . $safe_note . "
"; + echo "
by " . $safe_user . "
"; +\end{minted} + +\subsubsection{Επαλήθευση της διόρθωσης} +Μετά την εφαρμογή του output encoding, τα ήδη αποθηκευμένα payloads στη βάση δεν απαιτείται να διαγραφούν. +Αντίθετα, προβάλλονται ως απλό κείμενο, όπως φαίνεται στην Εικόνα~\ref{fig:xss_fix_notes_plaintext}, όπου οι συμβολοσειρές \texttt{} εμφανίζονται χωρίς να εκτελούνται. + +\begin{figure}[!ht] + \centering + \includegraphics[width=0.4\textwidth]{img/xss-SxX-NotesSubmitedFix2.png} + \caption{Μετά τη διόρθωση: τα XSS payloads εμφανίζονται ως απλό κείμενο (δεν εκτελείται JavaScript).} + \label{fig:xss_fix_notes_plaintext} +\end{figure} + +Επιπλέον, η απουσία εκτέλεσης επιβεβαιώνεται και από τα logs του web server: +ενώ καταγράφονται αιτήματα προς \textit{notes.php}, δεν καταγράφονται πλέον αιτήματα προς \textit{/passman/xss/getcookie.php} (δηλαδή δεν πραγματοποιείται cookie exfiltration), όπως φαίνεται στην Εικόνα~\ref{fig:xss_fix_weblogs}. + +\begin{figure}[!ht] + \centering + \includegraphics[width=\textwidth]{img/xss-SxX-WebLogsFix.png} + \caption{Μετά τη διόρθωση: καταγράφονται μόνο αιτήματα προς \textit{notes.php} και απουσιάζουν τα αιτήματα προς \textit{/passman/xss/getcookie.php}.} + \label{fig:xss_fix_weblogs} +\end{figure} + +Συνεπώς, η εφαρμογή \textit{context-aware output encoding} στο σημείο προβολής εξαλείφει την εκτέλεση αποθηκευμένων XSS payloads στο συγκεκριμένο context, διατηρώντας αμετάβλητη τη λειτουργικότητα της εφαρμογής. + +\subsection{Επέκταση της αντιμετώπισης XSS στα επιπλέον σημεία} + +Η ευπάθεια Stored XSS που παρουσιάστηκε μέσω της λειτουργίας σημειώσεων δεν αποτελεί μεμονωμένο περιστατικό, αλλά ενδεικτικό ενός γενικότερου προγραμματιστικού μοτίβου στην εφαρμογή. +Δεδομένα προερχόμενα από χρήστες ή από τη βάση δεδομένων προβάλλονταν απευθείας στο HTML χωρίς κατάλληλη κωδικοποίηση εξόδου. +Για τον λόγο αυτό πραγματοποιήθηκε εκτενέστερη ανάλυση και εντοπίστηκαν επιπλέον σημεία με δυνητική ή άμεση ευπάθεια σε XSS. + +\subsubsection{Εμφάνιση διαπιστευτηρίων ιστοσελίδων (\textit{dashboard.php})} +Στο \textit{dashboard.php}, τα πεδία \textit{web\_url}, \textit{web\_username} και \textit{web\_password} προέρχονται από δεδομένα που εισάγονται από τον χρήστη, αποθηκεύονται στη βάση δεδομένων και στη συνέχεια εμφανίζονται στη διεπαφή. +Στην αρχική υλοποίηση, τα δεδομένα αυτά προβάλλονταν απευθείας, όπως φαίνεται εδώ: +\begin{minted}{php} + // Vulnerable output: database-backed user input rendered without escaping. + echo "" . $row["web_url"] . ""; + echo "" . $row["web_username"] . ""; + echo "" . $row["web_password"] . ""; +\end{minted} + +Η πρακτική αυτή επιτρέπει την αποθήκευση και εκτέλεση κακόβουλου HTML ή JavaScript κώδικα (\textit{Stored XSS}), με εκτέλεση του payload κάθε φορά που προβάλλεται η σελίδα. +Η αντιμετώπιση πραγματοποιήθηκε με εφαρμογή \textit{context-aware output encoding} σε όλα τα αντίστοιχα πεδία. + +\subsubsection{Εμφάνιση ονόματος χρήστη από session (\textit{dashboard.php})} +Στην ίδια σελίδα, το όνομα του συνδεδεμένου χρήστη εμφανιζόταν στο header της σελίδας. +Η τιμή αυτή προέρχεται από session μεταβλητή και στην αρχική υλοποίηση εμφανιζόταν χωρίς κωδικοποίηση εξόδου, όπως φαίνεται εδώ: +\begin{minted}{php} + // Vulnerable output: session-derived value treated as trusted. + echo "

Entries of " . $username . "

"; +\end{minted} + + +Παρότι τα session δεδομένα συχνά θεωρούνται έμπιστα, στην πράξη μπορούν να αλλοιωθούν σε σενάρια XSS, session hijacking ή cookie tampering. +Η συγκεκριμένη περίπτωση αποτελεί χαρακτηριστικό παράδειγμα \textit{second-order XSS}. +Η αντιμετώπιση βασίστηκε στην κωδικοποίηση της τιμής πριν την εμφάνιση της. + +\subsubsection{Reflected XSS σε μηνύματα σφάλματος (\textit{login.php}, \textit{register.php})} +Κατά την ανάλυση εξετάστηκε και η περίπτωση εμφάνισης μηνυμάτων σφάλματος προς τον χρήστη. +Στα αρχεία \textit{login.php} και \textit{register.php} τα μηνύματα αυτά εμφανίζονται με χρήση μεταβλητής, όπως παρακάτω: +\begin{minted}{php} + // Display login or registration status message. + echo "

" . $login_message . "

"; +\end{minted} + + +Στην παρούσα υλοποίηση, οι μεταβλητές αυτές λαμβάνουν μόνο στατικές συμβολοσειρές και δεν ενσωματώνουν δεδομένα εισόδου χρήστη. +Ως εκ τούτου, δεν είναι πρακτικά εκμεταλλεύσιμες για Reflected XSS στην τρέχουσα μορφή της εφαρμογής. +Για τον λόγο αυτό, δεν πραγματοποιήθηκε περαιτέρω εκμετάλλευση, αλλά το σημείο καταγράφεται ως θεωρητικό σενάριο που θα απαιτούσε αντιμετώπιση σε μελλοντική επέκταση της εφαρμογής. +Ο αναγνώστης μπορεί \href{\fixxsstag}{εδώ} να βρει το branch με όλες τις αλλαγές. + + +% ===================================================================== +% Plaintext authentication credentials (login passwords) + mitigation +% ===================================================================== + +\section{Αποθήκευση κωδικών αυθεντικοποίησης σε απλό κείμενο} +\label{subsec:plaintext-auth} + +Η εφαρμογή, στην αρχική της υλοποίηση, διαχειριζόταν τους κωδικούς αυθεντικοποίησης των χρηστών (login passwords) ως απλό κείμενο (plaintext). +Το πρόβλημα αυτό εμφανίζεται σε περισσότερα του ενός σημεία της εφαρμογής: + +\begin{enumerate} + \item \textbf{Πίνακας βάσης δεδομένων \texttt{login\_users}:} + Οι κωδικοί πρόσβασης αποθηκεύονταν αυτούσιοι στη βάση δεδομένων, γεγονός που μπορεί να επιβεβαιωθεί με απευθείας ερώτημα SQL. + + \item \textbf{Διαδικασία εγγραφής χρήστη (\texttt{register.php}):} + Ο κωδικός που εισάγεται από τον χρήστη αποθηκευόταν στη βάση χωρίς καμία μορφή μετασχηματισμού (hashing). + + \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_query = "SELECT * FROM login_users WHERE username='{$username}' + AND password='{$password}';"; + $result = $conn->query($sql_query); + + if (!empty($result) && $result->num_rows >= 1) { + $_SESSION['username'] = $username; + $_SESSION['loggedin'] = true; + // ... + } +\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} + +Η αποθήκευση του κωδικού σε απλό κείμενο είναι άμεσα ορατή και στο περιεχόμενο +της βάσης δεδομένων, όπως φαίνεται στο αντίστοιχο στιγμιότυπο οθόνης. +\begin{figure}[!ht] + \centering + \includegraphics[width=0.7\textwidth]{img/pltxt-VulnLogins.png} + \caption{Κωδικοί χρηστών σε απλό κείμενο.} + \label{fig:pltxt_vuln_logins} +\end{figure} + +\subsection{Προσέγγιση αντιμετώπισης} +Για την ασφαλή διαχείριση κωδικών αυθεντικοποίησης, οι κωδικοί δεν πρέπει ποτέ να αποθηκεύονται σε απλό κείμενο. +Η καθιερωμένη πρακτική είναι: + +\begin{itemize} + \item χρήση συναρτήσεων hashing με ενσωματωμένο salt κατά την εγγραφή, + \item επαλήθευση του κωδικού κατά τη σύνδεση μέσω σύγκρισης hash και όχι μέσω SQL. +\end{itemize} + +Στην παρούσα εργασία χρησιμοποιούνται οι συναρτήσεις \texttt{password\_hash()} και \texttt{password\_verify()} της PHP, οι οποίες θεωρούνται βέλτιστη πρακτική για την αποθήκευση κωδικών. + + +\subsection{Διορθωμένη υλοποίηση} + +Στη διορθωμένη υλοποίηση οι κωδικοί πλέον δεν εισάγονται στη βάση αυτούσιοι, αλλά περνούν πρώτα από: +\begin{minted}{php} + $password_hash = password_hash($new_password, PASSWORD_DEFAULT); +\end{minted} + +Ομοίως κατά το login, η επαλήθευση γίνεται με την: +\begin{minted}{php} + password_verify($password, $stored_hash); +\end{minted} + +\subsection{Απαιτούμενες αλλαγές περιβάλλοντος και βάσης δεδομένων} +Μετά την αλλαγή του μηχανισμού αυθεντικοποίησης, οι ήδη αποθηκευμένοι plaintext κωδικοί πρέπει να αντικατασταθούν από hashes. +Για τον προ-εγκατεστημένο χρήστη δοκιμών (\texttt{u1/p1}), η διαδικασία πραγματοποιήθηκε χειροκίνητα στο περιβάλλον Docker, ως εξής: + +Αρχικά δημιουργήσαμε ένα hashed κωδικό για τον υπάρχον χρήστη: +\begin{verbatim} + $ 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} + +Έπειτα αλλάξαμε των κωδικό χειροκίνητα στη βάση: +\begin{verbatim} + MariaDB [pwd_mgr]> SELECT * FROM login_users; + +----+----------+----------+ + | id | username | password | + +----+----------+----------+ + | 1 | u1 | p1 | + +----+----------+----------+ + + MariaDB [pwd_mgr]> UPDATE login_users + > SET password = '$2y$10$L18u5/PyVkDgsce/DsUOQu0sKhTzh854Euhog3cVb1W4YAfgRzY8W' + > WHERE username='u1'; + + MariaDB [pwd_mgr]> SELECT * FROM login_users; + +----+----------+--------------------------------------------------------------+ + | id | username | password | + +----+----------+--------------------------------------------------------------+ + | 1 | u1 | $2y$10$L18u5/PyVkDgsce/DsUOQu0sKhTzh854Euhog3cVb1W4YAfgRzY8W | + +----+----------+--------------------------------------------------------------+ +\end{verbatim} + +Η παραπάνω διαδικασία επιβεβαιώνει την επιτυχή αντικατάσταση του plaintext κωδικού με ασφαλές hash, διασφαλίζοντας τη συμβατότητα της βάσης δεδομένων με τη νέα υλοποίηση αυθεντικοποίησης. + +Τέλος ενημερώσαμε τον ίδιο κωδικό και στο αρχείο αρχικοποίησης της βάσης στον container. + +\begin{figure}[H] + \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 +% ===================================================================== + +\section{Χρήση διαπιστευτηρίων διαχειριστή (root)} +\label{subsec:db-root-user} + +Ένα επιπλέον σημαντικό πρόβλημα ασφάλειας της εφαρμογής είναι ότι η σύνδεση προς τη βάση δεδομένων +πραγματοποιείται με διαπιστευτήρια διαχειριστή (\textit{administrator credentials}, χρήστης \texttt{root}). +Η πρακτική αυτή παραβιάζει τη θεμελιώδη αρχή του \textit{least privilege} (ελάχιστα απαραίτητα προνόμια), +διότι οποιοσδήποτε επιτιθέμενος αποκτήσει δυνατότητα εκτέλεσης SQL εντολών (π.χ. μέσω SQL injection ή +μέσω πρόσβασης στη βάση) δεν περιορίζεται από δικαιώματα και μπορεί να πραγματοποιήσει καταστροφικές +ενέργειες. + +Το πρόβλημα εντοπίζεται στα ακόλουθα σημεία. +\begin{itemize} + \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} + \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} + \label{lst:compose-web-root} + + \item SQL init (δεν υπάρχει dedicated χρήστης εφαρμογής). + Στο αρχείο αρχικοποίησης \textit{01-create-pwd\_mgr-db-withData.sql} δημιουργούνται tables και demo δεδομένα, + όμως δεν δημιουργείται ξεχωριστός χρήστης βάσης δεδομένων με περιορισμένα δικαιώματα (least privilege). +\end{itemize} + +\subsection{Επιπτώσεις ασφάλειας} +Η χρήση διαπιστευτηρίων διαχειριστή σημαίνει ότι σε περίπτωση παραβίασης: +\begin{itemize} + \item είναι δυνατή η \textbf{πλήρης ανάγνωση} όλων των δεδομένων (π.χ. users, notes, websites), + \item είναι δυνατές \textbf{καταστροφικές ενέργειες} (\texttt{DROP}, \texttt{TRUNCATE}, μαζικά \texttt{DELETE}), + \item είναι πιθανή \textbf{μόνιμη παραβίαση} (π.χ. αλλαγές σε grants/χρήστες), ανάλογα με τη ρύθμιση του DB server. +\end{itemize} + +Με άλλα λόγια, ακόμη και αν διορθωθούν SQLi σε επίπεδο κώδικα, η χρήση root αυξάνει σημαντικά το \textit{impact} +(impact amplification) οποιασδήποτε επιτυχούς επίθεσης. + +\subsection{Αντιμετώπιση: least privilege χρήστης βάσης δεδομένων} + +Η αντιμετώπιση βασίζεται στη δημιουργία ενός dedicated χρήστη εφαρμογής (π.χ. \texttt{passman\_app}), +στον οποίο εκχωρούνται μόνο τα απολύτως απαραίτητα δικαιώματα στο schema \texttt{pwd\_mgr}. + +\begin{itemize} + \item Αλλαγή στο 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). + -- Grant only the required privileges on the application database. + CREATE USER IF NOT EXISTS 'passman_app'@'%' IDENTIFIED BY 'passman_app_pw'; + GRANT SELECT, INSERT, UPDATE, DELETE ON pwd_mgr.* TO 'passman_app'@'%'; + FLUSH PRIVILEGES; +\end{minted} + \label{lst:db-create-app-user} + Με αυτόν τον τρόπο, η εφαρμογή μπορεί να λειτουργήσει κανονικά, + ενώ παράλληλα δεν επιτρέπονται επικίνδυνα δικαιώματα όπως \texttt{DROP}, \texttt{ALTER}, \texttt{CREATE USER}, \texttt{GRANT OPTION}. + + \item Αλλαγή στο docker-compose.yml: web συνδέεται ως passman\_app. + Στη συνέχεια, στο \textit{docker-compose.yml} αλλάχθηκαν τα credentials της web υπηρεσίας ώστε να χρησιμοποιείται ο νέος χρήστης: + \begin{minted}{yaml} + services: + web: + environment: + DB_HOST: db + DB_USER: passman_app + DB_PASS: passman_app_pw + DB_NAME: pwd_mgr + \end{minted} + \label{lst:compose-web-appuser} + + Ο χρήστης \texttt{root} παραμένει διαθέσιμος μόνο για διαχειριστικές εργασίες στο DB container (\textit{administration}), αλλά η εφαρμογή δεν τον χρησιμοποιεί πλέον. + + \item Αλλαγή στο config.php: ασφαλέστερα defaults / αποφυγή fallback σε root. + Τέλος, στο \textit{config.php} αφαιρέθηκε το επικίνδυνο fallback σε root. + Υπάρχουν δύο ασφαλείς επιλογές: + \begin{itemize} + \item \textbf{Επιλογή 1 (fail closed):} αν λείπουν env vars, η εφαρμογή σταματάει με μήνυμα σφάλματος. + \item \textbf{Επιλογή 2 (safe defaults):} fallback σε \texttt{passman\_app} αντί για \texttt{root}. + \end{itemize} + + Στην παρούσα εργασία ακολουθήθηκε η \textit{safe defaults} επιλογή: + \begin{minted}{php} + $DB_HOST = getenv('DB_HOST') ?: 'db'; + $DB_USER = getenv('DB_USER') ?: 'passman_app'; + $DB_PASS = getenv('DB_PASS') ?: 'passman_app_pw'; + $DB_NAME = getenv('DB_NAME') ?: 'pwd_mgr'; + \end{minted} + \label{lst:db-config-fixed} +\end{itemize} + +Με τις παραπάνω αλλαγές, η εφαρμογή λειτουργεί με περιορισμένα δικαιώματα στη βάση δεδομένων, +μειώνοντας σημαντικά τον αντίκτυπο (impact reduction) πιθανών επιθέσεων. +Η πρακτική αυτή αποτελεί βασικό μέτρο \textit{defense-in-depth} και ευθυγραμμίζεται με θεμελιώδεις αρχές secure design. + +Ένα παράδειγμα φαίνεται και στο στιγμιότυπο παρακάτω, όπου η βάση απορρίπτει τη διαγραφή πίνακα, στον χρήστη passman\_app: +\begin{minted}{sql} +-- $ docker compose exec db mariadb -upassman_app -ppassman_app_pw +Welcome to the MariaDB monitor. Commands end with ; or \g. +Your MariaDB connection id is 5 +Server version: 11.8.5-MariaDB-ubu2404 mariadb.org binary distribution + +Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. + +Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. + +MariaDB [(none)]> DROP TABLE pwd_mgr.login_users; +ERROR 1142 (42000): DROP command denied to user 'passman_app'@'localhost' for +table `pwd_mgr`.`login_users` +MariaDB [(none)]> +\end{minted} + + +% ===================================================================== +% HTTP -> HTTPS (Transport security) + mitigation +% ===================================================================== + +\section{Χρήση HTTP αντί HTTPS} +\label{subsec:http-https} + +Η εφαρμογή αρχικά λειτουργεί αποκλειστικά μέσω του μη ασφαλούς πρωτοκόλλου HTTP. +Όπως αναφέρεται και στην εκφώνηση, η χρήση HTTP επιτρέπει σε έναν επιτιθέμενο που παρακολουθεί την κίνηση του δικτύου (\textit{network observer / man-in-the-middle}) να υποκλέψει τις πληροφορίες που εμφανίζονται στον χρήστη και τα δεδομένα που αυτός αποστέλλει (π.χ. username/password στα forms). + +Σε πραγματικό περιβάλλον, αυτό σημαίνει ότι: +\begin{itemize} + \item τα credentials μπορούν να διαρρεύσουν σε plaintext, + \item το session cookie μπορεί να υποκλαπεί, + \item το περιεχόμενο σελίδων (π.χ. αποθηκευμένοι κωδικοί ιστοσελίδων) μπορεί να αναγνωστεί από τρίτους. +\end{itemize} + +\subsection{Πού εμφανίζεται στην υλοποίηση} +Στο Docker Compose, η web υπηρεσία εκθέτει προς τα έξω μόνο την πόρτα 80 (HTTP), χωρίς καμία μορφή TLS. + +\begin{minted}{yaml} + services: + web: + build: . + ports: + - "80:80" +\end{minted} +\label{lst:http-compose-before} + +Επιπλέον, στο \textit{index.html} υπάρχουν hard-coded σύνδεσμοι προς \texttt{http://localhost/...}, οι οποίοι επιβάλλουν τη χρήση HTTP από τον browser. +\begin{minted}{html} + Login Page + Dashboard + Notes +\end{minted} +\label{lst:http-index-before} + + +\subsection{Αντιμετώπιση} +\label{subsec:https-fix} + +Για να επιτευχθεί ασφαλής μεταφορά δεδομένων (\textit{transport security}), απαιτείται η χρήση HTTPS. +Σε περιβάλλον Docker, ένας πρακτικός και καθαρός τρόπος είναι να προστεθεί ένα reverse proxy +(π.χ. Caddy / NGINX) μπροστά από τον Apache web server. +Το reverse proxy αναλαμβάνει: +\begin{itemize} + \item TLS termination (διαπραγμάτευση κρυπτογράφησης), + \item αυτόματη ανακατεύθυνση από HTTP σε HTTPS, + \item προώθηση (proxying) της κίνησης προς το εσωτερικό container της εφαρμογής. +\end{itemize} + +Με αυτή την αρχιτεκτονική, το container \texttt{web} \textbf{δεν εκτίθεται πλέον} απευθείας προς τα έξω. +Εκτίθενται μόνο οι πόρτες 80/443 του reverse proxy. + +\subsection{Αλλαγές στο docker-compose.yml} +Αφαιρέθηκε το \texttt{ports: "80:80"} από τη web υπηρεσία και προστέθηκε νέα υπηρεσία \texttt{proxy} (Caddy) η οποία εκθέτει τις θύρες 80 (redirect) και 443 (HTTPS): + +\begin{minted}{yaml} + services: + proxy: + image: caddy:2 + ports: + - "80:80" + - "443:443" + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile:ro + - caddy_data:/data + - caddy_config:/config + depends_on: + - web + + volumes: + caddy_data: + caddy_config: +\end{minted} +\label{lst:https-compose-after} + +\subsection{Ρύθμιση reverse proxy -- Caddyfile} +Για χρήση σε τοπικό περιβάλλον (\texttt{localhost}), επιλέχθηκε self-signed / internal TLS (\texttt{tls internal}). +Αυτό είναι κατάλληλο για demo/testing, καθώς δεν απαιτεί domain name ή δημόσιο πιστοποιητικό. +Το \textit{Caddyfile} είναι: + +\begin{minted}{text} +# HTTP site: redirect everything to HTTPS +http://localhost { + redir https://{host}{uri} permanent +} + +# HTTPS site +https://localhost { + reverse_proxy web:80 + tls internal + + # Optional: security headers (defense-in-depth) + header { + X-Content-Type-Options "nosniff" + X-Frame-Options "DENY" + Referrer-Policy "no-referrer" + } +} +\end{minted} +\label{lst:caddyfile} + +\paragraph{Σημείωση για τοπικά πιστοποιητικά (browser warning).} +Η χρήση \texttt{tls internal} δημιουργεί self-signed πιστοποιητικό, το οποίο ενδέχεται να προκαλέσει warning στον browser. +Το γεγονός αυτό είναι αναμενόμενο σε τοπικό demo περιβάλλον και δεν αναιρεί τη λειτουργία κρυπτογράφησης. +Σε παραγωγικό περιβάλλον θα χρησιμοποιούνταν έγκυρο πιστοποιητικό (π.χ. μέσω Let's Encrypt) και domain name. + +\subsubsection{Αλλαγές στο index.html} +Για να αποφευχθεί το hard-coding του scheme (\texttt{http://}) και να λειτουργεί σωστά τόσο σε HTTP$\rightarrow$HTTPS redirect όσο και σε μελλοντικό deployment, οι σύνδεσμοι άλλαξαν ώστε να είναι \textbf{relative URLs}: + +\begin{minted}{html} + Login Page + Dashboard + Notes +\end{minted} +\label{lst:https-index-after} + +\subsection{Επαλήθευση} +Όπως φαίνεται και στην Εικόνα~\ref{fig:https-sample}, μετά τις αλλαγές, η εφαρμογή είναι διαθέσιμη μέσω: \texttt{https://localhost/passman},. +\begin{figure}[!ht] + \centering + \includegraphics[width=0.55\textwidth]{img/https-Sample.png} + \caption{λειτουργία μέσω https (και εμφάνιση του warning).} + \label{fig:https-sample} +\end{figure} + +Επιπλέον, η πρόσβαση σε \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} + +Με την εισαγωγή reverse proxy και την ενεργοποίηση HTTPS, μειώνεται σημαντικά ο κίνδυνος υποκλοπής δεδομένων (\textit{eavesdropping}) και επιτυγχάνεται προστασία στο επίπεδο μεταφοράς (transport layer), ενισχύοντας τη συνολική ασφάλεια της εφαρμογής. + + + +\section{Συμπεράσματα} + +Στην παρούσα εργασία μελετήθηκε μια απλή διαδικτυακή εφαρμογή διαχείρισης κωδικών πρόσβασης, με στόχο την ανάδειξη και αντιμετώπιση κρίσιμων κενών ασφάλειας που προκύπτουν από μη ασφαλείς προγραμματιστικές πρακτικές. +Η προσέγγιση που ακολουθήθηκε ήταν πειραματική και βασισμένη σε πραγματικά σενάρια επίθεσης. +Αρχικά εντοπίστηκαν ευπάθειες όπως SQL Injection, Stored Cross-Site Scripting, αποθήκευση κωδικών σε απλό κείμενο, χρήση διαπιστευτηρίων διαχειριστή για τη βάση δεδομένων και απουσία κρυπτογράφησης στο επίπεδο μεταφοράς (HTTP). +Για κάθε περίπτωση παρουσιάστηκε ο τρόπος εκμετάλλευσης, τεκμηριώθηκαν οι επιπτώσεις και στη συνέχεια εφαρμόστηκαν στοχευμένα διορθωτικά μέτρα, με ελάχιστη αλλά ουσιαστική παρέμβαση στον κώδικα και στη συνολική αρχιτεκτονική. + +Οι διορθώσεις υλοποιήθηκαν με βάση θεμελιώδεις αρχές ασφαλούς σχεδίασης, όπως ο διαχωρισμός δεδομένων και εντολών (prepared statements), η αντιμετώπιση κάθε εισόδου ως μη έμπιστης (output encoding), η ασφαλής αποθήκευση κωδικών μέσω hashing, η αρχή του least privilege στη διαχείριση της βάσης δεδομένων και η προστασία της επικοινωνίας μέσω HTTPS. +Ιδιαίτερη έμφαση δόθηκε όχι μόνο στη «διόρθωση» μεμονωμένων σφαλμάτων, αλλά και στη μείωση του συνολικού αντίκτυπου πιθανών επιθέσεων (impact reduction), υιοθετώντας μια προσέγγιση defense-in-depth. +Μέσα από τη διαδικασία αυτή κατέστη σαφές ότι πολλές σοβαρές ευπάθειες δεν οφείλονται σε πολύπλοκα σφάλματα, αλλά σε απλές παραλείψεις και λανθασμένες παραδοχές κατά την ανάπτυξη της εφαρμογής. + +Συνολικά, η εργασία ανέδειξε τη σημασία της ασφάλειας ως αναπόσπαστο μέρος του σχεδιασμού λογισμικού και όχι ως μεταγενέστερη προσθήκη. +Η κατανόηση των μηχανισμών επίθεσης και η εφαρμογή βασικών πρακτικών secure coding επιτρέπουν τη δραστική βελτίωση της ασφάλειας ακόμη και σε απλές εφαρμογές. +Η εμπειρία που αποκομίστηκε υπογραμμίζει ότι η συστηματική σκέψη, η σωστή αρχιτεκτονική και η επίγνωση των κινδύνων είναι καθοριστικοί παράγοντες για την ανάπτυξη αξιόπιστων και ασφαλών πληροφοριακών συστημάτων. + + +\end{document}