# Software > Ασφάλεια >  PHP Σύστημα Login

## mojiro

Αυτό το καιρό γράφω ένα σύστημα δημιουργίας χρηστών με login/logout/mail-auth/pass-recovery (τα κλασσικά).

Έχω όμως ένα πρόβλημα όσο αφορά την ασφάλεια των κωδικών κατά το Login.

Εάν το POST γίνει με md5-hashed κωδικό τότε κανείς δε θα ξέρει τον κωδικό, αλλά μπορεί να υποκλαπεί το hash.
Καθώς η 2η σελίδα περιμένει το hash, μπορεί κάποιος να προκαλέσει διαδικασία POST από δικό του σύστημα και να στήλει το username+hash...

Σε αυτή τη περίπτωση τι κάνουμε; Φυσικά η λύση HTTPS δεν είναι πάντα εφικτή.

----------


## xrg

Challenge,response;

Δηλ, παράγεις στον server μία τυχαία σειρά.. τη στέλνεις στον πελάτη και του ζητάς να στείλει hashed το password του με αυτή. Εσύ, κρατάς την τυχαία στο $_SESSION και τη θεωρείς έγκυρη μόνο για τα επόμενα 5' .. Μετά, εσύ ελέγχεις αυτό που σου έστειλε ο πελάτης..

----------


## pkent79

Αυτό ακριβώς που λέει και ο xrg.
Ιδιαίτερη προσοχή στο θέμα timeout.
Επίσης για λίγο καλύτερη ασφάλεια, μπορείς το συγκεκριμένο random αριθμό που θα στείλεις να τον αντιστοιχίσεις μέσω του Session σε συγκεκριμένη IP (και web browser id) και να απορρίψεις οποιαδήποτε απάντηση που θα έρθει από άλλη IP μέχρι να γίνει το login.
Κατόπιν, μπορείς να συνεχίσεις με τον ίδιο τρόπο (έλεγχο IP & Browser ID) αν το επιθυμείς προκειμένου να αποκλείσεις κάποιος να υποκλέψει το session id από cookie.

Αν σε ενδιαφέρει, μπορείς να ελέγχεις και το header Χ-Forward-For για να καλύψεις και τη χρήση μέσω proxy.  ::

----------


## mojiro

Λοιπόν...
Κοντεύω να τελειώσω τη σελίδα "νέου λογαριασμού" η οποία περιέχει έως τώρα σα βασικό input: username, password, mail. Έχω βάλει τους εξής χαρακτηριστικά:

1) διπλή εισαγωγή password & email
2) έλεγχο στη μορφή του email σε javascript και php αφού σταλεί
3) έλεγχο μήκους κειμένου εισαγωγής για όλα τα πεδία τη στιγμή που γράφεις και όταν πατάς το submit
4) server-side έλεγχο μήκους μόνο για το username αφού το password έχει σταλεί σε md5
5) captcha φωτογραφία με τυχαίο όνομα αρχείου & αποστολή του κωδικού (που έχει σωθεί σε md5 στο session) του σε md5
6) σβήνω το whitespace από όλα τα πεδία πριν γίνει το submit & ελέγχω πάλι για την ορθότητα των πεδίων
7) δε γίνεται γίνεται POST εάν όλα τα πεδία δεν είναι εντάξει

μου μένουν να προσθέσω:
1) έλεγχο για linefeed & html tags στο πεδίο username
2) να βάλω αυτά που μου προτείνατε για τον έλεγχο του session
3) έλεγχο για την ύπαρξη του username/email στη βάση δεδομένων

υπάρχει κάτι ακόμη που θα μπορούσα να προσθέσω (σε επίπεδο ελέγχου στοιχείων & ασφάλειας);

----------


## pkent79

Μπορείς να ελέγξεις και αν ο mail server που δείχνει το mail είναι έγκυρο MX record.
Για δες το ακόλουθο κομμάτι κώδικα.



```
function check_email_address($email) {
  // First, we check that there's one @ symbol, and that the lengths are right
  if (!ereg("[^@]{1,64}@[^@]{1,255}", $email)) {
    // Email invalid because wrong number of characters in one section, or wrong number of @ symbols.
    return false;
  }
  // Split it into sections to make life easier
  $email_array = explode("@", $email);
  $local_array = explode(".", $email_array[0]);
  for ($i = 0; $i < sizeof($local_array); $i++) {
     if (!ereg("^(([A-Za-z0-9!#$%&'*+/=?^_`{|}~-][A-Za-z0-9!#$%&'*+/=?^_`{|}~\.-]{0,63})|(\"[^(\\|\")]{0,62}\"))$", $local_array[$i])) {
      return false;
    }
  }  
  if (!ereg("^\[?[0-9\.]+\]?$", $email_array[1])) { // Check if domain is IP. If not, it should be valid domain name
    $domain_array = explode(".", $email_array[1]);
    if (sizeof($domain_array) < 2) {
        return false; // Not enough parts to domain
    }
    for ($i = 0; $i < sizeof($domain_array); $i++) {
      if (!ereg("^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$", $domain_array[$i])) {
        return false;
      }
    }
  }
  
  list($username,$domain)=split('@',$email);
  // checks for if MX records in the DNS
  $mxhosts = array();
  if(!getmxrr($domain, $mxhosts))
  {
    // no mx records, ok to check domain
    if (@!fsockopen($domain,25,$errno,$errstr,30))
    {
      return false;
    }
    else
    {
      return true;
    }
  }
  else
  {
    // mx records found
    foreach ($mxhosts as $host)
    {
      if (@fsockopen($host,25,$errno,$errstr,30))
      {
        return true;
      }
    }
    return false;
  }
  
}
```

----------


## mojiro

καλό!

----------


## mkan

Η ακόμα καλύτερα RSA encryption, όπως χρησιμοποιεί και το http://meebo.com.
Check http://www.ohdave.com/rsa/ για javascript implementation (νομίζω απ'την serverside μεριά με php είναι πιο εύκολο πάντως)

----------


## mkan

Α, επίσης η συνήθης πρακτική είναι να στέλνεται plaintext ο κωδικός και να γίνεται το hashing μετά το POST, στον έλεγχο, δηλαδή, και στην αποθήκευση στην βάση. Γιατί αλλιώς είναι σαν ο κωδικός να ήταν το hash, οπότε τα πεδία στην βάση αντιστοιχούν σε κωδικό (και αν κάποιος υποψιάζεται eavesdropping, απλά χρησιμοποιεί https)

----------

