MastHead
  Entry     Photo Lib     Forum     Links     Glossary     Misc.  
サイトを SSL 化したときのメモ

Site を SSL 化したときの変更点についてメモしておく。
当サイトではクレジットカード番号を入力するような場面はないので暗号化通信は不要なのだが、 それでも近年はサイトを SSL にしておかないとユーザー側のブラウザに注意事項が表示されたり、検索クローラから除外されたりといった不利益があるので、 やむなく SSL 化をすることにした。
SSL 化後数週間で、Page View の数字は 1.5 倍 から 2 倍程度になった。  しかし同時に不正アクセスも増加し、多様化した。
なお、以下の記述で前提としているのは httpd が Apache で、バージョンは 2.4.54 である。

[方針]
openssl.exe を使って certification file を作る方法を試したが、 それだとユーザー側のブラウザに「公式認証の無い危険なサイト」という表示が出て使い勝手が悪かった。
改めて無料の認証サイトの Let's Encrypt を使うことに方針を変更した。
Let's Encrypt は認証期間が 90 日しかないので、方法として mod_md を使って自動的に更新を実行させることにした。
mod_ssl.so を使うが、それに伴っている httpd_ssl.conf は httpd.conf と重複する項目が多いので、 見通しをよくするために httpd.conf のみを使う。

mod_md 上で認証方法として HTTP 認証 (http-01)を使う。  但し、Let's Encript は認証の時に Challenge をしてくるサーバーの IP アドレスを固定していないので、こちらの Firewall がそれを阻止してしまう可能性がある。  これについては DNS-01 を使う以外は良い解決法は見つかっていないが、私のプロバイダは DNS-01 を使わせてくれないので HTTP-01 を使わざるを得ない。  とりあえず広範囲な IP レンジを許可しておき、不正アクセスしてくる IP がたまたまそのレンジ内にある場合には firewall を工夫して阻止できるようにする。

http プロトコル(Port 80)でアクセスしてくるユーザーは https (Port 443)へ Redirect する。

主として httpd.conf だけの変更で済ませられるが、副次的に Firewall と Router の変更も必要となる。

[実装]
httpd.conf へ追加する項目(すでにあるものは追加しない):
Define ENABLE_TLS13 "Yes"
LoadModule ssl_module           modules/mod_ssl.so
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
LoadModule watchdog_module      modules/mod_watchdog.so
LoadModule md_module            modules/mod_md.so

#SSL
Listen 443
MDBaseServer           on
MDCertificateProtocol  ACME
MDCAChallenges         http-01
MDDriveMode            auto
MDPrivateKeys          RSA 2048
MDRenewWindow          33%
MDStoreDir             md
MDCertificateAuthority https://acme-staging-v02.api.letsencrypt.org/directory (テスト用のサイト)
#MDCertificateAuthority https://acme-v02.api.letsencrypt.org/directory        (これが本物のサイト)
MDCertificateAgreement https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf
SSLSessionCache        "shmcb:${SRVROOT}/logs/ssl_scache(262144)"
SSLSessionCacheTimeout 120

MDomain wista.jp                   (web server のドメインネーム)
MDStapling on
<VirtualHost *:80>
  ServerName wista.jp              (web server のドメインネーム)
  RewriteEngine On
  RewriteCond %{ENV:REDIRECT_STATUS} !^$
  RewriteRule ^(.*)$ - [L]
  RewriteCond %{ENV:reject} 1      (SetEnvIf で攻撃アクセスにマークを付けてあるので阻止)
  RewriteRule ^(.*)$ - [F,L]
  RewriteCond %{HTTPS} off
  RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>
<VirtualHost *:443>
  SSLEngine on
  ServerName wista.jp              (web server のドメインネーム)
  SSLSessionTickets on
  DocumentRoot "c:\documentroot"     (html ファイルが置かれている root フォルダーパス) 
</VirtualHost>

AcceptFilter https none
httpd.conf 中の変更する行:
    ServerName wista.jp:80     という行が上記以外にあるから :80 を消す
httpd.conf 以外の変更:
Firewall で Let's Encrypt の Challenge を通すようにしておくこと、但し IP が変化する(下記追加情報)。
Firewall の設定で、hhtpd に向けて port 443 の通行を許可する。
Router の静的 NAT の port 443 を開ける(つなぐ)。
Router の IPv4 パケットフィルターで TCP の port 443 を通す。

