Écriture de code sécurisé: comment MYETV faire crypter, auth, transférer et stocker des informations

Dès Changement de code nous avons mis en œuvre, chaque jour, des améliorations sur MYETV sécurité; le premier travail a été le service d'authentification expliqué dans le#sécurité chapitre et puis nous avons affiné les capacités des développeurs pour créer la sécurité exclusive pour notre site Web. Les développeurs ont fait une mise à jour chaque fois que nous avons trouvé une sorte de vulnérabilités; c'est extrêmement utile pour faire des corrections d'algorithme à la volée, c'est le moment de se concentrer sur la façon dont nous avons sécurisé les pages côté client qui doivent communiquer avec le côté serveur (comme les appels ajax et les mises à jour post/get). En fait, nous avons divisé les deux opérations : GET (données envoyées par des files de requête) et POST (données envoyées par un formulaire).

Dans le premier cas (GET), l'utilisateur doit suivre ces points pour demander avec succès la page:

  1. Authentifier (lorsque la demande est faite)
  2. Vérification d'en-tête pour être sûr qu'il est appelé uniquement via Javascript
  3. E/S enregistrer dans un endroit sécurisé du disque dur l'horodatage et les informations sur l'utilisateur, hashed avec SHA512; chaque fois qu'une page côté client est demandée le système peut compter la datetime et combien de fois la page est demandée dans une période spécifique de temps; vous pourriez être interdit temporairement si vous demandez la page trop de temps dans une période spécifiée de secondes
  4. Un jeton généralement envoyé par requêtestring et c'est le SHA1 ou SHA512 (dépend de la rapidité avec laquelle la requête doit être) hash de l'utilisateur
  5. Ce jeton doit correspondre à l'ID de session original de l'utilisateur, lorsque l'utilisateur fait une requête côté serveur
  6. Si le jeton correspond, alors vous pouvez faire une simple demande GET

En tant que requête GET, nous entendons toute requête qui ne touche pas les bases de données ou les E/S des disques durs et qui provient de requêtes.

Dans le deuxième cas (POST), l'utilisateur doit suivre ces points pour demander avec succès la page:

  1. Authentifier (lorsque la demande est faite)
  2. Vérification d'en-tête pour être sûr qu'il est appelé uniquement via Javascript
  3. E/S enregistrer dans un endroit sécurisé du disque dur l'horodatage et les informations sur l'utilisateur, hashed avec SHA512; chaque fois qu'une page côté client est demandée le système peut compter la datetime et combien de fois la page est demandée dans une période spécifique de temps; vous pourriez être interdit temporairement si vous demandez la page trop de temps dans une période spécifiée de secondes
  4. Un premier jeton habituellement envoyé par GET (querystring) et c'est le hachage SHA1 ou SHA512 de l'identifiant de session de l'utilisateur
  5. Un second jeton envoyé par POST (formulaire) et c'est la crypte aes256 du hachage avec SHA1 ou SHA512 (dépend de la rapidité avec laquelle la requête doit être) de l'utilisateur, plus des informations supplémentaires comme datetime et autres (crypté seulement avec aes256 et paquet avec toute la requête)
  6. Ces deux jetons doivent correspondre à l'ID de session original de l'utilisateur, et des informations supplémentaires sont déchiffrées
  7. Si le jeton correspond, alors vous pouvez faire une simple demande GET
  8. Avec la datetime précédemment cryptée, nous pouvons contrôler l'interaction des utilisateurs à chaque seconde et nous pouvons approuver ou non certaines actions en les limitant dans le temps
  9. Lorsque tout est déballé succès (jetons et informations supplémentaires), vous avez juste besoin de quelques secondes pour faire une demande normale côté serveur et alors cet accès sera obfusqué pour le futur

En tant que requête POST, nous entendons toute requête qui vient par un formulaire et/ou touche n'importe quelle base de données ou E/S des disques durs.

Vérification des en-têtes côté serveur :

