最近 Let's Encrypt が Public Beta になったということで,自分のサイト(https://sonickun.xyz)もSSL化してみた.また,どうせならSSL LabsのテストでA+を取りたいと思いあれこれ試行錯誤したので備忘録として残しておく.
Let's Encrypt
letsencrypt.org
Let's Encrypt は,SSL/TLSサーバ証明書の取得・管理を簡略化できる無料のサービスであり,TLSやHTTPSを普及させることを目的としている.Let's Encryptで取得可能なSSL/TLSサーバ証明書は「ドメイン認証 (DV) SSL/TLS証明書」であり,独自ドメインの所有者であれば誰でも取得可能である.企業認証(OV)SSL/TLS証明書やEV SSL証明書は取得できないが,個人が運営するサイト程度ならDV証明書で十分といえる.
Let's Encryptの詳細は有志による日本語サイトによくまとまっている.
Qualys SSL Labs
Qualys SSL Labs社が提供するSSL Server Testは,SSLサーバ証明書の設定状況の確認や,信頼性の診断などができるサービスである.グレード表記や項目別スコア表示があり,さらに信頼性に乏しいと思われる設定項目を指摘してくれる.
今回はQualys SSL Labsのテストの最高グレードである A+ の取得を目指す.
Let's EncrptでWebサイトをSSL化
今回SSL化するWebサイトは自分のプロフィールサイト(sonickun.xyz)で,WebサーバはNginx,OSはCentOS 6.5である.
詳しくは過去記事
sonickun.hatenablog.com
Lets's Encrypt Clientのインストール
事前に以下のパッケージをインストールしておく.
# yum -y install httpd openssl mod_ssl # yum -y install git
次に以下のコマンドでLets's Encrypt Clientをインストールする.--debug
オプションは必須ではないが,これがないとエラーが起きる場合があるので付けておいたほうが良い.
# git clone https://github.com/letsencrypt/letsencrypt # cd letsencrypt # ./letsencrypt-auto --help --debug
自分の環境の場合,letsencrypt-autoの実行時にvirtualenvというPythonモジュールがないとがないと怒られてしまったのでeasy_installで入れておく.
# easy_install virtualenv
SSL証明書の取得
以下のコマンドを実行する.${DOMAIN}
の部分は取得したいドメイン(自分の場合は"sonickun.xyz")を,${WEBROOT}
の部分はNginxで設定しているルートディレクトリ(自分の場合は"/var/www/html/")を指定する.
# ./letsencrypt-auto certonly --webroot -d ${DOMAIN} --webroot-path ${WEBROOT} --debug
すると,青い画面でメールアドレスの入力を求められるので,メールアドレスを入力して,<了解>を選択する.つぎに,利用規約に同意するか聞かれるので,<Agree>を選択する.
証明書の取得が完了すると以下の様な表示になる.
IMPORTANT NOTES: - If you lose your account credentials, you can recover through e-mails sent to xsonickun@gmail.com. - Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/sonickun.xyz/fullchain.pem. Your cert will expire on 2016-03-13. To obtain a new version of the certificate in the future, simply run Let's Encrypt again. - Your account credentials have been saved in your Let's Encrypt configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Let's Encrypt so making regular backups of this folder is ideal. - If like Let's Encrypt, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le
/etc/letsencrypt/live/sonickun.xyz/
に以下のファイルが置かれる.
# cd /etc/letsencrypt/live/sonickun.xyz/ # ls cert.pem #サーバ証明書 chain.pem #中間証明書 fullchain.pem #サーバ証明書+中間証明書 privkey.pem #サーバ秘密鍵
Nginxの設定
今回はSSL化に加えて,HTTP/2にも対応させることにする.HTTP/2はHTTP/1.1と比べ様々な最適化がされており,例えば,バイナリーフレームの採用,ストリームによる多重化,サーバープッシュなどの特徴がある.
Nginxでは,mainlineで提供されているバージョン1.9.5以降でHTTP/2に対応しているため,これよりも古いバージョンの場合はアップデートする必要がある.
まず,"nginx: Linux packages"を参考にしつつリポジトリを以下のように変更する(baseurlに注意).
# vi /etc/yum.repos.d/nginx.repo [nginx] name=nginx repo baseurl=http://nginx.org/packages/mainline/OS/OSRELEASE/$basearch/ gpgcheck=0 enabled=1
yumでアップデート,バージョンの確認をする.
# yum -y install nginx # nginx -v nginx version: nginx/1.9.9
これにてNginxのバージョンアップが完了した.
次に,Nginxの設定ファイルetc/nginx/conf.d/server.conf
を以下のように設定する(なおこれが最終版ではない).
server { listen 80; listen [::]:80; listen 443 ssl http2; listen [::]:443 ssl http2; server_name sonickun.xyz; ssl_certificate /etc/letsencrypt/live/sonickun.xyz/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/sonickun.xyz/privkey.pem; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA; ssl_dhparam /usr/local/nginx/conf/dhparam.pem; location / { root /var/www/html; index index.html index.htm; } }
設定変更後のNginxの再起動も忘れずに.
# service nginx reload # service nginx restart
Webサイトの確認
実際にアクセスしてみるとHTTPSで通信していることが分かる.また,Googleの拡張であるHTTP/2 and SPDY indicatorを使ってHTTP/2が使われていることが確認できる.
chrome://net-internals/#events&q=type:HTTP2_SESSION%20is:active
SSL Labs A+ を目指して
ひとまず先程のSSL Labsのテストを行ってみる.
はい.
診断結果によれば,DH鍵が弱く,Perfect Forward Secrecy (PFS) に対応していないとのこと.
DH鍵の変更
DHE鍵交換にはLogjam攻撃という攻撃が存在し,512bit長の標準素数であれば数十秒で解ける.また1024bit長でも国家予算並みのお金をかければ解読できると言われており,現在は2048bitの利用が推奨されている.
さて,現状のDH鍵の鍵用は1024bitとなっているため,2048bitのものに変更する.
まず/usr/local/nginx/conf/
下でopensslを用いてDH鍵を生成する.
# openssl dhparam -out dhparam.pem 2048 # openssl dhparam -text -in dhparam.pem -noout
次にserver.conf
に以下の行を追加する.
ssl_dhparam /usr/local/nginx/conf/dhparam.pem;
これにてDH鍵の変更は完了.
Perfect Forward Secrecy (PFS) ヘの対応
Perfect Forward Secrecyとは,サーバの秘密鍵が暴露された場合でも,ユーザーの個人的な情報記録を過去に遡って解読することを妨ぐ暗号化技術であり,HeartBleedのような致命的なバグに対して効果を発揮する.
PFSをサポートしているのはDHE鍵交換とECDHE鍵交換である.
したがって,server.conf
のssl_ciphersの部分を以下のように変更する.
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";
Chromeのアドレスバーの鍵マークをクリックすると,ECDHE鍵交換が行われているのが確認できる.
HTTP Strict Transport Security (HSTS) ヘの対応
HSTSでは,サーバから"Strict-Transport-Security"というHTTPヘッダを送ることで,クライアントに常にHTTPSで通信するように強制させることができる.この指定はmax-ageに指定した期間クライアントにキャッシュされる.これにより,中間者攻撃より知らず知らずのうちに攻撃者に平文通信を盗聴されることを防ぐことができる.
SSL LabsのテストではHSTSが有効になっているとスコアが上がるとの事だったのでこれを有効にすることにする.Nginxではserver.conf
に以下の行を追加することでHSTSが有効になる.
add_header Strict-Transport-Security "max-age=15768000; includeSubdomains";
実際にHTTPSで接続した後,URLの"https"を"http"に変更してアクセスすると,すぐさまHTTPSのサイトにリダイレクトする.レスポンスヘッダを見ると"Strict-Transport-Security"ヘッダが付加されていることが確認できる.
再テスト
再びSSL Labsで診断した結果,めでたくA+を取得できた:)
最終的な設定ファイルserver.conf
は以下のとおり.
server { #listen 80; #listen [::]:80; listen 443 ssl http2; listen [::]:443 ssl http2; server_name sonickun.xyz; ssl_session_timeout 10m; ssl_certificate /etc/letsencrypt/live/sonickun.xyz/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/sonickun.xyz/privkey.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4"; ssl_prefer_server_ciphers on; ssl_dhparam /usr/local/nginx/conf/dhparam.pem; add_header Strict-Transport-Security "max-age=15768000; includeSubdomains"; location / { root /var/www/html; index index.html index.htm; } }
おわりに
Let's EncrptによるSSL証明書の取得は思ったよりも簡単に行うことができた.また,HTTPSにしたからといって安全と高をくくってはいけないと学んだ.
MozilaやGoogleをはじめとする多くの団体や企業があらゆるWebコンテンツをHTTPSに移行するように呼びかけており,SSL化されたWebサイトはどんどん増えている.GoogleではHTTPS ページが優先的にインデックスに登録されるようになる.
一方で,未だにHTTPSに対応していない大手のWebサービスも多々あり,それらのHTTPのコンテンツがHTTPSのWebサイト上で動作しないといった問題が起きている.
もちろんセキュリティ上の問題もあるが,この度のLet's Encryptのリリースによってこれらの問題が改善されていくことが期待される.
参考
- TLS, HTTP/2演習
- Let's EncryptとnginxでHTTP/2サーバを立てる - pixiv inside
- 無料SSL証明書の Let’s Encrypt が公開されたので実際に試してみた | Webセキュリティの小部屋
- Enable Perfect Forward Secrecy for nginx | AxiaCore
- Heartbleed以後の対策の1つで希望の光「Forward Secrecy」をnginxに設定する巻 - Qiita
- nginx - httpsだからというだけで安全?調べたら怖くなってきたSSLの話!? - Qiita
- HTTPS 化する Web をどう考えるか - Block Rockin’ Codes
- nginx - 我々はどのようにして安全なHTTPS通信を提供すれば良いか - Qiita