【问题标题】:Only display content if loaded from within a frame from specific domains?仅在从特定域的框架内加载时才显示内容?
【发布时间】:2014-10-26 15:47:09
【问题描述】:

关于框架检测的大多数问题似乎都来自希望防止他们的网站出现在框架内的人。但是,我试图找到一种方法来拒绝显示特定的 php 页面,除非它在 ​​frame 中。一个警告是 iframe 和主页位于不同的域上。

domain1.com/index.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Site/title>
        <meta name="viewport" content="width=device-width,minimum-scale=1.0">
        <meta HTTP-EQUIV="Pragma" CONTENT="no-cache">
        <meta HTTP-EQUIV="Expires" CONTENT="-1">
    </head>
    <body>
        <div id="content">
            <iframe width="100%" height="100%" frameborder="0" src="http://domain2.com/browse.php" />   
        </div>
    </body>
</html>

我尝试了以下验证方式:

  • 查看 domain2.com/browse.php 中的 REFERER 信息,看看它是否已从 domain1.com/index.php 中引用。这取得了有限的成功,因为我每天记录了大约 1,000 名禁用引荐信息的访问者

  • 将用户的 IP 地址作为加密查询字符串的一部分从 domain1.com/index.php 传递到 domain2.com/browse.php。这也取得了有限的成功,但我认为缓存(尽管我尝试禁用它)导致 index.php 将旧的加密查询字符串传递给具有过时 IP 地址的 browse.php。

理想情况下,我想知道 domain2.com/browse.php 是否在 domain1.com/index.php 中加载,但如果这不可能,我希望 browse.php 不显示内容如果它不在 iframe 中。

帮助非常感谢

【问题讨论】:

  • 这需要有多安全?
  • 不太像我希望browse.php在没有iframe的情况下提供不同的内容,隐藏了他们基本上被拒绝直接访问browse.php的事实

标签: php html session iframe referer


【解决方案1】:

您在问题中使用了 PHP 标记。为什么不用 PHP 来包含外部页面:

<?php

// get doc from url
$doc = new DOMDocument;
$doc->loadhtmlfile('http://bitinfocharts.com/x11coin/');

function getElements($tagName,$stripTag = FALSE)
// echo all these elements in direct succession
{
  global $doc;
  $elements = $doc->getElementsByTagName($tagName);
  foreach ($elements as $node)
  {
    $html = $doc->savehtml($node);
    if ($stripTag)
    {
      $html = substr($html,strpos($html,'>')+1);
      $html = substr($html,0,strrpos($html,'<'));
    }
    echo $html;
  }
}

?><!doctype html>
<html lang=en>
    <head>
        <title>Site</title>
        <meta name="viewport" content="width=device-width,minimum-scale=1.0">
        <meta HTTP-EQUIV="Pragma" CONTENT="no-cache">
        <meta HTTP-EQUIV="Expires" CONTENT="-1">
        <?php echo '        <base href="'.$url.'">'.PHP_EOL; ?>
        <?php echo '        '; getElements('link'); ?>
        <?php echo '        '; getElements('script'); ?>
        <?php echo '        '; getElements('style'); ?>
    </head>
    <body>
        <div id="content">
           <?php getElements('body',TRUE); ?>
        </div>
    </body>
</html>

我不是说这是完美的,我也不知道这是你想要的,但它很好地隐藏了外部来源。密码保护,任何人都无法加载。

您坚持使用&lt;iframe&gt;。你可以做的是用一个简单的本地 php 文件检索外部文件,你猜对了,file_get_contents(),然后回显它。您需要添加到内容中的只是&lt;base&gt; 标签。这有什么帮助?两点:

  1. 您现在可以限制从您的外部服务器下载到您希望允许下载的服务器。
  2. 该服务器恰好是您的&lt;iframe&gt; 页面所在的服务器。您可以在提供他们刚刚下载的&lt;iframe&gt; 页面的&lt;iframe&gt; 内容之前检查该服务器。

因此您不需要服务器之间的任何通信来验证下载。请确保&lt;iframe&gt; 页面未被缓存!

(抱歉修改了这么多,不过这个编辑器有点怪。)

【讨论】:

  • 尽管我很想这样做,但 iframed 页面中的内容需要保留在 iframe 中,因为其上的 javascript 检查以确保它是从 domain2.com 运行的。我是否正确地说上面的方法与 $content = file_get_contents('http://domain2.com/browse.php') 减去包含基本 href 的方法非常相似?
  • 不,它与file_get_contents() 不太一样。我删除了页面中已经存在的所有位(、 等),并包括所有需要的位,例如
  • 啊,是的,对不起,我现在看到了。非常方便的代码,但会等待您的其他解决方案,看看它是否符合我的“从 domain2.com 运行”要求。
  • 刚刚看到您的编辑。我无法完全理解这将如何工作? domain2.com 上的内容“知道”它从哪里运行(基本上是它的 JS 广告和统计脚本),并且仍然需要从 domain2.com 运行。通过从 file_get_contents() 回显它 - 即使使用 标头,这不会使验证失败吗?
  • 啊,是的,那会是个问题。如果您想将文件保留在 domain2.com 上,并且仍然使用时间戳,如我的第二个答案中所述,您可以让它从 domain1.com 询问时间。只需用这个非常短的脚本在上面放一个文件:&lt;?php echo time(); ?&gt;。您必须这样做,因为您永远无法确定时钟是否同步。
【解决方案2】:

所以,我的想法是在本地下载外部页面。让我们将此本地页面称为“本地”。让我们在'`'IFRAME'中调用它将被加载到的页面。

您限制将外部页面下载到 LOCAL 所在的服务器。

验证用户是否有权查看 LOCAL 的最简单方法是使用编码时间戳。所以当服务器生成 IFRAME 时,它只是在 LOCAL 的 URL 上放置一个编码的时间戳。为什么要编码?因为它不应该太明显它是什么,并且您需要能够在 LOCAL 中对其进行解码。

那么首先是生成编码时间戳的方式:

$code = urlencode(gzencode(time()));

在 LOCAL 中我们将使用相反的:

$timestamp = gzdecode(urldecode($code)));

请测试这些例程,urldecode() 可能已在您的服务器上应用。如果您想让黑客更难猜测发生了什么,您可以使这些编码和解码例程更加复杂。

现在,在您的 LOCAL 文件中,您首先需要检查您获得的时间戳确实是一个数字并且不是太旧:

if (is_numeric($timestamp)) $age = abs(time()-$timestamp); 
                       else $age = 99999999;

例如,如果内容超过 5 分钟,您可以提供一个空白页面。不要忘记在 LOCAL 中设置 &lt;base&gt; 标签,您可以使用 DOM 类,就像我之前的回答一样。或者,您可以将所有相对链接设为绝对链接。

这个想法有一个明显的缺点。可能有一些 JavaScript 依赖于它们在外部服务器上运行的事实。在这种情况下,它们不会,这可能会破坏它们。

(为什么我会打这么多错字?)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多