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
いやそれは困る…
場合によっては困る場合もあるでしょう。
その場合、バーチャルホストの一番最初の定義に、ダミーの設定を挟むことで回避できます。
<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>