Web Security Part 1: Πώς προστατεύεται πραγματικά μια εφαρμογή;

Από την κρυπτογράφηση και τα passwords μέχρι την ταυτοποίηση, τα δικαιώματα πρόσβασης και τις επιθέσεις στον browser. Κάθε φορά που συνδεόμαστε σε μια ιστοσελίδα, πραγματοποιούνται αρκετές διαδικασίες ασφαλείας χωρίς να τις αντιλαμβανόμαστε. Τα δεδομένα μεταφέρονται κρυπτογραφημένα, η ταυτότητά μας επαληθεύεται και το σύστημα ελέγχει τι επιτρέπεται να κάνουμε. Η ασφάλεια δεν είναι ένας μοναδικός μηχανισμός που ενεργοποιούμε και ξεχνάμε. Είναι ένα σύνολο διαφορετικών τεχνολογιών και κανόνων που συνεργάζονται για την προστασία μιας εφαρμογής. Ας δούμε τις βασικότερες έννοιες, με παραδείγματα που συναντάμε καθημερινά στην ανάπτυξη λογισμικού.

Ευθύμιος Θεοτοκάτος 11′ ανάγνωση

Web Security Part 1: Πώς προστατεύεται πραγματικά μια εφαρμογή;

1. Encryption και Hashing: Δύο διαφορετικοί μηχανισμοί

Η κρυπτογράφηση (Encryption) μετατρέπει δεδομένα σε μορφή που δεν μπορεί να διαβαστεί χωρίς το κατάλληλο κλειδί. Με τη διαδικασία της αποκρυπτογράφησης μπορούμε να ανακτήσουμε τις αρχικές πληροφορίες.

Το Hashing (Κατακερματισμός) δημιουργεί ένα ψηφιακό αποτύπωμα από τα δεδομένα που δέχεται. Δεν διαθέτει αντίστροφη διαδικασία αποκρυπτογράφησης και χρησιμοποιείται, μεταξύ άλλων, για τον έλεγχο ακεραιότητας.

Παράδειγμα Encryption

Έχουμε ένα API key που πρέπει να χρησιμοποιεί η εφαρμογή μας για να επικοινωνεί με εξωτερική υπηρεσία.

API KEY: sk-123456789
        ↓
     Encryption
        ↓
  Κρυπτογραφημένη τιμή
        ↓
    Database

Όταν χρειαστούμε το API key, χρησιμοποιούμε το κατάλληλο κλειδί αποκρυπτογράφησης για να ανακτήσουμε την αρχική τιμή.

Παράδειγμα Hashing

Κατεβάζουμε ένα αρχείο και θέλουμε να ελέγξουμε αν έχει αλλοιωθεί.

Αρχικό αρχείο
     ↓ SHA-256
   HASH A

Αρχείο που κατεβάσαμε
     ↓ SHA-256
   HASH B

HASH A == HASH B ?

Αν τα hashes διαφέρουν, τα αρχεία δεν είναι ίδια. Αν ταιριάζουν, έχουμε ισχυρή ένδειξη ακεραιότητας, αρκεί το αρχικό hash να προέρχεται από αξιόπιστη πηγή.

Τι είναι το Collision;

Ένα hash δεν είναι εγγυημένα μοναδική ταυτότητα. Δύο διαφορετικά δεδομένα μπορούν θεωρητικά να παράγουν το ίδιο hash.

Αυτό ονομάζεται Collision (Σύγκρουση).

Για παράδειγμα, ένας υποθετικός αλγόριθμος παράγει μόνο δέκα διαφορετικά hashes. Αν επεξεργαστεί έντεκα διαφορετικές εισόδους, τουλάχιστον δύο θα έχουν το ίδιο αποτέλεσμα.

Στον SHA-256 υπάρχουν (2^{256}) πιθανά αποτελέσματα. Οι συγκρούσεις είναι μαθηματικά αναπόφευκτες, αλλά η εύρεσή τους θεωρείται υπολογιστικά εξαιρετικά δύσκολη.

2. Πώς αποθηκεύουμε τα Passwords;

Οι σωστά σχεδιασμένες εφαρμογές δεν αποθηκεύουν τους κωδικούς πρόσβασης των χρηστών ως απλό κείμενο. Χρησιμοποιούν ειδικούς αλγορίθμους hashing, όπως το Argon2id, που δυσκολεύουν τις προσπάθειες αποκάλυψής τους.

