具体的には、Let’s Encryptで取得した証明書の暗号化方式がTLS1.0だったため、1.2にアップデートしたんだけど、いろいろスッタモンダしたので備忘録として書いておきます。
事の発端
おっちゃんはメインで使ってるブラウザがFireFoxなのですよ。理由は単純で、Googleが好きじゃないのと、Chromeはもはや最速でもなんでもないから。もちろん開発に便利なときもあるので使ってはいるけど、あくまでメインはFireFoxってだけね。Mozilla製だから辺に利害関係とか無さげなのが良いね。
FireFoxで複数タブを開いた状態のウィンドウが複数ある時、最後じゃないウィンドウを閉じると、そのウィンドウのセッションが消滅してしまうらしく、タブの復元でもとに戻せなくなる。Chromeだとウィンドウまたいでも履歴を復活させてくれて順番に復元可能なので、FireFoxでも同じ機能を実装してほしいね。機能拡張でそういうのあるらしいけど、あんまりゴタゴタ入れるの好きじゃないので本体の対応待ち。
で、FireFoxで自分のブログ見てみたら、なんと最新版(v68.0)だとURLのロケーションバーに警告がでてるじゃないですかンガポゴ!
みっともないし恥ずかしいので、とにかく時間を無理やり作って対策することにしたのです。
Webに携わってる人なら知ってるとは思うけど(IT関連やっててしらんとか情弱にも程があるぞ)、SSLってのはもう殆ど流通してなくて、今みんなが使ってるのはTLSなんだよ。でもSSLって名前で普及しちゃってるのにいきなりTLSに変えましょう!ったって変わらないから、苦肉の策でSSL/TLSって名前にしてるんだよね。詳しくは自分でググればいいと思う。
ちなみにFireFoxの開発ツールのコンソールにはこんなメッセージが山盛り。
準備
まずはFireFox情で証明書の概要を確認してみます。
TLSのECDHE_RSA_WITH_AES_256_CBC_SHAとか、ちょっとよくわからないんだけど、とにかくTLSが1.0であることがわかったので、これはまずいです。せめて1.1でしょ。
早速Let’s Encrypt界隈をごちゃごちゃいじってみることにします。
既存の旧Certbotを削除
以前はyumコマンドでインストールしていたので同じくyumコマンドで削除します。なんでyumで入れたのかと言うと、当時はyum派とgitでclone派があって、cloneが面倒くさかったのでyumでインストールしました。
でも今考えると、yumだとパッケージが古い可能性もあるし、リポジトリから消える可能性もあるので、今回を機にgithubからcloneすることにします。いろいろぐぐってみるとその方法で証明書のインストールしてる人のほうが圧倒的に多いので。
で、サクサクっと既存のcertbotを消しましょう。
$ sudo -s
← rootユーザになる# yum remove certbot
← yumで入れたのでyumで消す# yum install git
← git入ってなかったのでインストール# exit
商用サーバにgit入れるとかやや抵抗があるのですが、まぁデプロイツールとかでも普通に使われているので、とりあえず良しとします。
こういう意識が大事。何でもかんでも入れればいいってもんじゃない。ITゆとりにはそれがわからんのですよ。
certbotは証明書をインストールするためのツールなので、別にcertbotを削除しても証明書が削除されるわけではないです。当然消してもWebサイト側は特に問題ないです。
改めて最新版のCertbotをgitでcloneする
さて、certbotをgitでcloneする時、rootユーザではなく一般ユーザで行います。理由は、そのほうが楽だから。というわけで、一般ユーザのホームディレクトリにcloneしておきます。
$ cd
← ホームディレクトリに移動$ git clone https://github.com/certbot/certbot
いちおうcertbotの動作確認をしておきましょう。certbotはいわばLet’s Encryptの本体と言ってもいいです。
$ cd certbot
← cloneしたディレクトリ内に移動$ ./certbot-auto --help
← とりあえずヘルプを表示させてみる
こんな感じでターミナルに表示されたと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Requesting to rerun ./certbot-auto with root privileges... Usage: certbot-auto [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates to both this script and certbot will be downloaded and installed. After ensuring you have the latest versions installed, certbot will be invoked with all arguments you have provided. Help for certbot itself cannot be provided until it is installed. --debug attempt experimental installation -h, --help print this help -n, --non-interactive, --noninteractive run without asking for user input --no-bootstrap do not install OS dependencies --no-permissions-check do not warn about file system permissions --no-self-upgrade do not download updates --os-packages-only install OS dependencies and exit --install-only install certbot, upgrade if needed, and exit -v, --verbose provide more output -q, --quiet provide only update/error output; implies --non-interactive All arguments are accepted and forwarded to the Certbot client when run. |
1行目にメッセージがありますね。これは一般ユーザじゃなくてrootユーザで実行してくれよな!という警告です。証明書発行するときはrootユーザになって実行するので無視していいです。
certbot実行
さて、それでは既存の証明書がまだインストールされているとは思いますが、NginxとかApacheを再起動しない限り影響がないので、いきなり証明書をインストールしてみましょう。
StandaloneとWebroot
certbotで証明書をインストールする際のモードが2つあります。Standalone方式はNginxやApacheなどのHTTPdが動いているとエラーが出ます。Webroot方式では出ません。
- standalone方式
- certbot自体が持っているWebサーバ機能を使って証明書をインストール
- 80番ポートを使用するので稼働中のHTTPdは止めておく必要がある
--standalone
オプションを使用
- webroot方式
- 可動しているhttpdを使用して証明書をインストールする方式
--webroot
オプションを使用
上記を見れば一目瞭然ですね。すでに証明書が入っているし、HTTPdも稼働中なので、今回はwebroot方式でインストールすることにします。
Webroot方式で実行
ここでは仮に、ブログが/var/www/html
にインストールされているとします。いわゆるドキュメントルートのことです。
$ sudo -s
# ./certbot-auto certonly --webroot -w /var/www/html -d blog.ogaaaan.com
簡単に説明します。certonly
で証明書をインストールします。--webroot
でWebroot方式を指定します。-w
でドキュメントルートの場所を指定します。-d
でドメインを指定します。簡単ですね。
で、依存関係なんかを先にインストールしてくれます。yumで入れたcertbotを消した時、依存関係も消えてるってことですね。神経質でいい感じです。
というわけで依存パッケージのインストールが開始しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
・・・ tkinter x86_64 2.7.13-2.fc24 updates 395 k zlib-devel x86_64 1.2.8-10.fc24 fedora 55 k Upgrading: glibc x86_64 2.23.1-12.fc24 updates 3.6 M glibc-all-langpacks x86_64 2.23.1-12.fc24 updates 7.0 M glibc-common x86_64 2.23.1-12.fc24 updates 861 k httpd x86_64 2.4.27-3.fc24 updates 1.3 M httpd-filesystem noarch 2.4.27-3.fc24 updates 27 k httpd-tools x86_64 2.4.27-3.fc24 updates 89 k krb5-libs x86_64 1.14.4-5.fc24 updates 741 k libgcc x86_64 6.3.1-1.fc24 updates 89 k libgomp x86_64 6.3.1-1.fc24 updates 191 k openssl x86_64 1:1.0.2k-1.fc24 updates 494 k openssl-libs x86_64 1:1.0.2k-1.fc24 updates 1.2 M python x86_64 2.7.13-2.fc24 updates 96 k python-libs x86_64 2.7.13-2.fc24 updates 6.2 M Skipping packages with conflicts: (add '--best --allowerasing' to command line to force their upgrade): ca-certificates noarch 2017.2.14-1.0.fc24 updates 484 k p11-kit x86_64 0.23.2-4.fc24 updates 149 k p11-kit-trust x86_64 0.23.2-4.fc24 updates 129 k redhat-rpm-config noarch 42-2.fc24 updates 59 k Transaction Summary ================================================================================================================== Install 30 Packages Upgrade 13 Packages Skip 4 Packages Total download size: 63 M Is this ok [y/N]: y |
インストールしてもいいですかね?と聞かれるので、当然y
をタイプしてEnterします。しなければ何も始まりません。そしてそのまま待っていると、勝手にcertbotが実行されて証明書がインストールされます。
が、以前インストールした設定が残っているので、どうするのか聞かれました。そんなの関係ねぇ!バリに実行を続けるか聞かれますので、実行させました。そんなの関係ねぇから。
証明書がインストールされる場所は、
/etc/letsencrypt/renewal/
+ ドメイン名 +fullchain.pem
- サーバ証明書と中間証明書の合体した証明書
/etc/letsencrypt/renewal/
+ ドメイン名 +privkey.pem
- 秘密鍵
になりました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
./certbot-auto has insecure permissions! To learn how to fix them, visit https://community.letsencrypt.org/t/certbot-auto-deployment-best-practices/91979/ Creating virtual environment... Installing Python packages... Installation succeeded. Saving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator webroot, Installer None Cert not yet due for renewal You have an existing certificate that has exactly the same domains or certificate name you requested and isn't close to expiry. (ref: /etc/letsencrypt/renewal/blog.ogaaaan.com.conf) What would you like to do? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1: Keep the existing certificate for now 2: Renew & replace the cert (limit ~5 per 7 days) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Select the appropriate number [1-2] then [enter] (press 'c' to cancel): |
ここで2を選択して証明書を最新のものと入れ替えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
Renewing an existing certificate Performing the following challenges: http-01 challenge for blog.ogaaaan.com Using the webroot path /var/www/html for all unmatched domains. Waiting for verification... Cleaning up challenges IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/blog.ogaaaan.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/blog.ogaaaan.com/privkey.pem Your cert will expire on 2019-10-11. To obtain a new or tweaked version of this certificate in the future, simply run certbot-auto again. To non-interactively renew *all* of your certificates, run "certbot-auto renew" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le |
で、後はこの2つのファイルをHTTPd側の設定ファイルで指定するだけです。
ちなみに設定ファイルを見る限り、以前と同じ場所に同じファイル名で作られたことがわかったので、特に変更せずに再起動だけで済むようです。楽ですね。
Nginxの再起動と確認
このブログはNginxで動いています。
現在読み込まれている証明書はサーバのメモリ上に展開されているため、Nginxを再起動して最新の証明書に読み込み直す必要があります。
# systemctl restart nginx
ブラウザ上で確認するも以前と変わらず警告が出てしまました。うーむ。なにかやるべきこと忘れたのかな?
証明書の発行日は本日、有効期限は3ヶ月後になっているため、更新されたことは確認できたので、とりあえずブログがぶっ壊れたとか証明書がぶっ壊れたと買ってことにはなってないわけで、少し時間をかけて調べることにしました。
ツールでスコア判定
Qualys SSL LABSのSSL Server Testをってスコアを判定してみます。ここは判定したいサイトのドメイン名のみを入力して実行すればスコアが表示されます。便利です。
以下がその結果になります。
現状
- ランクC
- Certificate: 100
- Protocol Support: 50
- Key Exchange: 70
- Cipher Strength: 70
SSLv2/v3の無効化
とりあえずTLSとして明示的に指定したいので、SSLの設定を無効化してみたいと思います。
現状のNginxのSSLの設定は以下。思いっきりSSLv2とか書いちゃってますし、TSLも1になってます。
1 2 3 4 |
ssl_prefer_server_ciphers on; ssl_ciphers HIGH:!aNULL:!MD5; ssl_protocols SSLv2 SSLv3 TLSv1; |
これを以下のように、SSLv2とSSLv3以外 が有効になるように編集します。
1 2 3 4 |
ssl_prefer_server_ciphers on; ssl_ciphers 'ALL !SSLv2 !SSLv3'; #ssl_protocols SSLv2 SSLv3 TLSv1; ←コメントアウトか削除する |
Nginxを再起動後、ブラウザで警告は出なくなったので、再度スコアを見てみました。
- ランクC
- Certificate: 100
- Protocol Support: 50
- Key Exchange: 70
- Cipher Strength: 70
特に変わらずランクCなので、とりあえず最終的によくわからなくなったらこれにしておこうと思います。
しかしもう少し調べておきたいので、更に調査してもっと編集してみることにしました。
匿名認証方式の無効化
以下のように、aNULL
とeNULL
も無効化しました。
1 2 |
ssl_ciphers 'ALL !aNULL !eNULL !SSLv2 !SSLv3'; |
Nginx再起動後スコアを見てみます。
- ランクF
- Certificate: 100
- Protocol Support: 100
- Key Exchange: 0
- Cipher Strength: 90
なんと一気にFまで落ちてしまったという。なんで?
強度の弱い暗号化方式の無効化
更に以下のように、DH
も無効化しました。
1 2 |
ssl_ciphers 'ALL !DH !aNULL !eNULL !SSLv2 !SSLv3'; |
- ランクF
- Certificate: 100
- Protocol Support: 100
- Key Exchange: 0
- Cipher Strength: 90
残念ながらこちらもランクF。ついでなのでもう少しいろいろ試してみましょう。
Forward Security対応
鍵交換方式をALL
からECDH
固定にし、DHは有効に戻してみます。
1 2 |
ssl_ciphers 'ECDH !aNULL !eNULL !SSLv2 !SSLv3'; |
- ランクF
- Certificate: 100
- Protocol Support: 100
- Key Exchange: 0
- Cipher Strength: 90
速攻で結果が表示された。残念ながらこちらもランクFでした。
うーむ。ここらへん得意じゃないのでよくわかってないのが痛い。
Strict-Transport-Securityヘッダ対応
サイファは以下のように設定し直して、ヘッダを付与するように設定してみます。
1 2 3 |
ssl_ciphers 'ECDH !aNULL !eNULL !SSLv2 !SSLv3'; add_header Strict-Transport-Security 'max-age=31536000; includeSubdomains'; |
- ランクF
- Certificate: 100
- Protocol Support: 100
- Key Exchange: 0
- Cipher Strength: 90
こちらもランクF。
いろいろ調整
最終的に以下にしておきました。
1 2 3 4 5 |
ssl_prefer_server_ciphers on; ssl_ciphers 'RSA ECDH !LOW !EXPORT !3DES !MD5 !aNULL !eNULL !SSLv2'; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; add_header Strict-Transport-Security 'max-age=31536000; includeSubdomains:preload'; |
ランクはCです。
個人的にここらへんの知識が足りず、勉強不足なので一旦ここまでにしておきました。
BやAにする方法はまた後日考えます。
おわり
セキュリティ大事。