如果我理解正确,此任务不需要验证码。
我假设你想看看用户是否点击了自己,坐在他的电脑前。
新想法
在您的表单上提交多个图像:
<input type="image" name="send1" src="buttons.php?i=1" />
...
<input type="image" name="send8" src="buttons.php?i=8" />
在生成表单时,获取一个介于 1 和 8 之间的随机数并将其保存在 $_SESSION['submitnumber'] 中。
创建两个相同大小的图像 - 一个空的填充了您在表单中的默认背景,另一个看起来像一个提交按钮。
创建将使用此代码输出图像的buttons.php:
header("Content-Type: image/jpeg");
flush();
readfile($filename);
如果$_GET[i]!=$_SESSION['submitnumber']返回空图像,否则返回提交图像。
如果点击了正确的图片提交,则接受表单(当用户点击按钮时,浏览器将向您发送类似 send1X 的坐标)
这是一种验证码,但人们不会知道;)
老想法
你需要两件事:
1为非常独特的表单生成令牌。
输入<input type="hidden" name="timertoken" value="someweirdstring" />
并将“someweirdstring”生成为某些(用户名和时间)相关事物的 md5 哈希。我可以详细说明一下,但这是用于安全和 CSRF 攻击阻止的基本形式令牌。发布后验证令牌。
示例:
这不是令牌机制的典型实现,但已经足够了。
$token=generatesomerandomtext();
$_SESSION['token']=$token;
//... somewhere later when outputing forms:
echo '<input type="hidden" name="token" value="'.$token.'" />';
//and when it comes back:
if($_POST['token']==$_SESSION['token']) {
//it's ok
}
这就是你所需要的。
这个简单的示例为每个页面创建一个唯一的令牌并放入表单。它不依赖于时间并且不使用 md5,而是将令牌存储在会话中。要自动发送将被接受的表单,此人必须使用您生成的表单或复制令牌。
真正的形式令牌示例将更像这样:
$token=md5($username.'一些密文'.$date.$timeRoundedTo10Minutes);
//... somewhere later when outputing forms:
echo '<input type="hidden" name="token" value="'.$token.'" />';
//and when it comes back:
if(
($_POST['token']==md5($username.'some secret text'.$date.$timeRoundedTo10Minutes)) ||
($_POST['token']==md5($username.'some secret text'.$date.$timeRoundedTo10Minutes-10minutes)) ) {
//it's ok
}
为什么是用户名?因为它消除了使用一个用户的令牌来破解另一个用户的可能性
为什么是秘密文本(称为“盐”)?因为有人可以将其他用户的名字与时间粘在一起并执行 md5,但无需猜测他不能猜到的盐。
为什么要进行两次比较?因为如果现在是 22:44:59 - 令牌是在 22:40 生成的,如果用户发送它是 22:45:30,所以它会四舍五入到 22:50,并且只有当你收回 10 分钟时它才匹配令牌.
这就是一个基本示例。如需参考,请参阅this 问题。
2 将您的提交按钮更改为<input type="image" ...,因为它会发布按钮单击位置的 x 和 y 坐标。我不知道谁在规范中提出了这个,但这是第一次可以使用它! :)
现在看看用户是否点击了自己你只需要看看坐标是否存在(经典提交不会发送它们)并阻止简单的黑客攻击你还可以记住玩家会话中的最后一个 x 和 y 并进行比较.破解它以每次发送不同的坐标要困难得多。
表单标记用于防止用户准备带有随机字段的表单副本,这些字段会模拟点击坐标。如果令牌每次都更改,则很难覆盖表单字段。
这仍然可以通过用户脚本功能破解,但要困难得多。如果您在一小时内添加一次验证码,那么没有人会费心编写仅能帮助一个小时并在此之后中断的脚本(并且需要一些努力和知识)。