Κατά την εγγραφή, το password συνδυάζεται με μια τυχαία τιμή που ονομάζεται Salt. Το αποτέλεσμα αποθηκεύεται στη βάση μαζί με το salt και τις απαραίτητες παραμέτρους επαλήθευσης.

Παράδειγμα Register

Ο Γιώργος δημιουργεί έναν λογαριασμό με password Hello123.

Password: Hello123
          +
      Random Salt
          ↓
        Argon2id
          ↓
      Password Hash
          ↓
        Database

Το αρχικό password δεν αποθηκεύεται στη βάση.

Παράδειγμα Login

Την επόμενη ημέρα ο Γιώργος πληκτρολογεί ξανά το Hello123.

Password από Login
        +
Αποθηκευμένο Salt
        ↓
      Argon2id
        ↓
      Νέο Hash
        ↓
Σύγκριση με αποθηκευμένο Hash
        ↓
   Match → Login

Στην πράξη, χρησιμοποιούμε ειδική λειτουργία επαλήθευσης του Argon2id, η οποία πραγματοποιεί τον απαραίτητο έλεγχο.

Γιατί χρειάζεται το Salt;

Αν δύο χρήστες έχουν τον ίδιο κωδικό, διαφορετικά salts οδηγούν σε διαφορετικά αποθηκευμένα hashes. Αυτό δυσκολεύει επιθέσεις που χρησιμοποιούν προϋπολογισμένους πίνακες hashes.

3. API Keys: Πότε χρησιμοποιούμε Encryption και πότε Hashing;

Τα API Keys είναι μυστικές τιμές που χρησιμοποιούνται για την πρόσβαση σε προγραμματιστικές διεπαφές εφαρμογών. Ο τρόπος αποθήκευσής τους εξαρτάται από τη χρήση τους.

Παράδειγμα Α — Καλούμε εξωτερικό API

Η εφαρμογή μας χρησιμοποιεί ένα API key για να καλέσει μια εξωτερική υπηρεσία.

Χρειαζόμαστε την αρχική τιμή κάθε φορά που πραγματοποιούμε ένα request.

Database
   ↓
Encrypted API Key
   ↓
Decryption
   ↓
Original API Key
   ↓
External API

Σε αυτή την περίπτωση χρησιμοποιούμε κρυπτογράφηση ή ένα κατάλληλο σύστημα διαχείρισης μυστικών. Το κλειδί αποκρυπτογράφησης πρέπει να προστατεύεται χωριστά από τα δεδομένα.

Παράδειγμα Β — Εκδίδουμε δικά μας API Keys

Η εφαρμογή μας παρέχει API keys σε άλλους developers.

Ο πελάτης στέλνει το API key και ο server ελέγχει αν είναι έγκυρο.

API Key από Client
       ↓
      Hash
       ↓
Σύγκριση με Database
       ↓
    Valid / Invalid

Για μεγάλα, κρυπτογραφικά τυχαία API keys μπορούμε να χρησιμοποιούμε SHA-256. Δεν χρειάζεται να ανακτούμε το αρχικό κλειδί.

4. HTTPS, TLS και Certificates

Όταν κάνουμε login σε μια ιστοσελίδα, το password πρέπει να μεταφερθεί με ασφάλεια στον server. Το HTTPS χρησιμοποιεί το TLS (Transport Layer Security) για την προστασία της επικοινωνίας.

Το TLS παρέχει κρυπτογράφηση, ακεραιότητα και μηχανισμούς ταυτοποίησης του server.

Τα ψηφιακά πιστοποιητικά (Certificates) συνδέουν την ταυτότητα ενός server με ένα δημόσιο κρυπτογραφικό κλειδί. Ο browser ελέγχει την εγκυρότητά τους χρησιμοποιώντας, μεταξύ άλλων, έμπιστες Αρχές Πιστοποίησης (Certificate Authorities — CA).

Παράδειγμα HTTPS Login

BROWSER
Username: giorgos
Password: Hello123
         ↓
    HTTPS / TLS
         ↓
Κρυπτογραφημένη επικοινωνία
         ↓
       SERVER
         ↓
Αποκρυπτογράφηση TLS
         ↓
Επαλήθευση Password

Ο server αποκτά πρόσβαση στο αρχικό password ώστε να πραγματοποιήσει την επαλήθευση του hash.

