多个站点共享一个IP地址:我无法使用主机标头访问特殊站点

时间:2017-08-03 15:03:40

标签: http curl

在我现在阅读的一本书中,作者会显示HTTP标头的含义。即他说有服务器托管多个网站。

让我们这样做:

ping fideloper.com

我们可以看到IP地址:198.211.113.202。

现在我们只使用IP地址:

curl -I 198.211.113.202

我们抓住了:

$ curl -I 198.211.113.202
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 03 Aug 2017 14:48:33 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: https://book.serversforhackers.com/

让我们接下来看看当我们向HTTP请求添加Host头时会发生什么:

$ curl -I -H "Host: fideloper.com" 198.211.113.202
HTTP/1.1 200 OK
Server: nginx
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
Cache-Control: max-age=86400, public
Date: Thu, 03 Aug 2017 13:23:58 GMT
Last-Modified: Fri, 30 Dec 2016 22:32:12 GMT
X-Frame-Options: SAMEORIGIN
Set-Cookie: laravel_session=eyJpdiI6IjhVQlk2UWcyRExsaDllVEpJOERaT3dcL2d2aE9mMHV4eUduSjFkQTRKU0R3PSIsInZhbHVlIjoiMmcwVUpNSjFETWs1amJaNzhGZXVGZjFPZ3hINUZ1eHNsR0dBV1FvdE9mQ1RFak5IVXBKUEs2aEZzaEhpRHRodE1LcGhFbFI3OTR3NzQxZG9YUlN5WlE9PSIsIm1hYyI6ImRhNTVlZjM5MDYyYjUxMTY0MjBkZjZkYTQ1ZTQ1YmNlNjU3ODYzNGNjZTBjZWUyZWMyMjEzYjZhOWY1MWYyMDUifQ%3D%3D; expires=Thu, 03-Aug-2017 15:23:58 GMT; Max-Age=7200; path=/; httponly
X-Fastcgi-Cache: HIT

这意味着serversforhackers.com是默认网站。

然后作者说我们可以在同一台服务器上请求黑客服务器:

$ curl -I -H "Host: serversforhackers.com” 198.211.113.202

这里收到的书是HTTP / 1.1 200 OK。

但我接受了这个:

curl -I -H "Host: serversforhackers.com" 198.211.113.202
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 03 Aug 2017 14:55:14 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: https://book.serversforhackers.com/

嗯,作者组织了301重定向并立即使用HTTPS。

我可以这样做:

curl -I https://serversforhackers.com

但是这并没有说明默认网站的概念以及主机头如何在共享IP地址上寻址特殊网站。

是否仍然可以以某种方式通过IP地址获得200 Ok寻址?

1 个答案:

答案 0 :(得分:2)

在HTTP / 1.1中,没有HTTPS,Host标头是主机名发送到服务器的唯一位置。

使用HTTPS,事情更有趣。

首先,您的客户端通常会尝试根据预期名称检查服务器的TLS证书:

$ curl -I -H "Host: book.serverforhackers.com" https://198.211.113.202
curl: (51) SSL: certificate subject name (book.serversforhackers.com) does not match target host name '198.211.113.202'

大多数客户提供了覆盖此检查的方法。 curl具有-k / --insecure选项:

$ curl -k -I -H "Host: book.serverforhackers.com" https://198.211.113.202
HTTP/1.1 200 OK
Server: nginx
[...]

但接下来是第二个问题。我无法用你的示例服务器来说明它,但这是我在互联网上找到的一个:

$ curl -k -I https://analytics.usa.gov 
HTTP/1.1 200 OK
Content-Type: text/html
[...]

$ host analytics.usa.gov | head -n 1
analytics.usa.gov has address 54.240.184.142

$ curl -k -I -H "Host: analytics.usa.gov" https://54.240.184.142
curl: (35) gnutls_handshake() failed: Handshake failed

这是由server name indication (SNI)引起的 - 这是TLS(HTTPS)的一项功能,即TLS握手中的主机名。这是必要的,因为服务器需要提供正确的证书(对于正确的主机名)才能接收任何HTTP头。在上面的示例中,当我们使用https://54.240.184.142时,curl不会发送正确的SNI,并且服务器拒绝握手。其他服务器可能会接受连接,但会将其路由到错误的位置,Host标头最终会被忽略。

使用curl,您无法像设置Host标题一样使用单独的选项设置SNI。 curl将始终从请求URL中获取它。但curl有一个特殊的--resolve选项:

  

为特定主机和端口对提供自定义地址。使用此方法,您可以使curl请求使用指定的地址,并防止使用通常解析的地址。将其视为命令行上提供的一种/ etc / hosts替代方案。

在这种情况下:

$ curl -I --resolve analytics.usa.gov:443:54.240.184.142 https://analytics.usa.gov
HTTP/1.1 200 OK
Content-Type: text/html
[...]

(443是HTTPS的标准TCP端口)

如果您想在较低级别进行实验,可以使用openssl工具与正确的SNI建立原始TLS连接:

$ openssl s_client -connect 54.240.184.142:443 -servername analytics.usa.gov -crlf

然后,您就可以输入HTTP请求并查看正确的响应:

HEAD / HTTP/1.1
Host: analytics.usa.gov

HTTP/1.1 200 OK
Content-Type: text/html
[...]

最后,请注意,在HTTP / 2中,有一个名为:authority的特殊标头(是的,带有冒号)可以被某些客户端用来代替Host。它们之间的区别是为了向后兼容HTTP / 1.1和代理:有关详细信息,请参阅RFC 7540 § 8.1.2.3RFC 7230 § 5.3