169

我在服务器上有我的网站http://www.myserver.uk.com

在这台服务器上,我有两个域:

one.com and two.com

我想使用 PHP 获取当前域,但如果我使用,$_SERVER['HTTP_HOST']那么它会显示给我

myserver.uk.com

代替:

one.com or two.com

如何获取域,而不是服务器名称?

4

9 回答 9

202

尝试使用这个:

$_SERVER['SERVER_NAME']

或解析:

$_SERVER['REQUEST_URI']

参考:apache_request_headers()

于 2012-05-23T09:41:05.637 回答
80

最好的用途是

echo $_SERVER['HTTP_HOST'];

它可以像这样使用:

if (strpos($_SERVER['HTTP_HOST'], 'banana.com') !== false) {
    echo "Yes this is indeed the banana.com domain";
}

下面的代码是在结构化 HTML 输出中查看 $_SERVER 中所有变量的好方法,其中突出显示的关键字在执行后立即停止。因为我有时会忘记自己使用哪一个 - 我认为这可能很漂亮。

<?php
    // Change banana.com to the domain you were looking for..
    $wordToHighlight = "banana.com";
    $serverVarHighlighted = str_replace( $wordToHighlight, '<span style=\'background-color:#883399; color: #FFFFFF;\'>'. $wordToHighlight .'</span>',  $_SERVER );
    echo "<pre>";
    print_r($serverVarHighlighted);
    echo "</pre>";
    exit();
?>
于 2013-05-05T15:54:16.440 回答
62

这样做的唯一安全方法

检索当前域的唯一有保证的安全方法是将其存储在自己的安全位置。

大多数框架都会为您存储域,因此您需要查阅特定框架的文档。如果您不使用框架,请考虑将域存储在以下位置之一:

   存储域的安全方法</th>   使用者
一个配置文件</td> Joomla , Drupal / Symfony
数据库</td> WordPress
环境变量 Laravel  </td>
服务注册中心</td> Kubernetes DNS

以下工作......但它们并不安全

黑客可以使以下变量输出他们想要的任何域。这可能导致缓存中毒和几乎不明显的网络钓鱼攻击。

$_SERVER['HTTP_HOST']

这会从对黑客开放的请求标头中获取域。与:

$_SERVER['SERVER_NAME']

如果 Apache 设置usecanonicalname关闭,这个可以做得更好;在这种情况下,$_SERVER['SERVER_NAME']将不再允许使用任意值填充并且将是安全的。但是,这不是默认设置,也不是常见的设置。

在流行的系统中

以下是如何在以下框架/系统中获取当前域:

WordPress

$urlparts = parse_url(home_url());
$domain = $urlparts['host'];

如果您在 WordPress 中构建 URL,只需使用home_urlsite_url或任何其他 URL 函数

拉拉维尔

request()->getHost()

request()->getHost功能继承自 Symfony,自 2013 CVE-2013-4752补丁以来一直是安全的。

德鲁巴