//restreigne l'accès ajax seulement...
définir('IS_AJAX', isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH') == 'xmlhttprequest');
if(!IS_AJAX) {
die('Accès restreint');
}
$pos = strpos($_SERVER['HTTP_REFERERER'],getenv('HTTP_HOST'));
if($pos=false){
die('Accès restreint');
}

Il s'agit d'un code côté serveur (PHP) vous donnera une idée de la manière dont les en-têtes sont vérifiés ; c'est une sécurité supplémentaire mais les en-têtes pourraient être spoofed facilement donc nous devons implémenter une autre couche de sécurité comme ci-dessous.

Vérification du disque dur E/S

// nombre de demandes de page autorisées pour l'utilisateur
définir("CONTROL_MAX_REQUESTSclientside", 1);
// intervalle de temps pour commencer à compter les requêtes de page (secondes)
définir("CONTROL_REQ_TIMEOUTside", 1);
// secondes pour punir l'utilisateur qui a dépassé les demandes
définir("CONTROL_BAN_TIMEclientside", 10);
// IP utilisateur
if(vide($_SERVER["REMOTE_ADDR"]):
définir("USER_IPclientside", désinfecterUSERIPclientside(hash('sha512','clientside'.session_id()));
Sinon:
définir("USER_IPclientside", désinfecterUSERIPclientside(hash('sha512', 'clientside'.$_SERVER["REMOTE_ADDR"]));
endif;

// répertoire en écriture pour conserver les données du script remplacer "[répertoire]" par un dossier sécurisé dans le disque dur
définir("SCRIPT_TMP_DIRclientside", "[répertoire]");
définir("CONTROL_DBclientside", "[répertoire2]");
définir("CONTROL_LOCK_DIRclientside", "[répertoire3]");
définir("CONTROL_LOCK_FILEclientside", "[répertoire4]".sanitizeUSERIPclientside(hash('sha512', USER_IPclientside));
@mkdir(côté clientCONTROL_LOCK_DIR);
@mkdir(côté client SCRIPT_TMP_DIR);

//afficher l'erreur si une erreur existe
si (file_exists(CONTROL_LOCK_FILEclientside)) {
si (time()-filemtime(CONTROL_LOCK_FILEclientside) > CONTROL_BAN_TIMEclientside) {
// cet utilisateur a terminé sa punition
unlink(CONTROL_LOCK_FILEclientside);
} autre {
// trop de requêtes
l'écho « Trop de demandes »;
contact(côté clientCONTROL_LOCK_FILE);
mourir;
}
}

fonction antiflood_countaccessCLIENTSIDE() {
// Requêtes de comptage et dernière heure d'accès
$control = Array();
si (file_exists(CONTROL_DBclientside)) {
$fh = fopen(CONTROL_DBclientside, "r");
$control = array_merge($control, (array)unserialize(fread($fh, filesize(CONTROL_DBclientside)));
fclose($fh);
}
Si (permis($control[USER_IPclientside])) {
Si (time()-$control[USER_IPclientside]["t"] < CONTROL_REQ_TIMEOUTclientside) {
$control[USER_IPclientside]["c"]++;
} autre {
$control[USER_IPclientside]["c"] = 1;
}
} autre {
$control[USER_IPclientside]["c"] = 1;
}
$control[USER_IPclientside]["t"] = time();
si (contrôle [du côté client de l'USER_IP]["c"] >= CONTRÔLE_MAX_REQUESTS côté client) {
// cet utilisateur a fait trop de requêtes dans un délai très court
$fh = fopen(CONTROL_LOCK_FILEclientside, "w");
fwrite($fh, côté client USER_IP);
fclose($fh);
}
// table de contrôle à jour
$fh = fopen(CONTROL_DBclientside, "w");
fwrite($fh, serialize($control));
fclose($fh);
}
//sanitiser IP utilisateur ou sessionID pour le nom du fichier à écrire sur disque
désinfecter la fonction Côté client de l'utilisateur($theuserIP) {
//sanitiser l'identifiant d'utilisation ou de session
$userIP = str_replace(array('[\', \']'), '', $theuserIP);
$userIP = preg_replace('/\[.*\]/U', '', $userIP);
$userIP = preg_replace('/&(amp;)?#?[a-z0-9]+;/i', '-', $userIP);
$userIP = htmlentities($userIP, ENT_COMPAT, 'utf-8');
$userIP = preg_replace('/&([a-z])(acute="uml="circ="grave="gredil="slash="tilde="caron="lig="quot="rsquo);/i', '\\1', $userIP );
la valeur de la valeur de référence de l'élément d'actif,
retourner strtolower(trim($userIP, '-'));
}

c'est un code d'algorithme côté serveur (PHP) et écrira dans un endroit sécurisé des disques durs le nombre de fois que la requête est envoyée, l'horodatage et certaines informations uniques de cette requête hashed avec SHA512 (comme le nom du fichier); lorsque le nombre de fois dépassé ou l'horodatage est différent de celui spécifié, la requête échouera du tout et une erreur est affichée. Cet algorithme est un peu compliqué et fonctionne seul, avec le nombre donné de secondes et les bons dossiers sur le disque dur, sans aucune intervention humaine.

Authentification des jetons

$token1 = urlencode(sha1(session_id()));
//avec AES256 CRYPT
$token2 = AES256CRYPT(sha1(session_id()),"[initialvectorkey]");
//SANS AES 256 CRYPT
//$token2 = sha1(session_id());

nous définissons la valeur des jetons dans l'exemple ci-dessus.

ci-dessus est un exemple de requête POST ; en combinaison avec la requête POST, une requête GET est également déclenchée (avec javascript ajax) avec une chaîne de requête comme ceci :

// Exécuter la requête sur /form.php (pas de chemin réel, par exemple)
requête = $.ajax({
url: "form.php?token1=",
type: "poste",
données: sérielisées Données
});

de cette façon les deux jetons sont envoyés du client aux scripts côté serveur prêts à être appariés.

Correspond aux jetons

$token1GETVAR = urldecode($_GET['token1']);
//avec AES256 CRYPT
$token2POSTVAR = AES256DECRYPT($_POST['token2'], "[initialvectorkey]";
// sans AES256 CRYPT
//$token2POSTVAR = $_POST['token2'];
$token1PHPVAR = sha1(session_id());
$token2PHPVAR = sha1(session_id());
if($token2POSTVAR != $token2PHPVAR=$token1GETVAR != token1PHPVAR:
die('");
endif;

La page demandée traitera la correspondance des jetons et déchiffrera toutes les informations supplémentaires pour s'assurer que la demande provient d'une source autorisée (dans le code ci-dessus nous ne voyons que la correspondance des jetons).

De cette façon, nous avons entièrement personnalisé et exclusif politique sécurisée à appliquer à toutes les demandes de source non fiable: cela réduit considérablement les risques de XSS ou d'autres attaques similaires côté client de sources non fiables. Remarque : comme pour des raisons de sécurité, nous pouvons vous révéler le code crypto qui crypte et décrypte les informations avec AES256 ; ce code réside dans un endroit sécurisé des disques durs et en dehors de la racine du site. Le chiffrement/décryptage avec AES256 est un pratique supplémentaire pour être sûr que les informations transmises sont fiables.

Ce ne sera pas une protection ddos, mais une protection côté serveur lorsque les données sont envoyées d'une source non fiable (comme les codes côté client). Toutes les données sont transférées avec ssl 128 bit de sorte que les transferts de données sûrs est un travail des navigateurs.

Ce flux de sécurité est le résultat d'années d'étude et d'application; avec ce système, personne, sauf qui est autorisé à le faire par la page précédente, ne peut accéder aux pages côté client.

Les A.P.I. sont construits pour l'accès public et ils ne mettent en œuvre qu'une petite partie de ce système de sécurité, à atteindre de tous sans restrictions. Au début de janvier 2018, le V1 de l'A.P.I. sera déprécié et seulement quelques fonctions seront disponibles par leur intermédiaire (plus d'informations sur les utilisateurs publics ou les contenus publics); de cette façon, les paramètres publics seront réduits de façon drastique et les informations seront les plus sûres. Nous continuerons à développer MYETV sans aucun paramètre public exposé.

C'est tout, les gars ! Tous vos commentaires sont appréciés et merci de lire cela et de faire MYETV toujours mieux, plus vite et plus sûr. Merci beaucoup.

A bientôt !