【发布时间】:2015-11-11 08:27:25
【问题描述】:
有史以来第一次尝试实现 CSRF 令牌......
我有一个内部$_SERVER["REQUEST_METHOD"] 表单...
网上的大部分内容都是通过_$POST php 表单完成的...
所以...在阅读完所有内容后,我认为既然我在内部拥有它,我应该在那里设置令牌...
所以这就是我所做的......但显然我在这里误解了一些东西,因为它不起作用......不仅仅是误解......我也不确定我应该做什么......所以...如果您能解释我应该做什么,以便我可以正确设置...我将不胜感激
<?php
session_start(); //allows use of session variables
$token = md5(uniqid(rand(), TRUE));
$_SESSION['token'] = $token;
$_SESSION['token_time'] = time();
if ($_SERVER["REQUEST_METHOD"] == "POST") {
if (empty($_POST["first-name"])) {
$firstNameErr = "First name is required";
} else {
$first_name = test_input($_POST["first-name"]);
}
if (empty($_POST["last-name"])) {
$lastNameErr = "Last name is required";
} else {
$last_name = test_input($_POST["last-name"]);
}
if (empty($_POST["email"])) {
$emailErr = "Email is required";
} else {
$email = test_input($_POST["email"]);
}
if (empty($_POST["message"])) {
$messageErr = "Message is required";
} else {
$message = test_input($_POST["message"]);
}
if(isset($first_name) && isset($last_name) && isset($email) && isset($message) && isset($token))
{
$_SESSION['first_name'] = $first_name;
$_SESSION['last_name'] = $last_name;
$_SESSION['email'] = $email;
$_SESSION['message'] = $message;
$_SESSION['token'] = $token;
header("Location: SessionsCRSF.php");
}
}
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
?>
在同一页面上是表单(放置一个 sn-p,但你明白了):
<form class="ui form" method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
<input type="hidden" name="token" value="<?php echo $token; ?>" />
<div class="field">
<label>First Name</label>
<input name="first-name" id="first-name" placeholder="First Name" type="text" value="<?php if(isset($first_name)) { echo $first_name; }?>">
<?php if(isset($firstNameErr)) print ('<span class="error">* ' . $firstNameErr . '</span>'); ?>
</div>
(...)
</form>
但我不知道如何通过您在标题中看到的SessionsCRSF.php 表单对其进行测试...
这是SessionsCRSF.php 表单的 sn-p,因为其余的只是 PHPMailer 的东西:
<?php
session_start();
if ($_POST['token'] == $_SESSION['token'])
{
die('working, yay?');
}
$first_name = $_SESSION['first-name'];
$last_name = $_SESSION['last-name'];
$email = $_SESSION['email'];
$message = nl2br($_SESSION['message']);
require 'PHPMailerAutoload.php';
$mail = new PHPMailer;
已编辑
好的,所以..这就是我目前所拥有的:
<?php
session_start(); //allows use of session variables
if ($_SERVER["REQUEST_METHOD"] == "POST" && $_SESSION['token'] == $_POST['token'] && !empty($_SESSION['token'])) {
if (empty($_POST["first-name"])) {
$firstNameErr = "First name is required";
} else {
$first_name = test_input($_POST["first-name"]);
}
if (empty($_POST["last-name"])) {
$lastNameErr = "Last name is required";
} else {
$last_name = test_input($_POST["last-name"]);
}
if (empty($_POST["email"])) {
$emailErr = "Email is required";
} else {
$email = test_input($_POST["email"]);
}
if (empty($_POST["message"])) {
$messageErr = "Message is required";
} else {
$message = test_input($_POST["message"]);
}
if(isset($first_name) && isset($last_name) && isset($email) && isset($message))
{
$_SESSION['first_name'] = $first_name;
$_SESSION['last_name'] = $last_name;
$_SESSION['email'] = $email;
$_SESSION['message'] = $message;
header("Location: contact9SessionsCRSF2.php");
exit;
}
}
else {
$token = md5(uniqid(rand(), TRUE));
$_SESSION['token'] = $token;
$_SESSION['token_time'] = time();
}
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
?>
【问题讨论】:
-
你没有发布到 SessionsCRSF.php 所以
if ($_POST['token'] == $_SESSION['token'])不可能工作,因为$_POST['token']变量不存在。至少,这会让你的测试失败。 -
@JoeRose,我认为它是通过
test_input上面的函数发布的......然后标题将它带到SessionCRSF.php?我不知道......我该如何让它工作?我的意思是,这不是$_POST,对吧?但更多的是$_SESSION?那么,我应该写这个而不是if ($_SESSION['token'] == $_SESSION['token'])?如果您能解释一下我是如何完成这项工作的,我将不胜感激! =) -
我认为更好的方法是创建一个处理 CRSF 的类,然后将发布的令牌和会话令牌传递给该类,然后返回它是否有效,并且然后您的当前页面可以根据此响应执行一些代码(例如再次显示该页面并为用户显示错误消息)。如果你不想写一个类,你可以在 link 找到一个很好的类,你可以将它添加到你的应用程序中(我在搜索 CSRF 时看到了一堆结果)。
-
@JoeRose,好吧,我认为根据这篇文章实现一个 CSRF 令牌相对简单:shiflett.org/articles/cross-site-request-forgeries ... 如果我能那样做,我愿意。我真的不想写一个类,也不想依赖外部脚本,因为这是出于商业目的,我希望维护它,所以如果可能的话,我想了解我在这里做什么。耸耸肩。
-
在这种情况下,为什么不直接发布到当前页面,验证当前页面上的令牌(可以访问
$token和$_POST['token']变量,检查匹配,然后执行基于此,而不是使用外部页面。如果令牌不正确并且需要重新显示页面,您可以将会话中的表单数据回显到表单字段中(确保使用标题重定向到同一页面以消除重新提交表单的可能性),或者如果令牌正确,您可以执行 PHPMailer 代码,然后重定向到成功页面。
标签: php forms csrf csrf-protection