如何安全地从链接获取变量


How to securely get variables from a link?

假设一个网站xyz.com正在使用JavaScript代码显示来自我的广告网络example.com的广告:

<script type='text/javascript' src='http://example.com/click.php?id=12345678'></script>

广告显示为:

click.php
<a href="http://example.com/process.php?var1=var1&var2=var2">
<img src="http://example.com/ads/banner.png"/></a>

当链接被点击时,它被带到process.php,在那里我使用一些MySQL查询添加和减去余额,然后重定向到广告的URL。

process.php
$ua = $_SERVER['HTTP_USER_AGENT'];
$ip = $_SERVER['REMOTE_ADDR'];
//invalid click
if($_SERVER['HTTP_REFERER']==null || $_SERVER['HTTP_USER_AGENT']==null) {
header("location: http://example.com");
exit;
}

我想在click.php添加到唯一会话,并在process.php检索它,以防止无效单击。我该怎么做?

更新:下面的答案解决了一半的问题,但用户仍然可以使用iframe和img标签发送虚假点击,如下所示:

<img src="http://example.com/click.php?id=12345678" height="1px" width="1px"/>

这些点击仍然被计算为请求由页面click.phpprocess.php 提供

解决方案是什么?

我已经找到了这个问题的解决方案,它运行得很好:编辑:我找到了一个解决方案:使用会话在click.php设置变量,并使用随机数将其发送到process.php

click.php
$_SESSION["ip"]=$ip;
$_SESSION["ua"]=$ua;
$rand="".rand(1,9)."".rand(0,9)."".rand(0,9)."".rand(0,9)."".rand(0,9)."".rand(0,9)."";
$_SESSION["hash"]=$rand;
<a href="http://example.com/process.php?hash=$rand">
<img src="http://example.com/ads/banner.png"/></a>

并从process.php 的会话中获取值

process.php
$hash=$_GET["hash"];
$ua=$_SESSION["ua"];
$ip=$_SESSION["ip"];
$rand=$_SESSION["hash"];
// Invalid Redirection Protection
if(($hash!=$rand) || ($ip!=$_SERVER['REMOTE_ADDR']) || ($ua!=$_SERVER['HTTP_USER_AGENT'])) {
header("location: http://example.com");
session_destroy();
exit;
}

如果我理解您的问题,您的目标是确保http://example.com/process.php来自创建的链接http://example.com/click.php

(请注意,这只意味着任何试图颠覆您系统的人都需要获取http://example.com/click.php并在提取之前提取相关数据http://example.com/process.php.它稍微提高了标准,但离万无一失还有很长的路要走)。

PHP已经有了一个非常好的会话机制。通过嵌入在脚本输出中的url来适应传播是很容易的(因为你不能依赖于可用的cookie)。然而,由于它依赖于对存储的写入,因此它的可扩展性不是很好。

我会选择一个具有有限数量的可预测好状态(以及更多数量的坏状态)的代币。这意味着使用某种加密。虽然对称密码将为提供最容易理解的模型,但它比基于哈希的模型更难实现。

使用散列模型,您可以用一个秘密salt对已经发送的值进行散列,并将散列包含在请求中。然后在接收端,重复该练习,并将生成的哈希与发送的哈希进行比较。

为了防止重复提交,您需要在请求变量中使用一些其他标识符——一个大的随机数、客户端IP地址、时间。。。。

define('SALT','4387trog83754kla');
function mk_protected_url($url)
{
    $parts=parse_url($url);
    $args=parse_str($parts['query']);
    $args['timenow']=time();
    $args['rand']=rand(1000,30000);
    sort($args);
    $q=http_build_query($args);
    $args['hash']=sha1(SALT . $q);
    $q=http_build_query($args);
    return $parts['scheme'] . '://'
        .$parts['host'] . '/'
        .$parts['path'] . '?' . $q;
}
function chk_protected_url($url)
{
    $parts=parse_url($url);
    $args=parse_str($parts['query']);
    $hash=$args['hash'];
    unset($args['hash'];
    // you might also want to validate other values in the query such as the age
    $q=http_build_query($args);
    $check=sha1(SALT . $q);
    return ($hash === $check)
 }