PHP offre une grande flexibilité aux développeurs, mais cela apporte aussi des dangers cachés potentiels pour la sécurité. Récemment, je dois résumer les problèmes passés. Ici, je vais traduire un article et ajouter quelques-unes de mes propres expériences de développement pour résumer.

Introduction
Lors du développement d'un service Internet, vous devez toujours garder à l'esprit les concepts de sécurité et les refléter dans le code que vous développez. Le langage de script PHP ne se préoccupe pas beaucoup des problèmes de sécurité, en particulier pour la plupart des développeurs inexpérimentés. Chaque fois que vous traitez une transaction impliquant de l'argent ou d'autres questions financières, vous devez accorder une attention particulière aux considérations de sécurité, comme le développement d'un forum ou d'un panier d'achat.
Points généraux pour la protection de la sécurité
Ne faites pas confiance aux formulaires
Pour la validation front-end JavaScript en général, comme vous ne pouvez pas connaître le comportement de l'utilisateur, par exemple en désactivant le moteur JavaScript du navigateur, des données malveillantes peuvent être envoyées au serveur en POST. Vous devez valider côté serveur et, pour chaque script PHP, valider les données qui lui sont transmises, afin de prévenir les attaques XSS et l'injection SQL.
Ne faites pas confiance aux utilisateurs
Supposez que chaque donnée que votre site Web reçoit contient du code malveillant et des menaces cachées, et nettoyez chaque donnée.
Désactiver les variables globales
Effectuez la configuration suivante dans le fichier php.ini :
register_globals = Off
Si cette option de configuration est activée, il y aura d'importants risques de sécurité. Par exemple, il existe un fichier de script process.php qui insère les données reçues dans la base de données. Le formulaire qui reçoit les données saisies par l'utilisateur pourrait ressembler à ceci :
<input name="username" type="text" size="15" maxlength="64">
De cette manière, après avoir soumis des données à process.php, PHP enregistrera une variable $username et soumettra les données de cette variable à process.php. En même temps, pour tout paramètre de requête POST ou GET, une telle variable sera définie. Si elle n'est pas explicitement initialisée, le problème suivant se produira :
<?php
// Define $authorized = true only if user is authenticated
if (authenticated_user()) {
$authorized = true;
}
?>
Ici, en supposant que la fonction authenticated_user vérifie simplement la valeur de la variable $authorized, si la configuration register_globals est activée, n'importe quel utilisateur peut envoyer une requête pour définir la variable $authorized à n'importe quelle valeur, contournant ainsi cette vérification.
Toutes ces données soumises doivent être obtenues via les tableaux globaux prédéfinis intégrés de PHP, notamment $_POST, $_GET, $_FILES, $_SERVER, $_REQUEST, etc. Parmi eux, $_REQUEST est une variable combinée des trois tableaux $_GET/$_POST/$_COOKIE, et l'ordre par défaut est $_COOKIE, $_POST, $_GET.
- Options de configuration de sécurité recommandées
Définissez error_reporting sur Off : n'exposez pas les messages d'erreur aux utilisateurs. Pendant le développement, il peut être défini sur ON.
Définissez safe_mode sur Off
Définissez register_globals sur Off
Désactivez les fonctions suivantes : system, exec, passthru, shell_exec, proc_open, popen
Définissez open_basedir sur /tmp, afin que les informations de session disposent des permissions de stockage, et configurez un répertoire racine de site web distinct.
Définissez expose_php sur Off
Définissez allow_url_fopen sur Off
Définissez allow_url_include sur Off
Attaque par injection SQL
Pour les instructions SQL qui opèrent sur une base de données, une attention particulière doit être accordée à la sécurité, car les utilisateurs peuvent saisir des instructions spécifiques qui modifient le fonctionnement de l'instruction SQL d'origine. Comme dans l'exemple ci-dessous :
$sql = "select * from pinfo where product = '$product'";
À ce stade, si le paramètre $product saisi par l'utilisateur est :
39'; DROP pinfo; SELECT 'FOO
Alors, l'instruction SQL finale devient la suivante :
select product from pinfo where product = '39'; DROP pinfo; SELECT 'FOO'
Cela deviendra trois instructions SQL, entraînant la suppression de la table pinfo, ce qui conduira à de graves conséquences.
Ce problème peut être simplement résolu en utilisant les fonctions intégrées de PHP :
$sql = 'Select * from pinfo where product = '"'
mysql_real_escape_string($product) . '"';
Pour prévenir les attaques par injection SQL, deux choses doivent être bien faites :
Toujours effectuer une validation de type sur les paramètres d'entrée
Toujours utiliser la fonction mysql_real_escape_string pour échapper les caractères spéciaux tels que les guillemets simples, les guillemets doubles et les backticks.
Cependant, d'après l'expérience de développement, n'activez pas les Magic Quotes de PHP. Cette fonctionnalité a été supprimée dans PHP 6. Échappez toujours manuellement lorsque cela est nécessaire.
Prévention des attaques XSS de base
Les attaques XSS ne ressemblent pas aux autres attaques ; cette attaque est menée côté client. L'attaque XSS la plus élémentaire consiste à placer un script JavaScript sur la page de formulaire que l'utilisateur s'apprête à soumettre, afin de voler les données et les cookies soumis par l'utilisateur.
Les attaques XSS sont plus difficiles à défendre que l'injection SQL. Les sites web de grandes entreprises ont été attaqués par XSS. Bien que cette attaque ne soit pas liée au langage PHP, PHP peut être utilisé pour filtrer les données utilisateur afin d'atteindre l'objectif de protection des données utilisateur. Ici, l'approche principale consiste à filtrer les données utilisateur, généralement en filtrant les balises HTML, en particulier les balises <a>. Voici une méthode de filtrage courante :
function transform_HTML($string, $length = null) {
// Helps prevent XSS attacks
// Remove dead space.
$string = trim($string);
// Prevent potential Unicode codec problems.
$string = utf8_decode($string);
// HTMLize HTML-specific characters.
$string = htmlentities($string, ENT_NOQUOTES);
$string = str_replace("#", "#", $string);
$string = str_replace("%", "%", $string);
$length = intval($length);
if ($length > 0) {
$string = substr($string, 0, $length);
}
return $string;
}
Cette fonction convertit les caractères HTML spéciaux en entités HTML. Lorsque le navigateur affiche ce texte, il est affiché en texte brut. Par exemple, <strong>bold</strong> s'affichera comme :
<STRONG>BoldText</STRONG>
Le cœur de la fonction ci-dessus est la fonction htmlentities. Cette fonction convertit les balises HTML spéciales en caractères d'entité HTML, ce qui permet de filtrer la plupart des attaques XSS.
Cependant, pour les attaquants XSS expérimentés, il existe des façons plus astucieuses d'attaquer : encoder leur code malveillant en hexadécimal ou en UTF-8 au lieu de texte ASCII ordinaire. Par exemple, ils peuvent procéder de la manière suivante :
<a href="http://host/a.php?variable=%22%3e %3c%53%43%52%49%50%54%3e%44%6f%73%6f%6d%65%74%68%69%6e%67%6d%61%6c%69%63%69%6f%75%73%3c%2f%53%43%52%49%50%54%3e">
Dans ce cas, le résultat réel rendu par le navigateur est :
<a href="http://host/a.php?variable="> <SCRIPT>Dosomethingmalicious</SCRIPT>
Cela permet d'atteindre le but de l'attaque. Pour éviter cette situation, vous devez en plus convertir # et % en leurs symboles d'entité correspondants sur la base de la fonction transform_HTML, et ajouter le paramètre $length pour limiter la longueur maximale des données soumises.
Utilisation de SafeHTML pour prévenir les attaques XSS
La protection ci-dessus contre les attaques XSS est très simple, mais elle n'inclut pas toutes les balises utilisateur. En même temps, il existe des centaines de façons de contourner la fonction de filtrage pour soumettre du code JavaScript, et il n'y a aucun moyen d'empêcher complètement cette situation.
Actuellement, aucun script unique ne peut garantir qu'il ne sera pas compromis par des attaques, mais il existe toujours des mesures de protection relativement meilleures. Il existe deux méthodes de protection de sécurité : la liste blanche et la liste noire. Parmi celles-ci, la liste blanche est plus simple et plus efficace.
Une solution de liste blanche est SafeHTML, qui est suffisamment intelligente pour identifier le HTML valide, puis supprimer toutes les balises dangereuses. Cela nécessite une analyse basée sur le paquet HTMLSax.
Comment installer et utiliser SafeHTML :
1. Allez surhttp://pixel-apes.com/safehtml/?page=safehtml Téléchargez la dernière version de SafeHTML
2. Placez les fichiers dans le répertoire classes du serveur, qui contient toutes les bibliothèques SafeHTML et HTMLSax.
3. Incluez le fichier de classe SafeHTML dans votre propre script.
4. Créez un objet SafeHTML.
5. Utilisez la méthode parse pour le filtrage.
<?php
/* If you're storing the HTMLSax3.php in the /classes directory, along
with the safehtml.php script, define XML_HTMLSAX3 as a null string. */
define(XML_HTMLSAX3, '');
// Include the class file.
require_once('classes/safehtml.php');
// Define some sample bad code.
$data = "This data would raise an alert <script>alert('XSS Attack')</script>";
// Create a safehtml object.
$safehtml = new safehtml();
// Parse and sanitize the data.
$safe_data = $safehtml->parse($data);
// Display result.
echo 'The sanitized data is <br />' . $safe_data;
?>
SafeHTML ne peut pas empêcher complètement les attaques XSS ; ce n'est qu'une méthode de vérification relativement complexe basée sur un script.
Utilisation du chiffrement HASH à sens unique pour protéger les données
Le chiffrement par hachage à sens unique garantit que le mot de passe de chaque utilisateur est unique et ne peut pas être déchiffré. Seul l'utilisateur final connaît le mot de passe ; le système ne connaît pas le mot de passe d'origine. L'un des avantages est que, même si le système est attaqué, l'attaquant ne peut pas connaître les données de mot de passe d'origine.
Le chiffrement et le hachage sont deux processus différents. Contrairement au chiffrement, le hachage ne peut pas être déchiffré ; il est à sens unique. En même temps, deux chaînes différentes peuvent produire la même valeur de hachage, de sorte que l'unicité de la valeur de hachage ne peut pas être garantie.
Les valeurs de hachage traitées par la fonction MD5 sont fondamentalement impossibles à casser, mais il y a toujours une possibilité, et des dictionnaires de hachage MD5 sont disponibles en ligne.
Utilisation de mcrypt pour chiffrer des données
La fonction de hachage MD5 peut afficher les données sous une forme lisible, mais lors du stockage des informations de carte de crédit des utilisateurs, celles-ci doivent être chiffrées et stockées, puis déchiffrées ultérieurement.
La meilleure méthode consiste à utiliser le module mcrypt, qui contient plus de 30 méthodes de chiffrement pour garantir que seul le chiffreur peut déchiffrer les données.
<?php
$data = "Stuff you want encrypted";
$key = "Secret passphrase used to encrypt your data";
$cipher = "MCRYPT_SERPENT_256";
$mode = "MCRYPT_MODE_CBC";
function encrypt($data, $key, $cipher, $mode) {
// Encrypt data
return (string)
base64_encode
(
mcrypt_encrypt
(
$cipher,
substr(md5($key),0,mcrypt_get_key_size($cipher, $mode)),
$data,
$mode,
substr(md5($key),0,mcrypt_get_block_size($cipher, $mode))
)
);
}
function decrypt($data, $key, $cipher, $mode) {
// Decrypt data
return (string)
mcrypt_decrypt
(
$cipher,
substr(md5($key),0,mcrypt_get_key_size($cipher, $mode)),
base64_decode($data),
$mode,
substr(md5($key),0,mcrypt_get_block_size($cipher, $mode))
);
}
?>
La fonction mcrypt nécessite les informations suivantes :
1. Les données à chiffrer
2. La clé utilisée pour chiffrer et déchiffrer les données
3. L'algorithme spécifique (cipher) choisi par l'utilisateur pour chiffrer les données, tel queMCRYPT_TWOFISH192,MCRYPT_SERPENT_256, MCRYPT_RC2, MCRYPT_DES, et MCRYPT_LOKI97)
4. Le mode utilisé pour le chiffrement
5. La graine de chiffrement, les données utilisées pour démarrer le processus de chiffrement, est une donnée binaire supplémentaire utilisée pour initialiser l'algorithme de chiffrement.
6. Les longueurs de la clé de chiffrement et de la graine peuvent être obtenues à l'aide de la fonction mcrypt_get_key_size et de la fonction mcrypt_get_block_size.
Si les données et la clé sont toutes deux volées, l'attaquant peut parcourir les chiffrements pour trouver un moyen de déchiffrer. Par conséquent, nous devons appliquer MD5 à la clé de chiffrement une fois pour garantir la sécurité. De plus, comme les données chiffrées renvoyées par la fonction mcrypt sont des données binaires, les enregistrer directement dans un champ de base de données peut provoquer d'autres erreurs, c'est pourquoi base64encode est utilisé pour convertir ces données en un nombre hexadécimal afin de faciliter le stockage.
Références : http://www.codeproject.com/Articles/363897/PHP-Security
Source de l'article : http://blog.csdn.net/u010487568/article/details/29828757