Σημαντικό: Το HTTPS προστατεύει την επικοινωνία κατά τη μεταφορά. Δεν εγγυάται ότι η εφαρμογή είναι απαλλαγμένη από ευπάθειες.

5. Authentication, Authorization και Validation

Τρεις βασικές έννοιες που συχνά συγχέονται εξυπηρετούν διαφορετικούς σκοπούς.

Authentication (Ταυτοποίηση): Επιβεβαιώνουμε ποιος είναι ο χρήστης.

Authorization (Εξουσιοδότηση): Ελέγχουμε τι επιτρέπεται να κάνει.

Validation (Επικύρωση): Ελέγχουμε αν τα δεδομένα που στέλνει πληρούν τους κανόνες της εφαρμογής.

Παράδειγμα Authentication

Ο Γιώργος εισάγει σωστό username και password.

Username: giorgos
Password: Hello123
        ↓
Authentication
        ↓
      SUCCESS

Ο server έχει επαληθεύσει τα στοιχεία σύνδεσης του λογαριασμού.

Παράδειγμα Authorization

Ο Γιώργος είναι συνδεδεμένος, αλλά δεν έχει δικαίωμα να διαγράφει άρθρα.

DELETE /api/articles/15
         ↓
Authentication: SUCCESS
         ↓
Authorization: DENIED
         ↓
HTTP 403 Forbidden

Το επιτυχημένο Authentication δεν σημαίνει ότι επιτρέπονται όλες οι ενέργειες.

Παράδειγμα Validation

Ο Γιώργος στέλνει:

{
  "title": "",
  "price": -500
}

Ο server απορρίπτει τα δεδομένα επειδή ο τίτλος είναι κενός και η τιμή αρνητική.

Παράδειγμα Mass Assignment

Ένας χρήστης επιχειρεί να αλλάξει μόνος του τον ρόλο του.

{
  "name": "Giorgos",
  "role": "admin"
}

Η εφαρμογή επιτρέπει στους απλούς χρήστες να τροποποιούν μόνο συγκεκριμένα πεδία, όπως το name.

Το role δεν πρέπει να τροποποιηθεί μέσω αυτού του endpoint.

Αν ο server αποθηκεύει ανεξέλεγκτα όλα τα πεδία, μπορεί να προκύψει ευπάθεια Mass Assignment.

RBAC και ABAC στην πράξη

Στο RBAC (Role-Based Access Control) τα δικαιώματα συνδέονται με ρόλους.

Admin  → Edit Any Article
Editor → Edit Own Articles
Reader → Read Articles

Στο ABAC (Attribute-Based Access Control) εξετάζονται επιπλέον χαρακτηριστικά.

Για παράδειγμα, ένας Editor μπορεί να τροποποιήσει δικό του άρθρο μόνο εφόσον δεν είναι δημοσιευμένο. Αν είναι δημοσιευμένο, απαιτείται καταχωρισμένη έγκριση.

6. Least Privilege και Defense in Depth

Η Αρχή των Ελάχιστων Δικαιωμάτων (Least Privilege) λέει ότι κάθε χρήστης ή πρόγραμμα πρέπει να διαθέτει μόνο τα απαραίτητα δικαιώματα.

Το Defense in Depth (Άμυνα σε βάθος) βασίζεται σε πολλαπλά επίπεδα προστασίας. Αν αποτύχει ένα επίπεδο, τα υπόλοιπα μπορούν να περιορίσουν τις επιπτώσεις.

Παράδειγμα Least Privilege

Μια υπηρεσία χρειάζεται μόνο να διαβάζει άρθρα από τη βάση δεδομένων.

SELECT  → ALLOWED
INSERT  → DENIED
UPDATE  → DENIED
DELETE  → DENIED

Δεν υπάρχει λόγος να διαθέτει δικαιώματα που δεν χρησιμοποιεί.

Παράδειγμα Defense in Depth

Ένας εισβολέας βρίσκει μια ευπάθεια στην εφαρμογή και αποκτά δυνατότητα εκτέλεσης SQL queries.

Ακόμη κι αν εκμεταλλευτεί την ευπάθεια, ο περιορισμένος λογαριασμός της βάσης δεν του επιτρέπει να διαγράψει δεδομένα.

Η επίθεση εξακολουθεί να είναι επικίνδυνη, αλλά οι πιθανές επιπτώσεις περιορίζονται.

