TLSを設定した
HTTPS対応を行った。ついでにHTTP/2にも対応しようと試みた。 結果としてはis-http2 は通過するがh2spec のテストは大半が失敗したため有効にしなかった。
tl;dr;
TLSの1次情報はRFC5246で関連RFCはいっぱいあった。
TLSはtlsワーキンググループで検討されている。 IETFのワーキンググループ は他にもたくさんあっても公開されているので気になるのを購読すると良い。 だけど非公式なスレッドごとに分類表示するサイト がありこっちの方が眺めやすいのでときどき使っている。
現在の設定一覧
今回やった設定。Session ticket, OCSP staplingは対応したい。
項目 | 選択 |
---|---|
HTTP/2 | no |
Protocol | TLSv1.2 |
Session cache | no |
Session ticket | no |
OCSP stapling | no |
Strict Transport Security(HSTS) | yes |
Public Key Pinning | HPKP(no) |
現在の設定サンプル(コメント付き)
TLS関連設定はserverディレクティブ内に下のように設定した。
|
|
設定の説明
TLSに必要な秘密鍵と証明書はssl_certificate_key,ssl_certificate で指定している。 暗号スイートの選択時にサーバー側の指定を優先しないと危ないのでssl_prefer_server_ciphers で指定している。
ssl_dhparam はDHE向けのDHパラメータを指定する。 許可した暗号スイート(ssl_ciphers)にはDHEを利用するものが無いためssl_dhparam はコメントアウトしている。
ssl_stapling からresolver まではOCSP staplingの設定。 TLSではサーバー証明書の失効を検証する。 失効確認手段として、CRL, OCSP, OCSP staplingがある。 OCSP staplingはサーバーでOCSPを行い証明書と共にクライアントへ提供するため効率がいいとされている。
ただしOCSP staplingが有効にできず調べている途中。
ssl_stapling,ssl_stapling_verify はOCSP staplingを有効にするパラメータ。 またOCSP staplingを有効化するとNginx がOCSPレスポンダーと通信する。 そこで使われるDNSリゾルバをresolverで指定している。
TLSではハンドシェイクを一部簡略するSession resumptionと呼ばれる機能がある。
サーバーでキャッシュする方式と暗号化してクライアント側に保持させる方式の2つある。 どちらも再開時にサーバー認証を(場合によって鍵交換を)省略できる。
ssl_session_timeout は上記2つのどちらにも有効なパラメータで名前の通りタイムアウトを決めます。 ssl_session_cache パラメタはTLSのセッション再開を行うためのキャッシュサイズを決めています。 幾つかのパラメタがありますがsharedの効率が良さそうでした。
現段階ではssl_session_tickets はoffにしている。 NginxのドキュメントによるとAES256, AES128で暗号化されるらしいものの、 鍵が使いまわされるらしく暗号利用モードやIV管理の実装を確認しないと安全か判断できず怖かったため。
add_header はTLSではなくHTTPの設定だが、今回はTLSに関わるのでメモを残した。
ここではStrict-Transport-Security ヘッダを追加している。 これで一度HTTPSで通信したブラウザに同一ドメインへの通信をHTTPSに限定するように伝えている。
できてないこと(今後の対応と順序)
少なくとも下は自覚している。
- OCSP staplingが有効になっていない
- TLS session ticketsを活かせていない
- ALPNが無効になっている
- HTTP/2を有効にできていない
- HSTS Preloading(hstspreloadへ申請)してない
- HPKP対応できてない
今回、HTTP/2を有効にできなかった理由は2つある。
httpsスキームを利用している場合にHTTP/1.1からHTTP/2へアップグレードするには TLS拡張のTLS-ALPNを利用するけど、 環境が古くALPNを有効にできなかったため。
そしてALPNが有効な環境を再構築しても理解不足でh2spec のテストを通過させられなかったため。 (is-http2 は通過する)
ちなみに、アプリケーションのプロトコルネゴシエーションに関するTLS拡張としてALPNとNPNの名前がしばしば見つかるけれど、NPNは標準化されなかったみたい。
HPKP対応はしていません。理解しきれてないため調べてから利用しようと判断した。
読んだ資料
詳しくないのでRFC5246を読み始める前に、 色々な記事をつまむところから始めた。
玉石混交だけど目を通したのを下に並べておく。
- SSL評価サイトでA+を取る設定
- NginxでHTTPS:ゼロから始めてSSLの評価をA+にするまで Part 1
- NginxでHTTPS:ゼロから始めてSSLの評価をA+にするまで Part 2
- 暗号と署名の話
- httpsだからというだけで安全?調べたら怖くなってきたSSLの話!?
- 錆びついたTLSを滑らかに、GoogleによるGREASE試験
- SSL/TLS Deployment Best Practices
- Security/Server Side TLS
- CRYPTREC暗号リスト
- SSL/TLS暗号設定ガイドライン
- セキュリティ関連NIST文書
他には具体例としてMozillaのSSL Configuration Generator のモダン環境の設定を確認した。 この設定ではTLSv1.1も排除されている。
CVEを日常的に追い続けるのは辛いのでbotを仕掛けるのが大事なようだ。 とりあえずtwitterはフォローしてalfredのWeb検索にCVEのキーワード検索とweb検索を登録した。
いまは隙間をみてプロフェッショナルSSL/TLSを読んでいる。
動作検証
実際のサーバーの検証は下を参考にする。 手段としてはssllabs(web service), sslscan(tool), nmap, opensslなどがある。
- ssllabs で確認する
- rbsec-sslscan でCLIで検査する
- NmapでSSLの設定と対応ブラウザの確認方法の通りに使ってみる
ssllabsでは以下の様になる。
nmapを使った脆弱性検査
またnseスクリプトは自分の環境(MBP)では*/usr/local/share/nmap/scripts/ssl-enum-ciphers.nse* にある。
|
|
HTTP/2へのアップグレード
TLS拡張でアプリケーションプロトコルのネゴシエーションを行う方式にNPN, ALPNがある。 RFCで仕様として固まったのはALPNだ。
opensslで確認してみる
|
|
ちなみにちゃんと準備すると下のようにALPNは有効になった。
|
|
他ツールで確認する
is-http2は公式ドキュメントに従ってnpmでインストールして公式通りに使ってみると簡単に動く。
h2specは詳しくサポート範囲を確認してくれるツールです。ちなみに確認したら散々な結果だった。 なので今回はhttp2は無効にした。
|
|
証明書取得の自動化を行った
TLS対応ではx.509証明書が必要になる。
全世界のHTTPS化を推進するにあたって重要なプロトコルとしてACMEが策定されている。 これは証明書のなかで最もレベルの低いドメイン証明書(DV)を自動で発行できる仕組みだ。 (他には企業証明書(OV), EVがある)
ACMEを利用することでDVを無料で発行できるLet’s Encryptという証明局がある。 またACMEクライアント実装にはcertbot というソフトウェアがある。
用語 | 説明 |
---|---|
ACME | IETFのworkingグループで検討されているプロトコルでX.509証明書の発行を自動で行える |
Let’s Encrypt | ACMEプロトコルによる非営利の認証局で無料でTLSのX.509証明書を発行する |
certbot | ACMEの有名なクライアントで自動で証明書の取得と配置を行う |
ACMEではhttp://${target_domain}/.well-known/acme-challenge/ 配下へのアクセスを利用して対象ドメインが認証要求元の管理下か自動で判断する。 ワイルドカードドメインは認証オブジェクトに含んではならない(MUST NOT)。 しかしSANsオプション付きの証明書は発行できる。
certbotでは**-d** によって証明したいドメインを指定する。 SANsオプションもサポートされている。
|
|
ちなみに -w で取得した証明書の配置先を指定する。 Let’s Encryptでは証明書の期限が30日なのでcronなどで定期的実行する必要がある。
certbotでは、その際**–keep-until-expiring** で不用意な更新を行わないようにできる。 また**–non-interactive** フラグによって対話モードを切らないとcronで支障をきたす。 また**–renew-hook** フラグで更新後に実行するスクリプトを指定できるので証明書更新後に必要なnginx の再起動などを指定する。
|
|
crondで動かすためのサンプル設定を残しておく。
|
|