LoginSignup
4

More than 3 years have passed since last update.

SSL証明書でIPアドレスからホスト名が漏れる

Last updated at Posted at 2020-02-21

IPアドレスからWebサーバの名前がわかるよー

下の結果は、curl でIPアドレスにHTTPSでアクセスしただけです。

% curl -v https://198.51.100.15/
*   Trying 198.51.100.15...
* Connected to 198.51.100.15 (198.51.100.15) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=devel.keys.jp
*  start date: Jun 30 12:37:10 2020 GMT
*  expire date: Sep 28 12:37:10 2020 GMT
*  subjectAltName does not match 198.51.100.15
* SSL: no alternative certificate subject name matches target host name '198.51.100.15'
* Closing connection 0
* TLSv1.3 (OUT), TLS alert, close notify (256):
curl: (60) SSL: no alternative certificate subject name matches target host name '198.51.100.15'

わかりますか?

* Server certificate:
*  subject: CN=devel.keys.jp
*  start date: Jun 30 12:37:10 2020 GMT
*  expire date: Sep 28 12:37:10 2020 GMT
*  subjectAltName does not match 198.51.100.15

Apache httpd のバーチャルホスト機能を使ってHTTPSサーバを複数ホストしている場合、IPアドレスでアクセスした場合 一番最初に定義されたバーチャルホストが使われる ので、その証明書を使って検証することになっています。

アスタリスクはすべてのアドレスにマッチしますので、主サーバはリクエストを扱いません。www.example.com は 最初にあるため、優先順位は一番高くなり、default もしくは primary のサーバと考えることができます。つまり、リクエストがどの ServerName ディレクティブにもマッチしない場合、 一番最初の VirtualHost により扱われます。
https://httpd.apache.org/docs/2.4/ja/vhosts/examples.html

いやそれは困る…

場合によっては困る場合もあるでしょう。
その場合、バーチャルホストの一番最初の定義に、ダミーの設定を挟むことで回避できます。

_default.conf
<VirtualHost _default_:443>
    LogFormat "%h %l %u %t ¥"%r¥" %>s %b ¥"%{Referer}i¥" ¥"%{User-Agent}i¥"" combined
    CustomLog logs/ssl_access_log combined

    Redirect 403 /

    SSLEngine on
    SSLCertificateFile conf.d/dummy.crt
    SSLCertificateKeyFile conf.d/dummy.key
</VirtualHost>

バーチャルホストをファイルごとに分けている場合、以下のように先頭にアンダーバーを付けたファイルがあれば最初に読み込まれます。
あるいは ssl.conf の最後に書いてもいいかもですね。

 $ ls -la /etc/httpd/conf.vhosts.d
total 8
drwxr-xr-x 2 keys keys   48 Feb  4 10:15 ./
drwxr-xr-x 7 root root  138 Jan 31 18:06 ../
-rw-rw-r-- 1 keys keys 1062 Feb  3 13:49 _defailt.conf
-rw-rw-r-- 1 keys keys 1092 Jan 31 23:21 devel.keys.jp.conf

この設定で使うSSL証明書は自己署名証明書(オレオレ証明書)です。
CSRを作るときは Common Name だけ入力すれば大丈夫です。証明書の CN フィールドは、グローバルで設定した ServerName にしないと httpd の起動時に怒られるみたいです。

$ openssl genrsa 2048 > dummy.key
Generating RSA private key, 2048 bit long modulus (2 primes)
........+++++
.......................................................................+++++


$ openssl req -new -key dummy.key > dummy.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:localhost
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

$ openssl x509 -days 3650 -req -signkey dummy.key < dummy.csr > dummy.crt
Signature ok
subject=C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = localhost
Getting Private key

これでもう一度試してみると…

$ curl -v https://198.51.100.15/
*   Trying 198.51.100.15...
* Connected to 198.51.100.15 (198.51.100.15) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (OUT), TLS alert, unknown CA (560):
* SSL certificate problem: self signed certificate
* Closing connection 0
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

自己署名証明書だ、と言って怒られて処理が終わります。

これでホスト名が漏れることを防ぐことができました。しかしもう一つ、問題が残っています。

“Redirect 403 /”

ブラウザが止めようとなんと言おうと、自己署名証明書を無視してアクセスすることはできます。
curl に --insecure (自己署名証明書を無視するオプション)を付けてアクセスしてみます。

% curl --insecure https://198.51.100.15/
<html>

<head>
<title>hoge</title>
</head>

<body>
<p1>Hoge!</p1>
</body>

</html>

この場合も先頭のバーチャルホストの内容が使われます。そこからホスト名やサービスの内容が漏れる場合もあるでしょう。

これを防ぐには、先の設定ファイルにはあらかじめ書いておきましたが、一行追加しておくと防げます。

Redirect 403 /

すると、IPアドレスでのアクセスはすべて 403 になり、見えなくなります。

$ curl --insecure https://198.51.100.15/
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access this resource.</p>
</body></html>

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
4