SecurityControls
Διαχείριση Συνεδρίας
Αλλαγή αναγνωριστικού συνεδρίας μετά την αυθεντικοποίηση
$sr = session_regenerate_id(); if ($sr === true) { echo '<p>Your session was regenerated</p>'; } else { echo '<p>Your session was not regenerated. Is the session started?'; }
Με χρήση ESAPI:
$sr = ESAPI::getHTTPUtilities()->changeSessionIdentifier(); if ($sr === true) { echo '<p>Your session was regenerated</p>'; } else { echo '<p>Your session was not regenerated. Is the session started?'; }
Καθαρισμός cookie.
$name = 'το όνομα του cookie' setcookie($name, '', 1, '', '');
Με χρήση ESAPI:
$req = new SafeRequest; ESAPI::getHTTPUtilities()->killAllCookies($req);
Έλεγχος Παραμέτρων
Κανονικοποίηση
Η κανονικοποίηση ασχολείται με τον τρόπο με τον οποίο τα συστήματα μετατρέπουν τα δεδομένα από τη μία μορφή στην άλλη. Συγκεκριμένα, είναι η διαδικασία μετατροπής μίας μη αξιόπιστης εισόδου από την αρχική αναπαράστασή της σε απλούστερη μορφή, ωστε να μπορεί να ελεγθεί ως προς το περιεχόμενο, με χρήση μαύρης λίστας. (Μόνο για έλεγχο)
Με χρήση ESAPI:
$input = $_GET['input']; $codecArray = array(); array_push( $codecArray, new HTMLEntityCodec() ); array_push( $codecArray, new PercentCodec() ); $encoderInstance = new DefaultEncoder( $codecArray ); $inputToCheck = encoderInstance->canonicalize($input);
Χρήση Λευκής Λίστας
Αν ο τύπος των αναμενόμενων δεδομένων εισόδου ανήκει σε κάποια συγκεκριμένη κατηγορία (πχ αλφαριθμητικά δεδομένα), τότε θα πρέπει να ελέγχετε αν τα μη αξιόπιστα δεδομένα ανήκουν στην κατηγορία αυτή.
is_numeric() Checks a variable for numeric content. is_array() Checks if a variable is an array. strlen() Returns a string‘s length.
ctype_alnum() alphanumeric characters – A-Z, a-z, 0-9 ctype_alpha() alphabetic characters – A-Z, a-z ctype_cntrl() control characters – e.g. tab, line feed ctype_digit() numerical characters – 0-9 ctype_graph() characters creating visible output e.g. no whitespace ctype_lower() lowercase letters – a-z ctype_print() printable characters ctype_punct() punctuation characters – printable characters, but not digits, letters or whitespace, e.g. .,!?:;*&$ ctype_space() whitespace characters – e.g. newline, tab ctype_upper() uppercase characters – A-Z ctype_xdigit() hexadecimal digits – 0-9, a-f, A-F <?php if (!ctype_print($_GET['var'])) { die("User input contains non-printable characters"); } ?>
FILTER_VALIDATE_INT Checks whether the input is an integer numeric value. FILTER_VALIDATE_BOOLEAN Checks whether the input is a boolean value. FILTER_VALIDATE_FLOAT Checks whether the input is a floating point number. FILTER_VALIDATE_REGEXP Checks the input against a regular expression. FILTER_VALIDATE_URL Checks whether the input is a URL. FILTER_VALIDATE_EMAIL Checks whether the input is a valid email address. FILTER_VALIDATE_IP Checks whether the input is a valid IPv4 or IPv6 <?php $url = filter_var($var, FILTER_URL); ?>
Με χρήση ESAPI:
$context = 'test'; $input = $_GET['input']; $allowNull = false; $type = 'SSN'; $type = 'URL'; $type = 'IPAddress'; $type = 'Email'; $rs= ESAPI::getValidator()->isValidInput($context, $input, $type, $maxLength, $allowNull); $format = 'F j, Y'; $rs= ESAPI::getValidator()->isValidDate($context, $input, $format, $allowNull); $rs= ESAPI::getValidator()->isValidCreditCard($context, $input, $allowNull); $rs= ESAPI::getValidator()->isValidDirectoryPath($context, $input, $allowNull); $minValue = -999999999; $maxValue = 999999999; $rs= ESAPI::getValidator()->isValidNumber($context, $input, $minValue, $maxValue, $allowNull); $rs= ESAPI::getValidator()->isValidInteger($context, $input, $minValue, $maxValue, $allowNull); $rs= ESAPI::getValidator()->isValidDouble($context, $input, $minValue, $maxValue, $allowNull); $list=array('one','two'); $rs= ESAPI::getValidator()->isValidListItem($context, $input, $list); $maxLength= 100; $rs= ESAPI::getValidator()->isValidPrintable($context, $input, $maxLength, $allowNull); $rs= ESAPI::getValidator()->isValidHTML($context, $input, $maxLength, $allowNull);
Τοποθέτηση μή έμπιστης εισόδου σε HTML δομές
Πρέπει να αποφεύγεται η εισαγωγή δεδομένων μέσα σε δομές με ετικέτες τύπου “<script>”, “<style>” ή “<!–”. Όταν πρέπει να εισαχθούν μή αξιόπιστα δεδομένα, μέσα σε HTML ετικέτες, όπως <body>…</body>,<div>…</div>,<p>…</p>, κτλ, πάντα πρέπει να γίνεται κωδικοποίηση των χαρακτήρων ώστε να αποφευχθεί η μετάβαση σε οποιοδήποτε πλαίσιο εκτέλεσης, όπως ετικέτες <script>,<style> είτε σε άλλες ετικέτες οι οποίες υποστηρίζουν event handlers. Αυτό μπορεί να γίνει με την χρήση της htmlentities() είτε της htmlspecialchars() για σελίδες που περιέχουν utf-8 χαρακτήρες [2]. Το Open eClass διαθέτει την συνάρτηση q() η οποία μπορεί να χρησιμοποιηθεί για αυτό το σκοπό.
$output = q($input); // Είναι η htmlspecialchars($s, ENT_QUOTES)
Με χρήση ESAPI:
$output = ESAPI::getEncoder()->encodeForHTML($input);
Τοποθέτηση μή έμπιστης εισόδου σε HTML ετικέτες
Πρέπει να αποφεύγεται η εισαγωγή μή αξιόπιστων δεδομένων σαν όνομα ετικέτας ή σαν όνομα ιδιότητας ετικέτας. Όταν απαιτείται κάτι τέτοιο, οι δυνατές τιμές θα πρέπει να είναι ενσωματομένες στον κώδικα.
$view = "<input "; if($_GET['type']==="onload"){ $view .= "onload"; }
Τοποθέτηση μή έμπιστης εισόδου σε HTML ιδιότητες
Πρέπει να αποφεύγεται η εισαγωγή μη αξιόπιστων δεδομένων σε ιδιότητες ετικετών που μπορούν να οδηγήσουν σε εκτέλεση κώδικα, όπως οι “href = ‘…..’”, “src = ‘…..’”, “style = ‘….’”, “Fscommand(…)” και όλοι οι event handlers onClick = ‘….’, onLoad = ‘….’, onChange = ‘…..’, κτλ. Για την εισαγωγή σε τιμή κάποιας ιδιότητας που δεν μπορεί να οδηγήσει σε εκτέλεση κώδικα, μίας ετικέτας, πρέπει η τιμή της ιδιότητας να είναι απαραίτητα προστατευμένη με quotes, και να χρησιμοποιηθεί μία από τις παρακάτω συναρτήσεις, έχοντας απαραίτητα την ένδειξη κωδικοποίησης και των quotes. (ENT_QUOTE)
<body bgcolor = '<?php echo q($_GET['color']); ?>' > </body>
Με χρήση ESAPI:
<body bgcolor = '<?php echo ESAPI::getEncoder()->encodeForHTMLAttribute(($_GET['color']); ?>' > </body>
Τοποθέτηση μή έμπιστης εισόδου σε τμήμα URL
Για ιδιότητες που αφορούν συνδέσμους URLs, σε περίπτωση που είναι αναγκαίο να χρησιμοποιηθούν δεδομένα που παρέχει ο χρήστης, και εφόσον έχει ελεγχθεί η εγκυρότητα του συνδέσμου, πρέπει να χρησιμοποιηθεί η URL encode, και στη συνέχεια να γίνει χρήση των μεθόδων προστασίας όπως παρουσιάστηκαν παραπάνω.
$username = urlencode($_GET['username']); $link = "http://example.org/index.php?username={$username}"; $cleanlink = q($link); echo "<a href=\"{$cleanlink}\">Link</a>";
Με χρήση ESAPI:
$username= ESAPI::getEncoder()->encodeForURL($_GET['username']); $link = "http://example.org/index.php?username={$username}"; $cleanlink = ESAPI::getEncoder()->encodeForHTMLAttribute($link); echo "<a href=\"{$cleanlink}\">Link</a>";
Έλεγχος μή έμπιστης εισόδου σε Header
Για εισαγωγή δεδομένων στους Headers των απαντήσεων του εξυπηρετητή, πρέπει πάντα να γίνεται έλεγχος για ύπαρξη χαρακτήρων αλλαγής γραμμής, εκτός από τους ελέγχους / μετατροπές που θα γινόντουσαν με βάση τους παραπάνω κανόνες.
if (strpbrk($_GET['x'], "\r\n")) die('line break in x'); header("Location: " ."http://www.example.com/?p=".urlencode($_GET['x']));
Με χρήση ESAPI:
if (strpbrk($_GET['x'], "\r\n")) die('line break in x'); header("Location: " ."http://www.example.com/?p=".ESAPI::getEncoder()->encodeForURL(StringUtilities::stripControls($_GET['x'])));
Επιστροφή μή έμπιστης εισόδου σε απάντηση JSON
Σε περίπτωση που τα μη αξιόπιστα δεδομένα επιστρέφονται στον φυλλομετρητή του χρήστη με χρήση ερωτημάτων JSON, τότε οι απαντήσεις του εξυπηρετητή θα πρέπει να έχουν την αντίστοιχη σήμανση για τον τύπο στο Header.
HTTP/1.1 200 Date: Wed, 06 Feb 2013 10:28:54 GMT Server: .... Content-Type: application/json; charset=utf-8
Τοποθέτηση μή έμπιστης εισόδου σε JSON αποθηκευμένο στη σελίδα
Σε περίπτωση που απαντήσεις JSON του εξυπηρετητή, χρειάζεται να αποθηκευτούν εκ των προτέρων μέσα στη σελίδα, δεν θα πρέπει να εισάγονται μέσα σε απλές ετικέτες <script> αλλά σε ετικέτες με την ιδιότητα «application/json» ώστε να είναι προφυλαγμένες από επιθέσεις και να διαβάζονται στη συνέχεια από εκεί.
<script id="init_data" type="application/json"> <?php echo $jsonstring; ?> </script>
Τοποθέτηση μή έμπιστης εισόδου σε CSS styles
H εισαγωγή αναξιόπιστων δεδομένων σε CSS style ετικέτες, θα πρέπει να αποφεύγεται, καθώς στις περισσότερες περιπτώσεις δεν είναι δυνατόν να υπάρξει ασφαλής τρόπος εισαγωγής δεδομένων. Γενικότερα, αν η εισαγωγή είναι απαραίτητη, θα πρέπει να περιοριστεί στις τιμές μίας ιδιότητας που ήδη υπάρχει, σε ένα CSS style, και να αφορά μία ιδιότητα που δεν σχετίζεται με κάποιο url, behavior ή custom χαρακτηριστικό (-moz-binding), όπως επίσης και να έχει ένα συγκεκριμένο αποδεκτό σύνολο τιμών, (πχ μόνο νούμερα ή μόνο αλφαριθμητικοί χαρακτήρες - έλεγχος με λευκή λίστα). Η χρήση htmlEntities() είναι και εδώ απαραίτητη, ωστόσο σε ορισμένες περιπτώσεις θα πρέπει να γίνονται και εξειδικευμένοι έλεγχοι. Τα URLs δεν θα πρέπει ποτέ να ξεκινάνε με την λέξη “javascript” παραμόνο με την λέξη “http/s”. Αντίστοιχα, οι τιμές των ιδιοτήτων δεν θα μπορούν να περιέχουν ποτέ την λέξη “expression”.
Τοποθέτηση μή έμπιστης εισόδου σε HTML Markups
Όταν είναι απολύτως απαραίτητο, ο χρήστης να μπορεί να αξιοποιήσει τα HTML markups, θα πρέπει να χρησιμοποιηθεί κάποια ειδική βιβλιοθήκη για έλεγχο των εισόδων και των εξόδων. Το Open eClass διαθέτει μία τέτοια βιβλιοθήκη. Συγκεκριμένα, φιλτράρονται όλα τα δεδομένα που εισάγονται στη βάση μέσω του rich text editor Tiny MCE μέσω της HTML purify (καλείται μέσω της συνάρτησης rich_text_editor() και κατα την εμφάνιση rich text το output φιλτράρεται από την συνάρτηση standard_text_escape() η οποία αντικαθιστά τα μαθηματικά σύμβολα και εμφανίζει τους ορισμού του γλωσσάριου.
<td><?php echo rich_text_editor('rescomments', 4, 20, $rescomments); ?></td> <div class='smaller'><?php echp standard_text_escape($row['grade_comments']); ?></div>
Με χρήση ESAPI:
$output = ESAPI::getSanitizer()->getSanitizedHTML('test', $input,$length, false);
Έλεγχος μή έμπιστης εισόδου με PHP Operators
$a == $b Equal TRUE if $a is equal to $b after type juggling. $a === $b Identical TRUE if $a is equal to $b, and they are of the same type. $a != $b Not equal TRUE if $a is not equal to $b after type juggling. $a <> $b Not equal TRUE if $a is not equal to $b after type juggling. $a !== $b Not identical TRUE if $a is not equal to $b, or they are not of the same type. $a < $b Less than TRUE if $a is strictly less than $b. $a > $b Greater than TRUE if $a is strictly greater than $b. $a <= $b Less than or equal to TRUE if $a is less than or equal to $b. $a >= $b Greater than or equal to TRUE if $a is greater than or equal to $b. Περισσότερα https://www.php.net/manual/en/language.operators.comparison.php https://php.net/manual/en/types.comparisons.php
Έλεγχος Προσπέλασης
Έλεγχος Άμεσης Προσπέλασης Αρχείων
Θα πρέπει να απαγορεύεται η απευθείας προσπέλαση των αρχείων που γίνονται include. Ένας τρόπος να γίνει αυτό, είναι με την χρήση μίας defined μεταβλητής, στο αρχείο που κάνει include ένα άλλο, και με έναν αντίστοιχο έλεγχο για την ύπαρξή της στο άλλο αρχείο.
Εξωτερικό αρχείο:
define(A,true);
Αρχείο που γίνεται include:
defined('A') or die(header('HTTP/1.0 403 Forbidden'));
Έλεγχος Προσπέλασης Λειτουργιών
Σε κάθε σελίδα, θα πρέπει πάντα να γίνεται πρώτα έλεγχος, για το εάν ο χρήστης έχει τα απαραίτητα δικαιώματα είτε για να προσπελάσει το περιεχόμενο, είτε για να πραγματοποιήσει κάποια εντολή.
$require_admin = TRUE; $require_course_admin = TRUE; $guest_allowed = TRUE; $require_current_course = TRUE; $require_login = TRUE; $require_editor = TRUE; $require_valid_uid = TRUE; $require_mcourse = TRUE; $require_mlogin = TRUE; $require_usermanage_user = TRUE; $require_power_user = TRUE; include '../../include/init.php';
Επίπεδο Μεταφοράς Δεδομένων
Επαλήθευση οτι το αίτημα πραγματοποιήθηκε σε ασφαλή σύνδεση
if ( (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') || (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] === 'on') ){ return true; }
Με χρήση ESAPI:
$req = new SafeRequest; ESAPI::getHTTPUtilities()->assertSecureRequest($req);
Στο RandomAccessReferenceMap ο μηχανισμός για τους τυχαίους αριθμούς μπορεί να βελτιωθεί.
Προστασία από επιθέσεις τύπου CSRF
Κάθε ενέργεια η όποια έχει ως αποτέλεσμα κάποια αλλαγή στον λογαριασμό του χρήστη είτε στην ίδια την εφαρμογή θα πρέπει να προστατεύεται από επιθέσεις του τύπου CSRF. Για τον σκοπό αυτό πρέπει να γίνουν δύο ενέργειες: # Κάθε τέτοια ενέργεια θα πρέπει να πραγματοποιείται μέσω της μεθόδου HTTP POST χρησιμοποίωντας φόρμες, εκτός απο ελάχιστες εξαιρέσεις οι οποίες θα πρέπει να αντιμετωπίζονται με την ανάλογη προσοχή. # Οι φόρμες πρέπει να περιέχουν ένα ειδικό token το οποίο θα ελέγχεται κατα την υποβολή της κάθε φόρμας. Σε περίπτωση που δεν είναι ίσο με το token που στάλθηκε στον χρήστη η ενέργεια δεν θα πρέπει να πραγματοποιείται.
Ο τρόπος με τον όποιο μπορεί να γίνεται ο έλεγχος είναι ο ακόλουθος:
$token = generate_csrf_token();
Ύστερα το token επιστρέφεται στον χρήστη σε κάθε φόρμα ως ένα κρυμμένο πεδίο:
<input type="hidden" name="csrf" value="<?$token?>">
Τέλος, είναι πολύ σημαντικό να ελέγχεται το token σε κάθε υποβολή κάποιας φόρμας. Για παράδειγμα:
$token = $_POST['csrf']; if (verify_csrf_token($token) == false) { die('CSRF attack detected'); }