[実行]
Firewall と Router の窓を開けたのち、サイトサーバーを正規の IP (NAT で指定した IP)として 外部にさらした後で Apache を再起動する。
しばらく(5 分以内)して Let's Encrypt サーバーから認証ファイルが送られてきて、{HTTP_HOST}/md/domains/wista.jp に格納される。  その中の job.json ファイルを開いて、valid-from の行が今日の日付になっていれば成功している。  もしファイルが無かったり日付が過去のものだったりする場合は失敗してる。  その時は {HTTP_HOST}/md/staging/wista.jp/job.json を見て、あれば challenge の途中で失敗している。
失敗する場合は Firewall を全開放して再度試みる。
テスト用のサイトならば偽物(dummy)が送られて来るが、それにより通信が成功していることが確認できる。
テストが成功したら md フォルダーの中を消去し、httpd.conf の MDCertificateAuthority 行を本物のサイトに書き直して、再度立ち上げなおす。
しばらくして本物の認証ファイルが格納されたら、もう一度 Apache を立ち上げなおす。
以上の工程が 50 回失敗すると、7 日間は認証要求ができなくなる。

Web サーバーのある LAN 内からサーバーにアクセスすると、ドメイン名が異なるので拒否されるようになるから、アクセスする側の PC の hosts ファイルを書き換えてドメイン名を LAN 内 IP アドレスに紐づけしておくこと。

Qualys の SSL Server Test ImmuniWeb (ImmuniWeb は非推奨)を使って外部から SSL が動作していることを確認する。 なお、これらのテストサイトは UserAgent 無しでアクセスしてくる。

全 html 文書の header にある canonical の記述を http:// から https:// に書き換える。
sitemap.xml の <loc> の内容を http:// から https:// に書き換え、<lastmod> の日付を当日にする。
sitemap.xml を Google に送付する。

[更新時に失敗した場合]
Firewall がアクセスを拒否したときは失敗するが、その場合の回復方法は以下の通り:
1.管理者権限で cmd を 開き net stop apache2.4 で Apache を止める。
2.{HTTP_HOST}/md/staging/wista.jp/ の中身を消去する。 ほかのフォルダーは触らないこと。
3.net start apache2.4 でApache を開始する。
4.{HTTP_HOST}/md/domains/wista.jp/job.json がアップデートされたことを確認する。
5.Apache を停止し、再度開始する。

[追加情報]
LE の Challenge は、4つ別々のノードから打って来て、3つが成功しなければ認証されない。  Firewall で阻止していると認証されないことになる。  Challenge サーバーの IP アドレスは 公開されていない
今は Amazon や Google のクラウドを使うことが多いが、過去には Akamai や Cloudflare も使っていた。  実際に最初に来たのは 3.143.233.9、35.92.222.63、172.65.32.248 の3つだった。
それらを含め私が作ったリストは==> これ。
Lte's Encrypt 側としては Whitelist の使用を推奨していないが、かといって HPPT-01 を使った場合の代替え策は提示していない。  推奨しない理由は、IP を変化させるので認証が失敗する可能性があるため。
私が 2026 年 5 月現在 LE Challenge のために Firewall に開けてある IP Range は以下の通り:
3.0.0.0       - 3.17.255.255  
3.19.0.0      - 3.78.255.255  
3.120.0.0     - 3.129.255.255 
3.131.0.0     - 3.131.255.255 
3.133.0.0     - 3.134.255.255 
3.135.0.0     - 3.143.255.255 
3.143.0.0     - 3.149.255.255 
13.48.0.0     - 13.61.255.255 
13.63.0.0     - 13.63.255.255 
13.212.0.0    - 13.212.255.255
13.213.0.0    - 13.215.255.255
13.229.0.0    - 13.229.255.255
13.250.0.0    - 13.251.255.255
16.16.0.0     - 16.16.255.255 
16.146.0.0    - 16.146.255.255
16.170.0.0    - 16.171.255.255
18.116.0.0    - 18.169.224.255
18.184.0.0    - 18.188.255.255
18.190.0.0    - 18.200.255.255
18.216.0.0    - 18.255.255.255
23.178.112.0  - 23.178.112.255 重要:最初に来るアクセス
34.209.0.0    - 34.213.255.255
34.215.0.0    - 34.222.255.255
35.86.0.0     - 35.87.255.255 
35.89.0.0     - 35.90.255.255 
35.92.0.0     - 35.92.255.255 
35.157.0.0    - 35.166.255.255
44.249.0.0    - 44.250.255.255
47.129.0.0    - 47.129.255.255
51.20.0.0     - 51.20.255.255 
52.13.0.0     - 52.13.255.255 
52.15.0.0     - 52.19.255.255 
52.23.0.0     - 52.25.255.255 
52.25.101.0   - 52.33.255.255 
52.37.0.0     - 52.44.255.255 
52.55.0.0     - 52.59.255.255 
54.93.0.0     - 54.93.255.255 
54.168.0.0    - 54.170.255.255
54.184.0.0    - 54.186.255.255
54.189.0.0    - 54.191.255.255
54.201.0.0    - 54.206.255.255
54.213.0.0    - 54.213.255.255
54.214.0.0    - 54.214.255.255
54.244.0.0    - 54.247.255.255
54.254.0.0    - 54.255.255.255
64.78.144.0   - 64.78.159.255 
66.133.96.0   - 66.133.127.255
172.65.0.0    - 172.65.255.255

