La sécurité est un sujet brûlant. La sécurisation de votre site Web est extrêmement importante pour toute application Web. En fait, 70 % de mon temps est consacré à la sécurisation des applications. Les formulaires sont l’une des choses les plus importantes que nous devons protéger. Aujourd'hui, nous allons examiner un moyen d'empêcher la falsification de requêtes XSS (cross-site scripting) et cross-site sur vos formulaires.
Les données POST peuvent être envoyées d'un site Web à un autre. Pourquoi est-ce mauvais ? Une scène simple...
Un utilisateur connecté à votre site Web visite un autre site Web au cours de sa session. Le site Web pourra envoyer des données POST à votre site Web, par exemple en utilisant AJAX. Étant donné que l'utilisateur est connecté à votre site, d'autres sites peuvent également envoyer des données de publication vers un formulaire sécurisé qui n'est accessible que s'il est connecté.
Nous devons également protéger nos pages des attaques utilisant cURL
Avec les clés du formulaire ! Nous ajouterons un hachage spécial (clé de formulaire) à chaque formulaire pour garantir que les données ne sont traitées que lorsqu'elles sont envoyées depuis votre site Web. Une fois le formulaire soumis, notre script PHP validera la clé du formulaire soumis par rapport à la clé du formulaire que nous avons définie lors de la session.
Tout d’abord, nous avons besoin d’un formulaire simple pour démontrer. L'un des formulaires les plus importants que nous devons protéger est le formulaire de connexion. Les formulaires de connexion sont vulnérables aux attaques par force brute. Créez un nouveau fichier et enregistrez-le sous index.php dans votre répertoire racine Web. Ajoutez le code suivant dans le corps :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="content-type" content="text/html;charset=UTF-8" /> <title>Securing forms with form keys</title> </head> <body> <form action="" method="post"> <dl> <dt><label for="username">Username:</label></dt> <dd><input type="text" name="username" id="username" /></dd> <dt><label for="username">Password:</label></dt> <dd><input type="password" name="password" id="password" /></dd> <dt></dt> <dd><input type="submit" value="Login" /></dd> </dl> </form> </body> </html>
Nous avons maintenant une simple page XHTML avec un formulaire de connexion. Si vous souhaitez utiliser les clés de formulaire sur votre site Web, vous pouvez remplacer le script ci-dessus par votre propre page de connexion. Passons maintenant à l'action réelle.
Nous allons créer une classe PHP pour la clé du formulaire. Étant donné que chaque page ne peut contenir qu'une seule clé de formulaire, nous pouvons créer un singleton pour notre classe afin de garantir que notre classe est utilisée correctement. Étant donné que la création de singletons est un sujet POO plus avancé, nous ignorerons cette partie. Créez un nouveau fichier appelé formkey.class.php et placez-le dans votre répertoire racine Web. Nous devons maintenant réfléchir aux fonctionnalités dont nous avons besoin. Tout d’abord, nous avons besoin d’une fonction pour générer la clé du formulaire afin de pouvoir la mettre dans le formulaire. Placez le code suivant dans votre fichier PHP :
<?php
//You can of course choose any name for your class or integrate it in something like a functions or base class
class formKey
{
//Here we store the generated form key
private $formKey;
//Here we store the old form key (more info at step 4)
private $old_formKey;
//Function to generate the form key
private function generateKey()
{
}
}
?>
Maintenant, nous devons trouver un moyen de générer la clé du formulaire. Parce que notre clé de formulaire doit être unique (sinon nous n'avons aucune sécurité), nous lions la clé à l'utilisateur en utilisant une combinaison de l'adresse IP de l'utilisateur, utilisons mt_rand() pour la rendre unique et utilisons la fonction uniqid() pour la rendre unique. plus singulier. Nous chiffrons également ces informations à l'aide de md5() pour créer une valeur de hachage unique, que nous insérons ensuite dans notre page. Parce que nous avons utilisé md5(), l'utilisateur ne peut pas voir ce que nous avons utilisé pour générer la clé. Fonctionnalité complète :
//Function to generate the form key private function generateKey() { //Get the IP-address of the user $ip = $_SERVER['REMOTE_ADDR']; //We use mt_rand() instead of rand() because it is better for generating random numbers. //We use 'true' to get a longer string. //See http://www.php.net/mt_rand for a precise description of the function and more examples. $uniqid = uniqid(mt_rand(), true); //Return the hash return md5($ip . $uniqid); }
Insérez le code ci-dessus dans votre fichier
formkey.class.php. Remplacez la fonction par la nouvelle fonction. Étape 3 : Insérez la clé du formulaire dans le formulaire
Générez des clés de formulaire à l'aide de notre fonction generateKey().
et la rendons publique puisque nous devons l'utiliser en dehors de la classe. Notre fonction appellera la fonction privée generateKey() pour générer une nouvelle clé de formulaire et la sauvegarder dans la session locale. Enfin, nous créons le code XHTML. Ajoutez maintenant le code suivant dans notre classe PHP :
//Function to output the form key
public function outputKey()
{
//Generate the key and store it inside the class
$this->formKey = $this->generateKey();
//Store the form key in the session
$_SESSION['form_key'] = $this->formKey;
//Output the form key
echo "<input type='hidden' name='form_key' id='form_key' value='".$this->formKey."' />";
}
. Nous devons également démarrer la session car notre classe utilise la session pour stocker les clés générées. Pour ce faire, nous ajoutons le code suivant au dessus des balises doctype et head :
<?php
//Start the session
session_start();
//Require the class
require('formkey.class.php');
//Start the class
$formKey = new formKey();
?>
, qui créera notre classe et la stockera dans $formKey. Il ne nous reste plus qu'à éditer le formulaire pour qu'il contienne la clé du formulaire :
仅此而已!因为我们创建了函数 outputKey(),所以我们只需将它包含在表单中即可。我们可以在每个表单中使用表单键,只需添加 outputKey(); ?> 现在只需查看网页的源代码,您就可以看到表单上附加了一个表单密钥。剩下的唯一步骤是验证请求。 我们不会验证整个表单;只有表单键。验证表单是基本的 PHP 操作,并且可以在网络上找到教程。让我们验证表单密钥。因为我们的“generateKey”函数会覆盖会话值,所以我们向 PHP 类添加一个构造函数。创建(或构造)我们的类时将调用构造函数。在我们创建新密钥之前,构造函数会将前一个密钥存储在类中;所以我们将始终拥有以前的表单密钥来验证我们的表单。如果我们不这样做,我们将无法验证表单密钥。将以下 PHP 函数添加到您的类中: 构造函数应始终命名为__construct()。当调用构造函数时,我们检查是否设置了会话,如果是,我们将其本地存储在 old_formKey 变量中。 现在我们可以验证表单密钥了。我们在类中创建一个基本函数来验证表单密钥。这个函数也应该是公共的,因为我们将在类之外使用它。该函数将根据表单键的存储值验证表单键的 POST 值。将此函数添加到 PHP 类中: 在index.php中,我们使用刚刚在类中创建的函数来验证表单密钥。当然,我们仅在 POST 请求后进行验证。在 $formKey = new formKey(); 后添加以下代码 我们创建了一个变量$error来存储我们的错误消息。如果已发送 POST 请求,我们将使用 $formKey->validate() 验证表单密钥。如果返回 false,则表单键无效,并且我们会显示错误。请注意,我们仅验证表单密钥 - 您需要自己验证表单的其余部分。 在 HTML 中,您可以放置以下代码来显示错误消息: 这将回显 $error 变量(如果已设置)。 如果您启动服务器并转到index.php,您将看到我们的表单和消息“无错误”。当您提交表单时,您将看到消息“无表单键错误”,因为它是有效的 POST 请求。现在尝试重新加载页面并在浏览器请求再次发送 POST 数据时接受。您将看到我们的脚本触发了一条错误消息:“表单键错误!”现在,您的表单可以免受来自其他网站的输入和页面重新加载错误的影响!刷新后也会显示该错误,因为我们提交表单后生成了新的表单密钥。这很好,因为现在用户不会意外地将表单发布两次。 以下是完整的 PHP 和 HTML 代码: index.php fomrkey.class.php 将此代码添加到您网站上的每个重要表单中将显着提高表单的安全性。它甚至会停止刷新问题,正如我们在步骤 4 中看到的那样。由于表单密钥仅对一个请求有效,因此不可能进行双重发布。 这是我的第一个教程,希望您喜欢它并使用它来提高您的安全性!请通过评论让我知道您的想法。有更好的方法吗?让我们知道。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!
<form action="" method="post">
<dl>
<?php $formKey->outputKey(); ?>
<dt><label for="username">Username:</label></dt>
<dd><input type="text" name="username" id="username" /></dd>
<dt><label for="username">Password:</label></dt>
<dd>input type="password" name="password" id="password" /></dd>
<dl>
</form>
第 4 步:验证
//The constructor stores the form key (if one exists) in our class variable.
function __construct()
{
//We need the previous key so we store it
if(isset($_SESSION['form_key']))
{
$this->old_formKey = $_SESSION['form_key'];
}
}
//Function that validated the form key POST data
public function validate()
{
//We use the old formKey and not the new generated version
if($_POST['form_key'] == $this->old_formKey)
{
//The key is valid, return true.
return true;
}
else
{
//The key is invalid, return false.
return false;
}
}
$error = 'No error';
//Is request?
if($_SERVER['REQUEST_METHOD'] == 'post')
{
//Validate the form key
if(!isset($_POST['form_key']) || !$formKey->validate())
{
//Form key is invalid, show an error
$error = 'Form key error!';
}
else
{
//Do the rest of your validation here
$error = 'No form key error!';
}
}
<div><?php if($error) { echo($error); } ?></div>
完整代码
<?php
//You can of course choose any name for your class or integrate it in something like a functions or base class
class formKey
{
//Here we store the generated form key
private $formKey;
//Here we store the old form key (more info at step 4)
private $old_formKey;
//The constructor stores the form key (if one excists) in our class variable
function __construct()
{
//We need the previous key so we store it
if(isset($_SESSION['form_key']))
{
$this->old_formKey = $_SESSION['form_key'];
}
}
//Function to generate the form key
private function generateKey()
{
//Get the IP-address of the user
$ip = $_SERVER['REMOTE_ADDR'];
//We use mt_rand() instead of rand() because it is better for generating random numbers.
//We use 'true' to get a longer string.
//See http://www.php.net/mt_rand for a precise description of the function and more examples.
$uniqid = uniqid(mt_rand(), true);
//Return the hash
return md5($ip . $uniqid);
}
//Function to output the form key
public function outputKey()
{
//Generate the key and store it inside the class
$this->formKey = $this->generateKey();
//Store the form key in the session
$_SESSION['form_key'] = $this->formKey;
//Output the form key
echo "<input type='hidden' name='form_key' id='form_key' value='".$this->formKey."' />";
}
//Function that validated the form key POST data
public function validate()
{
//We use the old formKey and not the new generated version
if($_POST['form_key'] == $this->old_formKey)
{
//The key is valid, return true.
return true;
}
else
{
//The key is invalid, return false.
return false;
}
}
}
?>
结论
进一步阅读