7. SQL Injection: Όταν τα δεδομένα γίνονται εντολές

Το SQL Injection εμφανίζεται όταν μη έμπιστα δεδομένα ενσωματώνονται με μη ασφαλή τρόπο σε SQL queries.

Ο εισβολέας προσπαθεί να μεταβάλει τη λογική του ερωτήματος προς τη βάση δεδομένων.

Παράδειγμα μη ασφαλούς υλοποίησης

Η εφαρμογή κατασκευάζει το SQL query ενώνοντας απευθείας το κείμενο του χρήστη.

query = "SELECT * FROM users
         WHERE username = '" + input + "'"

Αν το input περιέχει ειδικά διαμορφωμένο SQL κείμενο, μπορεί να αλλάξει η σημασία του query.

Ασφαλέστερη υλοποίηση

Χρησιμοποιούμε Prepared Statements με παραμέτρους.

SELECT * FROM users
WHERE username = ?;

Η τιμή του username μεταφέρεται ξεχωριστά από τη SQL εντολή.

Έτσι, αντιμετωπίζεται ως δεδομένο και όχι ως εκτελέσιμο SQL.

Το Validation παραμένει χρήσιμο για τον έλεγχο μορφής και μεγέθους, αλλά δεν αντικαθιστά τα Prepared Statements.

8. XSS: Κακόβουλος κώδικας μέσα στον Browser

Το Cross-Site Scripting (XSS) είναι μια ευπάθεια που μπορεί να επιτρέψει την εκτέλεση κακόβουλης JavaScript μέσα στον browser άλλων χρηστών.

Αυτό μπορεί να συμβεί όταν μη έμπιστο περιεχόμενο εμφανίζεται ως εκτελέσιμο HTML ή JavaScript.

Παράδειγμα XSS

Ο Γιώργος γράφει ένα σχόλιο:

<script>alert('Hello')</script>

Αν η εφαρμογή το εμφανίσει ως εκτελέσιμο HTML, ο browser ενός επισκέπτη μπορεί να εκτελέσει τον κώδικα.

Παράδειγμα προστασίας με Output Encoding

Αν θέλουμε να εμφανίσουμε απλό κείμενο, μπορούμε να χρησιμοποιήσουμε:

element.textContent = userComment;

Αντί να εισαγάγουμε μη έμπιστο περιεχόμενο απευθείας μέσω:

element.innerHTML = userComment;

Το textContent εμφανίζει το περιεχόμενο ως κείμενο χωρίς να το ερμηνεύει ως HTML.

Παράδειγμα Sanitization

Θέλουμε να επιτρέπουμε:

<strong>Πολύ καλό άρθρο!</strong>

Αλλά όχι επικίνδυνο περιεχόμενο όπως:

<a href="javascript:alert('XSS')">
  Πάτα εδώ
</a>

Ένας σωστός HTML sanitizer ελέγχει τόσο τα επιτρεπόμενα tags όσο και τα attributes τους.

Παράδειγμα CSP

Η εφαρμογή μπορεί επίσης να εφαρμόσει μια Content Security Policy (CSP) που περιορίζει ποια scripts επιτρέπεται να εκτελεστούν.

Μια κατάλληλα διαμορφωμένη πολιτική μπορεί, για παράδειγμα, να εμποδίζει μη εξουσιοδοτημένα inline scripts.

Πρόκειται για πρόσθετο επίπεδο προστασίας, όχι για αντικατάσταση του ασφαλούς χειρισμού περιεχομένου.

9. CSRF: Εκμετάλλευση μιας ενεργής σύνδεσης

Το Cross-Site Request Forgery (CSRF) εκμεταλλεύεται το γεγονός ότι ο browser μπορεί να συμπεριλαμβάνει αυτόματα cookies στα αιτήματα.

Ένας κακόβουλος ιστότοπος προσπαθεί να προκαλέσει ανεπιθύμητες ενέργειες σε μια εφαρμογή όπου ο χρήστης είναι ήδη συνδεδεμένος.

Παράδειγμα CSRF

Ο Γιώργος έχει συνδεθεί στην τράπεζά του.

Ανοίγει έναν κακόβουλο ιστότοπο, ο οποίος προσπαθεί να προκαλέσει ένα αίτημα μεταφοράς χρημάτων προς την τράπεζα.

evil.com
   ↓
Αίτημα προς bank.gr
   ↓