安装程序尚未确保此安全(问题 #2404259)。但是在 Drupal 8 中,您可以在受信任的主机设置中遵循文档来保护您的 Drupal 安装,之后可以使用以下内容:

\Drupal::request()->getHost();

其他框架

随意编辑此答案以包括如何在您喜欢的框架中获取当前域。执行此操作时,请包含指向相关源代码或任何其他有助于我验证框架是否安全运行的链接的链接。


附录

开发示例:

  1. 如果僵尸网络不断地使用错误的主机头请求页面,则可能发生缓存中毒。然后,生成的 HTML 将包含指向攻击者网站的链接,他们可以在其中对您的用户进行网络钓鱼。起初恶意链接只会被发回给黑客,但如果黑客做了足够多的请求,页面的恶意版本最终会在你的缓存中分发给其他用户。

  2. 如果您根据主机标头将链接存储在数据库中,则可能发生网络钓鱼攻击。例如,假设您将绝对 URL 存储到论坛上用户的个人资料。通过使用错误的标题,黑客可以让任何点击其个人资料链接的人被发送到钓鱼网站。

  3. 如果黑客在为其他用户填写密码重置表单时使用恶意主机标头,则可能发生密码重置中毒。然后,该用户将收到一封电子邮件,其中包含指向网络钓鱼站点的密码重置链接。另一种更复杂的形式通过让电子邮件退回并重新发送到黑客的一个 SMTP 服务器(例如 CVE-2017-8295)来跳过用户必须做的任何事情。

  4. 这里有一些更恶意的例子

其他注意事项和注意事项:

  • usecanonicalname关闭时,将使用$_SERVER['SERVER_NAME']相同的标头填充$_SERVER['HTTP_HOST'](加上端口)。这是 Apache 的默认设置。如果您或 DevOps 将其打开,那么您就可以了 - 是的 - 但您是否真的想依赖一个单独的团队,或者三年后的您自己,以保持看起来像次要配置的非-默认值?尽管这使事情变得安全,但我会警告不要依赖此设置。
  • 然而,Red Hat 在默认情况下确实打开了 usecanonical [ source ]。
  • 如果在虚拟主机条目中使用了serverAlias,并且请求了别名域,$_SERVER['SERVER_NAME']则不会返回当前域,而是返回 serverName 指令的值。
  • 如果无法解析 serverName,则使用操作系统的 hostname 命令代替[source]
  • 如果主机头被遗漏,服务器将表现得好像 usecanonical 在[source]上。
  • 最后,我只是尝试在我的本地服务器上利用它,但无法欺骗主机头。我不确定 Apache 是否有解决此问题的更新,或者我是否只是做错了什么。无论如何,在不使用虚拟主机的环境中,此标头仍然可以利用。

一点咆哮:

     这个问题获得了数十万的关注,却没有提到手头的安全问题!不应该这样,但仅仅因为 Stack Overflow 答案很受欢迎,这并不意味着它是安全的。



于 2018-05-11T23:56:27.980 回答
41

使用$_SERVER['HTTP_HOST']得到我(子域。)maindomain.extension。对我来说,这似乎是最简单的解决方案。

如果您实际上是通过 iFrame 进行“重定向”,则可以添加一个GET参数来说明域。

<iframe src="myserver.uk.com?domain=one.com"/>

然后您可以设置一个会话变量,在整个应用程序中保留这些数据。

于 2013-04-15T10:45:32.607 回答
10

试试$_SERVER['SERVER_NAME']

提示:创建一个调用该函数的 PHP 文件phpinfo()并查看“PHP 变量”部分。那里有很多我们从未想过的有用变量。

于 2012-05-23T09:40:05.077 回答
5

要获取域:

$_SERVER['HTTP_HOST'] 

带协议的域:

$protocol = strpos(strtolower($_SERVER['SERVER_PROTOCOL']), 'https') === FALSE ? 'http' : 'https';
$domainLink = $protocol . '://' . $_SERVER['HTTP_HOST'];

协议、域和 queryString 总数:

$url = $protocol . '://' . $_SERVER['HTTP_HOST'] . '?' . $_SERVER['QUERY_STRING'];

**由于 $_SERVER['SERVER_NAME'] 对于多域托管不可靠!

于 2019-08-09T08:39:38.910 回答
3

每个人都在使用该parse_url函数,但有时用户可能会以不同的格式传递参数。

为了解决这个问题,我创建了一个函数。看一下这个:

function fixDomainName($url='')
{
    $strToLower = strtolower(trim($url));
    $httpPregReplace = preg_replace('/^http:\/\//i', '', $strToLower);
    $httpsPregReplace = preg_replace('/^https:\/\//i', '', $httpPregReplace);
    $wwwPregReplace = preg_replace('/^www\./i', '', $httpsPregReplace);
    $explodeToArray = explode('/', $wwwPregReplace);
    $finalDomainName = trim($explodeToArray[0]);
    return $finalDomainName;
}

只需传递 URL 并获取域。

例如,

echo fixDomainName('https://stackoverflow.com');

将返回:

stackoverflow.com

在某些情况下:

echo fixDomainName('stackoverflow.com/questions/id/slug');

而且它也会回来stackoverflow.com

于 2018-11-15T06:34:13.893 回答
3

我知道这可能不完全是关于这个主题,但根据我的经验,我发现将当前 URL 的 WWW 属性存储在一个变量中很有用。

此外,请参阅下面的我的评论,看看这是什么意思。

在确定是否使用“www”发送 Ajax 调用时,这一点很重要:

$.ajax("url" : "www.site.com/script.php", ...

$.ajax("url" : "site.com/script.php", ...

调度 Ajax 调用时,域名必须与浏览器地址栏中的域名匹配,否则您将在控制台中出现Uncaught SecurityError 。

所以我想出了这个解决方案来解决这个问题:

<?php
    substr($_SERVER['SERVER_NAME'], 0, 3) == "www" ? $WWW = true : $WWW = false;

    if ($WWW) {
        /* We have www.example.com */
    } else {
        /* We have example.com */
    }
?>

然后,根据 $WWW 是真还是假,运行正确的 Ajax 调用。

我知道这听起来可能微不足道,但这是一个很容易被绊倒的常见问题。

于 2016-08-23T17:56:09.903 回答
-2

只需尝试:

echo apache_request_headers()[3];
于 2018-06-17T14:14:34.947 回答