【问题标题】:PHP: Let user download purchased file ONLYPHP:让用户只下载购买的文件
【发布时间】:2012-09-24 23:35:01
【问题描述】:

我预见到允许通过 PayPal 从我这里购买某些内容的客户会出现问题。我将提供多种无形商品。当有人完成对其中一种商品的购买时,他们将被重定向到一个登陆页面——我们称之为“thank_you.php”——它将自动排队下载并允许链接排队下载以防万一自动启动。这将通过将唯一的项目 ID 传递给下载页面(“download.php”)来完成。

这种方法本质上是对这些主题的热门答案的模仿:

PHP generate file for download then redirect

A PHP script to let users download a file from my website without revealing the actual file link in my website?

但是,我担心一旦用户在“thank_you.php”上他们可以下载他们的项目,然后使用 Firebug(或等效)编辑项目 ID 并下载另一个不同的项目:

<a href="download.php/38a205ec300a3874c867b9db25f47c61">Download Here</a>

<a href="download.php/7c8ddc86c0e4c14517b9439c599f9957">Download Here</a>

我需要在这方面比我更擅长的人的想法和帮助:我可以实施什么(以及如何)作为一种解决方案,仍然允许相同的客户访问和休闲,同时防止这种操纵?

编辑:ID 哈希用于在整个站点中预览和引用项目,我不怕人们猜测,而是他们在单独的选项卡中浏览站点以获取其他 ID并继续下载不同的项目。

【问题讨论】:

  • ...他们怎么会知道 7c8ddc86c0e4c14517b9439c599f9957?
  • 这不是很明显ceejay吗?这是我想到的第一个哈希
  • 你的哈希对应的是什么?例如它们是针对特定文件的,还是由用户、文件等构建的?无论如何,听起来你好像害怕有人猜测一个有效的随机散列。 . .除非您想定时炸弹散列并导致它们过期,否则这听起来像是您必须处理的事情?
  • 项目 ID 是对整个站点中项目的唯一引用 - 虽然它不应该突出显示,但它会不时传递给客户。例如,当显示“立即购买”页面时,ID 在标题中(premium.php/[itemID])。
  • 嗯,右键->复制链接,粘贴,然后任何人都可以使用链接。 . .听起来好像您需要在身份验证方案(用户名?)中至少再添加一层,或者链接一旦使用就会过期。

标签: php redirect download client-side


【解决方案1】:

虽然这些其他答案假设您有一个带有用户名的会话,但听起来好像您刚刚为文件创建了一个哈希以隐藏文件名。换句话说,您不妨在键盘上放一把猴锤,并将其作为您拥有的每个文件的文件名。

然后听起来您担心用户会过来,敲击键盘,并以某种方式最终与您的猴子所做的完全匹配。这不太可能。

更有可能有人会复制并粘贴您的链接并进行分享。听起来好像您需要在您的身份验证方案中至少再添加一层(例如,对用户名和项目 ID 进行哈希处理),或者让链接在使用后过期。

从您的评论看来,您似乎也在使用哈希来识别您网站另一部分的项目,这意味着用户可以通过查看您网站另一部分的源来确定项目的哈希网站。在这一点上,你通过默默无闻的安全很像我在与某人闲聊并说“鱼和猫正在亲热”时使用暗语(例如“鱼意味着约翰,猫意味着丽莎”),同时拥有一张纸旁边的纸上写下任何人都可以看到的映射。听起来您只是想隐藏文件名,以免人们猜到它们。这被称为security through obscurity,并没有真正让你买太多。

大多数其他答案都假设一个项目存在,并且它将有多个不同的哈希指向它(例如,file1 将具有 hash1、hash2 和 hash3 都是指向它的有效链接)。在这种情况下,他们创建了多个哈希,并且每个哈希对于某个用户 + 项目都是唯一的。我认为他们还假设网站上的每个人都将下载项目称为item1 而不是hash1,这听起来像你在做什么?

您最好在代码中的某处创建一个字典,其中包含项目名称和哈希之间的映射,然后仅在下载页面上,用哈希代替名称。同样,这只是通过默默无闻的安全性,可以共享链接,但人们无法仅在浏览您的网站时获得哈希。

【讨论】:

  • 我真的不太担心人们猜测哈希值。此外,我担心人们会收集其他项目的哈希值,然后简单地复制-> 无限次粘贴原始项目以继续下载不同的项目。我正在寻求帮助以获取我缺少的安全层。
  • @JeremyBuller 是的,所以使用哈希的目的是在网站的其他任何地方,您将项目称为item1。您应该使用哈希的唯一地方是下载链接。
  • 啊,我明白了。 Theraot 和 Ben Griffins 之前说过,我想可能是这样。您看到的哈希是我使用的实际项目标识符;所以我应该使用随机散列(以及一个时间戳 + x 作为到期日期)来仅在我的收据表中引用该购买。