Challenge のアクセスは次のような形式(一部書き換え)で、2秒以内の間隔で別々の IP から4回来る:
 ip:     3.20.206.24   など多分上記レンジ内のもの
 port:   80
 method: GET 
 URI:    /.well-known/acme-challenge/xxxxxx_long_alphanumeric_string_xxxxxxxx
 agent:  Mozilla/5.0 (compatible; Let's Encrypt validation server; +/www.letsencrypt.org)
Challenge してくるアクセスは、まず最初に 23.178.112.0/24 から URI の /.well-known/acme-challenge/ に来て、 続いて1~2秒以内に3つの別々の IP から同じ URI に来る。  失敗した場合(例えば Firewall が阻止していた時)はこの回数が増えるのと、秒数が別れるので失敗していることが分かる。

[希望的方法]
http-01 ではできれば White List は使わないほうが良い。 Challenge は実に多くの IP を変化させながら撃ってくるのでその対応が面倒くさい。 それで、次のような方法ができないものか:
「Amazon の IP をすべて閉鎖しておく。 その上で、一旦 IP 23.178.112.0/24 からアクセスが来たら、直ちに(1ms以内に) IP 群 3.0.0.0/8, 13.0.0.0/8, 16.0.0.0/8, 18.0.0.0/8, 34.0.0.0/8, 35.0.0.0/8, 47.0.0.0/8, 51.0.0.0/8, 52.0.0.0/8, 54.0.0.0/8, 64.0.0.0/8, 66.0.0.0/8, 172.0.0.0/8 に対して通過を許可して、4秒後に再度閉鎖する。」
これは時間軸でダイナミックに Firewall 条件を変化させるやり方なので、現状で広く使われている静的な Firewall では実現できない。
別途 PowerShell で Script を書く必要があるが、Log や、既にある Firewall との競合についても入り組んだ考察が必要になる。

あるいは:
「Amazon はすべて閉じておくが、例外的に、IP 群 3.0.0.0/8, 13.0.0.0/8, などからの Port=80 経由で URI=/.well-known/acme-challenge/ への アクセスは許可する」
という方法が取れるかもしれない。 NGINX を使えば実現できそう。


[Reject の取り扱い]
不正なアクセスが :80 に来た時に直ちに 403 を返したいが、通常の Redirect を行うと 301 が返ってしまう。  SSL 化していなかったときは Environment 変数を設定して
  Require not env (変数)
を使って 403 のレスポンスを返していたが、SSL 化したときは <VietualHost> の中では <Directory > に到達する前に Redirect になるのが理由。
対応は上記の[実装]のようにした。 以下に経過を示す。

Case 1
SetEnvIf User-Agent ".*botnet" reject
<VirtualHost *:80>
  ServerName wista.jp
  RewriteEngine On
  RewriteCond %{HTTPS} off
  RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>
<VirtualHost *:443>
  SSLEngine on
  ServerName wista.jp              
  SSLSessionTickets on
  DocumentRoot "c:\documentroot" 
</VirtualHost>
<Directory "c:\documentroot">
  Options FollowSymLinks Multiviews
  AllowOverride none
  <RequireAll>
    Require not env reject
    Require all granted
  </RequireAll>
</Directory>
この方法では :80 への不正アクセスには 301 のレスポンスになる。  Require not env reject は Directory の中にあるので動作しない。  また Directory セクションは VirtualHost の中へは入れられないルールがある。

Case 2
SetEnvIf User-Agent ".*botnet" reject
<VirtualHost *:80>
  ServerName wista.jp
  RewriteEngine On
  RewriteCond %{ENV:reject} 1
  RewriteRule ^(.*)$ - [F,L]
  RewriteCond %{HTTPS} off
  RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>
(以下同)
この方法では 500 (サーバー内部エラー)を返す。  理由は [F] によって 403 を返すべく Redirect しようとしてループに入ってしまうため。

Case 3
SetEnvIf User-Agent ".*botnet" reject
<VirtualHost *:80>
  ServerName wista.jp
  RewriteEngine On
  RewriteCond %{ENV:rejected} 1
  RewriteRule ^(.*)$ - [L]
  RewriteCond %{ENV:reject} 1
  RewriteRule ^(.*)$ - [E=rejected:1,F,L]
  RewriteCond %{HTTPS} off
  RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>
(以下同)
この方法では [E=rejected:1,F,L] の部分がうまく働かず、下に抜けて https に Redirect されてしまう。 結果として http:// からは 301 が、https:// からは 403 が返ってくる。

Case 4
(前述の[実装]に書いてある方法)
この方法で :80 へのアクセスに対して 403 を返すことができる。


[特殊な注意事項]
1. ユーザーからのアクセスは https:// で行うようになったわけだが、Google の検索結果はしばらくは http:// で表示されていて Redirect が頻繁に発生する。
この Redirect を避けるために Google の Search Console の「インデックス作成」の「削除」で、 「このプレフィックスで始まる URL をすべて削除」を使って http://wista.jp/ で始まるすべてのページを削除したくなるが、これは絶対にしてはならない
やると、https:// 以下の全ページが表示されなくなる。

2. httpd.conf の設定の中で
 MDRenewWindow 33%
を指定してある。 これで60日後かその翌日に自動で更新を実行するので、その日辺りの Apatch log を見ること。  上記の White List の内、23.178.112.0/24 は必ず最初にくるので、それを見れば来た事が分かる。
Challenge があったら、サーバーの ocsp や staging フォルダーを見て成功していることを確認すること。
同時に Apache Error Log も見て、md モジュールでエラーが出ていないか確認すること。 失敗したときは Timeout エラーが記録される。
また、Firewall の Log を見て、同時刻(+1秒以内)に :80 へのアクセスを阻止している IP があれば Let's Encrypt からのアクセスである可能性があるので、一旦その IP のレンジ(*.*.*.0/24)は通過するように変更しておくこと。
これらの作業は60日ごとに行う。

3.OCSP
Let's Eccrypt は今後 OCSP サービスを終了する方針なので、使わないこと。
参照: Let's Encrypt の発表 2024/7/23 Intent to End OCSP Service


[2025.12.07 追記]
Port 80 を閉鎖することにした。
SSL 導入後ほぼ3年を経過し、Port 80 への正規のアクセスはほとんど無くなって、アタックだけになってきた。  Firefox も Chrome も Edge も http:// でアクセスすると自動的に https:// に切り替えるようになった。  もう Redirect は不要で、Port 443 のみで運用できる環境になったと判断する。  そこで、httpd.conf を書き換えて次のようにした。 これで Let's Encrypt 以外のアクセスが Port 80 に来た場合は 403 を返すことになる。

#MDomain wista.jp                                 Remove this line
MDStapling off                                    Disable OCSP
<VirtualHost *:80>
    ServerName wista.jp
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/ [NC]
    RewriteRule ^ - [F,L]                         Close port 80 except for LE
</VirtualHost>
<VirtualHost *:443>
    ServerName wista.jp
    MDomain wista.jp                              Move into :443 section
    SSLEngine on
    SSLSessionTickets on
    DocumentRoot "c:\documentroot"
</VirtualHost>
注: 上記は最小限の部分だけを記述してあり、実際にはもっと複雑。


[2025.12.16 追記]
今日、Let's Encrypt は認証期間を 90 日から 45 日に短縮する計画を発表した。
 ==>12/16発表文
2027.2.10 から 64 日に、2028.2.16 から 45 日になる。




サイトの最初のページに行くTopPage
SSL mod_md Let's Encrypt letsencrypt httpd.conf
(1/16/2023)武        

Ⓒ Copyright 2023  T. Fujiwara      All rights reserved.
Archiving or copying this article without the author's permission is prohibited.

SSL mod_md Let's Encrypt letsencrypt httpd.conf
作者: 藤原 武 Tak Fujiwara