php - 使用 PHP 对联系表单 POST 进行服务器端验证,当它应该为真时,秘密返回假
问题描述
所以基本上我有一个使用 mail() 函数发送的联系表,我实现了几个验证,如 reCaptcha 和模式、蜜罐等,它工作得很好,但并不完美,而且客户很挑剔,想要更少的垃圾邮件。现在我正在尝试使用秘密哈希添加服务器端验证,如此处所示https://css-tricks.com/serious-form-security/
我想坚持这样一个事实,即在没有verifyFormToken('form1')
附加条件的情况下一切都可以完美运行。我已经检查过,当我删除第一个条件和最后一个条件时,该函数返回 true,因此它与服务器上的令牌有关。我试图摆脱我认为是完全绕过我的表单/JS并直接发布的最后几封垃圾邮件。我还检查了一些现有问题,包括这个PHP 表单关键错误
require_once './php/recaptcha/src/autoload.php';
$siteKey = 'xxxxx';
$secret = 'xxxxxxxxx';
$name = $_POST['name'];
$email = $_POST['email'];
$telephone = $_POST['telephone'];
$company = $_POST['company'];
$message = $_POST['message'];
$recipient = "sales@xxxx.com";
$formcontent=" From: $name \n Phone: $telephone \n Company: $company \n Message: $message";
$subject = "Contact Form - QUOTE APPLICATION - EN";
$mailheader = "From: $email \r\n";
$recaptcha = new \ReCaptcha\ReCaptcha($secret);
$gRecaptchaResponse = $_POST['g-recaptcha-response']; //google captcha post data
$remoteIp = $_SERVER['REMOTE_ADDR']; //to get user's ip
$resp = $recaptcha->verify($gRecaptchaResponse, $remoteIp); //method to verify captcha
session_start();
function generateFormToken($form) {
$_SESSION[$form.'_token'] = md5(uniqid(microtime(), true));
return $_SESSION[$form.'_token'] ;
}
function verifyFormToken($form) {
if (!isset($_SESSION[$form.'_token'])) { return false;}
if (!isset($_POST['token'])) {return false;}
if ($_SESSION[$form.'_token'] !== $_POST['token']) {return false;}
return true;
}
if(isset($_POST['submit_client'])) {
$newToken = generateFormToken('form1');
$recaptcha = new \ReCaptcha\ReCaptcha($secret);
$gRecaptchaResponse = $_POST['g-recaptcha-response']; //google captcha post data
$remoteIp = $_SERVER['REMOTE_ADDR']; //to get user's ip
$resp = $recaptcha->verify($gRecaptchaResponse, $remoteIp); //method to verify captcha
if (($resp->isSuccess()) && (!empty($name)) && (preg_match("/^[a-zA-Z ]*$/", $name)) && (!empty($telephone)) && (preg_match("/^[0-9-+\s()]*$/", $telephone)) && (!empty($email)) && (preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $email))) {
if (verifyFormToken('form1')) {
mail($recipient, $subject, $formcontent, $mailheader) or die("Error!");
echo '<script language="javascript">alert("Thank you, we\'ll be in touch shortly!");</script>';
}}
else {
die("Error!");
}
}
<form style="position:relative;" class="contact-us-form contact-us-form2" method="POST">
<h2 class="">quote request</h2>
<div style="display:flex;justify-content:center;">
<fieldset>
<input name="name" placeholder="Name*" type="text" tabindex="1" required pattern="[a-zA-Z ]*$" autofocus>
</fieldset>
<fieldset>
<input name="email" placeholder="Email*" type="text" pattern="[A-Za-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$" tabindex="2" required>
</fieldset>
</div>
<div style="display:flex;justify-content:center;">
<fieldset>
<input name="telephone" placeholder="Telephone*" type="text" pattern="[0-9-+\s()]*$" tabindex="3" required>
</fieldset>
<fieldset>
<input name="company" placeholder="Company" type="text" tabindex="4">
<input name="token" type="hidden" value="<?php echo $newToken; ?>">
</fieldset>
</div>
<div style="display:flex;justify-content:center;">
<fieldset>
<textarea name="message" placeholder="Tell us more about your request*" rows="8" cols="30" tabindex="5" required></textarea>
</fieldset>
</div>
<div id="send-captcha-container">
<input name="token" type="hidden" value="<?=$newToken;?>">
<input id="submit-client-button" class="cta contact-form-submit-btn" style="cursor:pointer;border:none!important;" type="submit" name="submit_client" value="send" disabled>
<div class="g-recaptcha" data-callback="recaptcha_callback" data-expired-callback="recaptcha_expired_callback" data-sitekey="6Ldcw70ZAAAAAMkOcdoWhQPn8ey2opCbwRIZJe5M"></div>
</div>
</form>
解决方案
那里有2个错误:
- 第一个错误是您需要一个发送 POST 变量“submit_client”的提交按钮,因为您正在检查它。
- 第二个错误是您必须在验证后制作令牌,因此在发送每个 POST 之前不会对其进行修改
require_once './php/recaptcha/src/autoload.php';
$siteKey = 'xxxxx';
$secret = 'xxxxxxxxx';
$name = $_POST['name'];
$email = $_POST['email'];
$telephone = $_POST['telephone'];
$company = $_POST['company'];
$message = $_POST['message'];
$recipient = "sales@oxoinnovation.com";
$formcontent=" From: $name \n Phone: $telephone \n Company: $company \n Message: $message";
$subject = "Contact Form - QUOTE APPLICATION - EN";
$mailheader = "From: $email \r\n";
$recaptcha = new \ReCaptcha\ReCaptcha($secret);
$gRecaptchaResponse = $_POST['g-recaptcha-response']; //google captcha post data
$remoteIp = $_SERVER['REMOTE_ADDR']; //to get user's ip
$resp = $recaptcha->verify($gRecaptchaResponse, $remoteIp); //method to verify captcha
session_start();
function generateFormToken($form) {
$_SESSION[$form.'_token'] = md5(uniqid(microtime(), true));
return $_SESSION[$form.'_token'] ;
}
function verifyFormToken($form) {
if (!isset($_SESSION[$form.'_token'])) { return false;}
if (!isset($_POST['token'])) {return false;}
if ($_SESSION[$form.'_token'] !== $_POST['token']) {return false;}
return true;
}
if(isset($_POST['submit_client'])) {
/*
Take this out here
*/
// $newToken = generateFormToken('form1');
$recaptcha = new \ReCaptcha\ReCaptcha($secret);
$gRecaptchaResponse = $_POST['g-recaptcha-response']; //google captcha post data
$remoteIp = $_SERVER['REMOTE_ADDR']; //to get user's ip
$resp = $recaptcha->verify($gRecaptchaResponse, $remoteIp); //method to verify captcha
if (($resp->isSuccess()) && (!empty($name)) && (preg_match("/^[a-zA-Z ]*$/", $name)) && (!empty($telephone)) && (preg_match("/^[0-9-+\s()]*$/", $telephone)) && (!empty($email)) && (preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $email))) {
if (verifyFormToken('form1')) {
mail($recipient, $subject, $formcontent, $mailheader) or die("Error!");
echo '<script language="javascript">alert("Thank you, we\'ll be in touch shortly!");</script>';
}}
else {
die("Error!");
}
}
/*
and put it here
*/
$newToken = generateFormToken('form1');