【解决方案2】:

我原来的答案:

您需要存储(在数据库或会话变量中)用户可以访问的项目,您将为每个项目生成一个唯一的随机令牌。该令牌将用于识别购买的物品。将令牌传递到他们将能够下载的页面(在会话变量、POST 参数中,或者作为 url 中的最后一个选项,即 GET)。在您需要下载的页面中,您将使用会话信息查询数据库/会话变量,以识别客户和传递的令牌(但您是如何传递的)并检索要下载的文件。

如果您需要保留已购买项目的列表以供重新下载,您也可以这样做,但请记住在用户请求下载时再次创建令牌。如果您愿意,还可以添加到期日期。


现在我已经提到了几个替代方案,然后再次根据引用答案的性质,我想您需要更多关于如何做到这一点的详细信息。

也许 ernie 是对的,我不应该假设你有一个会话。也许我应该向您展示如何进行会话。

所以我会采取其中一种方案来实现,最简单的方案。


<?php
    //Oh, I'm in a PHP page...
    //check if there is not a session
    if (session_id() != '')
    {
        //Ok, there is no session, let's create one
        session_start();
    }
    //Now we are sure there is a session
    //Let's store in the session the id of the file I want to allow to download
    $_SESSION['download'] = GetFileId();
    //GetFileId will do some mambo jambo expecto patronum to return an id
    //The id will be 38a205ec300a3874c867b9db25f47c61 or something
?>

现在在下载页面....

<?php
    //Oh, I'm in another PHP page...
    //check if there is not a session
    if (session_id() != '')
    {
        //no session? screw you, no download for you
        header('Location: sorry.php');
    }
    else
    {
        //Now we are sure there is a session
        //Let's get from the session the id of the file I want to allow to download
        $id = $_SESSION['download'];
        //Now get the url to redirect to allow the download
        $url = GetUrl($id);
        //GetUrl will do some mambo jambo expecto patronum to return an url
        //Ok, now we are going to return that file...
        //So put the correct MIME type
        header('content-type: image/gif');  //if it is a gif...
        //Load the file
        $contents = file_get_contents($url); 
        echo $contents;
        //That's the only output
        exit();
     }
?>

请注意我只允许从 PHP 访问该文件,因此我可以先验证用户是否具有访问权限。您不应该允许用户只输入 url(即使他猜不到)并访问文件。因此,如果您正在运行您的服务器,您希望将这些文件放在服务器 Web 文件夹之外,或者如果您使用的是使用 .htaccess(或您的主机提供的其他机制)保护它们的主机。


对此解决方案的评论:

它很简单,易于实施。但它也有一些缺点:

  • 如果会话在下载前终止,用户将损失金钱*。
  • 没有明确的方法实现重新下载。
  • 它仍然容易受到会话劫持的攻击(我知道这很牵强,但最好是安全的)。

*:假设连接丢失,并且会话在客户端过期。哦,不,我们不需要满意的客户。

所以,你真的,真的,需要用数据库备份它并创建随机令牌,最好有一个到期日期。

【讨论】:

  • 实际上,您的第一个答案几乎就是我需要的解决方案 - 在收据表中,生成一个新的随机字符串作为该购买的 id,而不是使用商品的 id。我只选择了 Ben Griffin 的答案,因为他最先回答,但你们俩都是对的。
【解决方案3】:

当他们付款时,将可用的下载 ID 和随机哈希存储在付款表中。使用 that 哈希然后获取 ID。然后,哈希不应与特定产品相关,而应与付款相关。

【讨论】:

  • 你说得对——这就是我缺少的安全层。这应该允许人们仍然购买它 - 无需注册,我想唯一的利用将是人们在哈希的生命周期内共享链接(这没什么大不了的,我不相信人们会叫嚣从免费下载我)。非常感谢您的快速回复。
【解决方案4】:

您可以实现的最简单的事情之一是跟踪用户购买的日志系统。您可以将请求的 ID 与存储的与用户购买相关的 ID 交叉引用。如果它们不相关,则不要提供文件。

【讨论】:

  • 非常感谢您的回复,不幸的是我知道很多人真的很讨厌“注册”越来越多的网站;因此,我真的很想让拥有有效 PayPal 帐户的“客人”可以使用它。
  • 好吧,为什么不让 id 读取一次,然后删除呢?比如,说他们想要music.mp3。您使用 random4356string 或其他哈希值存储与 music.mp3 的数据库关系,然后当下载发生一次时,从数据库中删除该关系或将其设置为已使用状态。如果用户需要恢复它,也许他们需要联系您并提供原始哈希
【解决方案5】:

您需要跟踪用户在数据库中购买了哪些商品。然后 download.php 可以检查用户是否购买了他们正在尝试下载的项目。

【讨论】:

  • 这会禁止“客人”购买和下载吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-02
  • 1970-01-01
  • 2014-11-15
相关资源
最近更新 更多