Browser προσθέτει Session Cookie
   ↓
Server αναγνωρίζει τον Γιώργο

Αν η τράπεζα δεν διαθέτει κατάλληλη προστασία CSRF, μπορεί να εκτελέσει την ανεπιθύμητη ενέργεια.

Παράδειγμα προστασίας με CSRF Token

Ο server συνδέει με τη συνεδρία ένα απρόβλεπτο token και το απαιτεί σε ευαίσθητα αιτήματα.

Session Cookie → VALID
CSRF Token     → MISSING
        ↓
      DENIED

Πρόσθετη προστασία προσφέρουν οι έλεγχοι Origin και τα SameSite Cookies.

Ένα XSS μέσα στην ίδια την εφαρμογή μπορεί ενδεχομένως να παρακάμψει αυτές τις προστασίες. Γι' αυτό η πρόληψη του XSS παραμένει απαραίτητη.

10. Sessions και Cookies: Πώς παραμένουμε συνδεδεμένοι;

Μετά το Login, ο server μπορεί να δημιουργήσει ένα Session με ένα τυχαίο αναγνωριστικό.

Ο browser αποθηκεύει συνήθως το αναγνωριστικό μέσα σε cookie και το στέλνει στα κατάλληλα HTTP requests.

Παράδειγμα Session Cookie

Set-Cookie: session=ABC123; HttpOnly; Secure; SameSite=Lax

Κάθε χαρακτηριστικό έχει διαφορετικό ρόλο.

HttpOnly: Εμποδίζει τη JavaScript να διαβάσει το cookie.

Secure: Περιορίζει την αποστολή του cookie σε HTTPS, με ειδική εξαίρεση για localhost.

SameSite: Περιορίζει την αποστολή cookies σε αιτήματα μεταξύ διαφορετικών sites.

Παράδειγμα HttpOnly

Μια κακόβουλη JavaScript προσπαθεί να διαβάσει τα cookies.

console.log(document.cookie);

Το session cookie με HttpOnly δεν εμφανίζεται στο αποτέλεσμα.

Όμως ο browser μπορεί να συνεχίσει να το χρησιμοποιεί αυτόματα στα κατάλληλα requests. Επομένως το HttpOnly δεν εξουδετερώνει μια επίθεση XSS.

Παράδειγμα Session Hijacking

Ένας εισβολέας αποκτά ένα έγκυρο Session ID.

Αν ο server εξακολουθεί να αποδέχεται το αναγνωριστικό, ο εισβολέας μπορεί ενδεχομένως να χρησιμοποιήσει τη συνεδρία χωρίς να γνωρίζει το password.

Αυτή η επίθεση ονομάζεται Session Hijacking.

Παράδειγμα Session Fixation

Ο εισβολέας καταφέρνει να οδηγήσει τον χρήστη στη χρήση ενός Session ID που γνωρίζει ήδη.

Αν το ίδιο ID παραμείνει ενεργό μετά το login, ο εισβολέας μπορεί να επιχειρήσει να χρησιμοποιήσει την αυθεντικοποιημένη συνεδρία.

Γι' αυτό ανανεώνουμε το Session ID μετά το επιτυχές Authentication.

Πριν το Login: ABC123
        ↓
     Login OK
        ↓
Μετά το Login: XYZ789
        ↓
Ακύρωση παλιού Session ID

Παράδειγμα Session Expiration

Ένα session μπορεί να έχει δύο διαφορετικά χρονικά όρια:

  • Idle Timeout: Λήγει μετά από περίοδο αδράνειας, για παράδειγμα 15 λεπτά.

  • Absolute Timeout: Λήγει μετά από συνολική διάρκεια, για παράδειγμα 8 ώρες.

Τα χρονικά όρια επιβάλλονται στον server.

Παράδειγμα Logout

Όταν ο χρήστης πατήσει Logout:

Logout Request
      ↓
Server ακυρώνει Session
      ↓
Browser διαγράφει Cookie
      ↓
Session Invalid

Δεν αρκεί να διαγράψουμε το cookie μόνο από τον browser. Πρέπει να ακυρωθεί και η δυνατότητα χρήσης της συνεδρίας στον server.

11. Rate Limiting και Account Enumeration

Το Rate Limiting περιορίζει πόσο συχνά επιτρέπεται να πραγματοποιούνται αιτήματα προς μια υπηρεσία.

Χρησιμοποιείται, μεταξύ άλλων, για την αντιμετώπιση αυτοματοποιημένων προσπαθειών παραβίασης λογαριασμών.

Παράδειγμα Rate Limiting

Ένας εισβολέας δοκιμάζει συνεχώς διαφορετικά passwords.

Attempt 1 → FAILED
Attempt 2 → FAILED
Attempt 3 → FAILED
Attempt 4 → FAILED
Attempt 5 → FAILED
Attempt 6 → RATE LIMITED

Η εφαρμογή μπορεί να επιστρέψει:

HTTP 429 Too Many Requests

Τα όρια μπορούν να εφαρμόζονται ανά IP, λογαριασμό ή συνδυασμό χαρακτηριστικών.

Αν περιορίζουμε μόνο την IP, ένας εισβολέας μπορεί να επιχειρήσει να χρησιμοποιήσει διαφορετικές διευθύνσεις. Αν περιορίζουμε μόνο το username, μπορεί να προκαλέσει ανεπιθύμητα κλειδώματα λογαριασμών.

Παράδειγμα Account Enumeration

Ένας εισβολέας δοκιμάζει διαφορετικά usernames.

Username: giorgos
Response: User does not exist.

Username: maria
Response: Wrong password.

Ο server μόλις αποκάλυψε ότι υπάρχει λογαριασμός με username maria.

Η ασφαλέστερη συμπεριφορά είναι η επιστροφή γενικού μηνύματος:

Invalid username or password.

Παράδειγμα Timing Attack

Ακόμη κι αν επιστρέφουμε το ίδιο μήνυμα, μπορεί να υπάρχουν διαφορές στον χρόνο απόκρισης.

Άγνωστος χρήστης: 10 ms
Υπαρκτός χρήστης: 300 ms

Αν αυτές οι διαφορές είναι επαναλαμβανόμενες και μετρήσιμες, ένας εισβολέας μπορεί να τις χρησιμοποιήσει για να συμπεράνει ποια usernames υπάρχουν.

Οι εφαρμογές πρέπει να αποφεύγουν σημαντικές διαφορές στη διαδικασία επαλήθευσης και να εφαρμόζουν πρόσθετους περιορισμούς αιτημάτων.

Συμπέρασμα: Η ασφάλεια είναι μια αλυσίδα

Η πραγματική ασφάλεια μιας εφαρμογής δεν εξαρτάται από ένα ισχυρό password ή ένα πιστοποιητικό HTTPS. Προκύπτει από τη συνεργασία πολλών διαφορετικών μηχανισμών που προστατεύουν συγκεκριμένα σημεία του συστήματος.

Το Encryption προστατεύει την εμπιστευτικότητα, το Hashing δημιουργεί αποτυπώματα και το Authentication επαληθεύει στοιχεία ταυτότητας. Το Authorization περιορίζει τις ενέργειες, ενώ το Validation ελέγχει τα δεδομένα πριν χρησιμοποιηθούν.

Τα Prepared Statements προστατεύουν τα SQL queries, ενώ οι κατάλληλες τεχνικές χειρισμού HTML περιορίζουν το XSS. Τα CSRF Tokens, οι ρυθμίσεις cookies και η σωστή διαχείριση sessions προσφέρουν επιπλέον προστασία.

Κανένας μηχανισμός δεν είναι απόλυτος. Η ουσία βρίσκεται στον συνδυασμό τους και στην κατανόηση των ορίων τους.

Στο επόμενο μέρος

Στο Web Security – Part 2 θα συνεχίσουμε με:

  • Timing Attacks και τεχνικές αντιμετώπισης.

  • Multi-Factor Authentication (MFA).

  • JWT και Access Tokens.

  • OAuth 2.0 και OpenID Connect.

  • Διαχείριση κρυπτογραφικών κλειδιών.

  • Security Logging, Monitoring και Recovery.

Στόχος είναι να κατανοήσουμε όχι μόνο πώς λειτουργούν οι μηχανισμοί ασφαλείας, αλλά και πώς συνεργάζονται σε πραγματικές εφαρμογές.


Πηγές και περαιτέρω ανάγνωση

  •  
Πώς σου φάνηκε;

Ευθύμιος Θεοτοκάτος

Η συντακτική ομάδα του CodeCraft καλύπτει τεχνολογία, AI, hardware και software.

Σχόλια

Φόρτωση σχολίων…