HTTPS通信の疎通確認に覚えておきたい3つのコマンド


SSL証明書のハッシュ関数が、世界的にSHA-2に移行してきていますね。セキュアなAPIを公開する人や、そういうAPIをよく叩く人は、移行に備えていますか?

通信エラーに直面した時はハッシュ関数だけでなく、いくつかの観点で疎通確認をして、問題を切り分けることが重要です。時期が時期だからといってSHA-2のせいにしてはいけません。ここではHTTPS通信の疎通確認に便利なコマンドを3つ紹介します。

curl

言わずと知れたHTTP/HTTPS通信でダウンロードできるコマンド。下記のコマンドラインオプションを指定すれば、特定のSSL/TSLのバージョンでのHTTPS通信を試すことができる。

  • 覚えておきたいオプション
オプション 内容
--sslv2 SSL2.0で通信
--sslv3 SSL3.0で通信
--tlsv1 TLS1.Xで通信
--tlsv1.0 TLS1.0で通信
--tlsv1.1 TLS1.1で通信
--tlsv1.2 TLS1.2で通信
-k 危なそうな証明書でも通信してくれる
-v 通信時の色々な情報を出してくれる
-s 無駄な情報は省いてくれる
  • example.comにSSL3.0でHTTPSでアクセスしてみる1
$ curl -s -v --sslv3 https://example.com 1> /dev/null
* Rebuilt URL to: https://example.com/
*   Trying 93.184.216.34...
* Connected to example.com (93.184.216.34) port 443 (#0)
* SSL peer handshake failed, the server most likely requires a client certificate to connect
* Closing connection 0

おっと、SSLハンドシェイクで通信に失敗したようですね。SSL3.0はPOODLE脆弱性問題があります。ちゃんとexample.comでは無効にしているようですね。以下のようにTLS1.2ではきちんとできました。DigiCertの証明書で、SHA-2に移行済みですね。curlはオプションが覚えやすいので、サクッとSSL/TLSのバージョンごとの疎通確認をしたい時に便利です。

$ curl -s -k -v --tlsv1.2 https://example.com 1> /dev/null
* Rebuilt URL to: https://example.com/
*   Trying 93.184.216.34...
* Connected to example.com (93.184.216.34) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
* Server certificate: www.example.org
* Server certificate: DigiCert SHA2 High Assurance Server CA
* Server certificate: DigiCert High Assurance EV Root CA
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
...
  • オレオレ証明書を試す
$ curl -v -k https://localhost

正式な証明書を使う前に、一旦ダミーの証明書で通信の挙動を知りたいという人もいるはず。
いわゆるオレオレ証明書を使いたい人は-kオプションをつければ、途中動作が止まらず最後まで通信ができます。

openssl

やはりSSLと言ったらコイツでしょう。SSL証明書の作成だけでなく、特定の暗号アルゴリズムでの情報の暗号化や復号化など、無駄に高機能なコマンドです。特定のドメインにアクセスし、SSL証明書の中身を詳細に表示することができます。

オプション 内容
s_client SSL/TLSクライアントとして動作する
-showcerts 全てのSSL証明書を表示する
-connect ドメインとポート番号を指定
  • example.comのSSL証明書情報を表示する2
$ openssl s_client -connect example.com:443 -showcerts < /dev/null 2>&1
(※結果は長いので省略)

当然opensslでもcurlのように特定のSSL/TSLでの通信、さらにはクライアント証明書と秘密鍵を指定できたり、証明書チェーンを表示できたり……とopensslはあまりに色々できすぎるのでここでは割愛します。ちなみに下記のページによくまとまっていました。
https://siguniang.wordpress.com/2014/08/09/openssl-as-ssl-client/

ただ、私の場合は上記の例だけまず覚えておいて、必要に応じてgrepして情報を取り出しています。あまり色々覚えられないので。

  • SSL証明書チェーンを表示する
$ openssl s_client -connect example.com:443 -showcerts < /dev/null 2>&1 | grep '[si]:'
 0 s:/C=US/ST=California/L=Los Angeles/O=Internet Corporation for Assigned Names and Numbers/OU=Technology/CN=www.example.org
   i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert SHA2 High Assurance Server CA
 1 s:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert SHA2 High Assurance Server CA
   i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA

nmap

ポートスキャンやPINGスイープなど、スーパーハカーな方が使うコマンドという印象が強いnmapですが、通信に使えるSSL/TSLバージョンの表示や、対応している暗号化スイートの一覧を見やすく表示する機能があります。

オプション 内容
--script nmapの拡張スクリプト(NES)を使う。
-p ポート番号を指定する

ssl-enum-ciphersという拡張スクリプトがあり、これを使うと特定のドメインに何回もアクセスして対応している暗号化スイートを表示してくれます。私の環境ではnmapをインストールした後デフォルトでつかえたのですが、環境によっては手動でスクリプトを入れなければいけないかもしれません。

$ nmap --script ssl-enum-ciphers -p 443 example.com

Starting Nmap 6.47 ( http://nmap.org ) at 2015-12-03 15:50 JST
Nmap scan report for example.com (93.184.216.34)
Host is up (0.027s latency).
PORT    STATE SERVICE
443/tcp open  https
| ssl-enum-ciphers:
|   SSLv3: No supported ciphers found
|   TLSv1.0:
|     ciphers:
|       TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - strong
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - strong
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - strong
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA - strong
|       TLS_RSA_WITH_AES_128_CBC_SHA - strong
|       TLS_RSA_WITH_AES_256_CBC_SHA - strong
|       TLS_RSA_WITH_CAMELLIA_128_CBC_SHA - strong
|       TLS_RSA_WITH_CAMELLIA_256_CBC_SHA - strong
|       TLS_RSA_WITH_SEED_CBC_SHA - strong
|     compressors:
|       NULL
|   TLSv1.1:
|     ciphers:
|       TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - strong
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - strong
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - strong
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA - strong
|       TLS_RSA_WITH_AES_128_CBC_SHA - strong
|       TLS_RSA_WITH_AES_256_CBC_SHA - strong
|       TLS_RSA_WITH_CAMELLIA_128_CBC_SHA - strong
|       TLS_RSA_WITH_CAMELLIA_256_CBC_SHA - strong
|       TLS_RSA_WITH_SEED_CBC_SHA - strong
|     compressors:
|       NULL
|   TLSv1.2:
(※以下続く)

example.comにはなさそうですが、RC4など、塞ぐべき古い暗号化スイートを見つけるのに便利そうですね。


  1. レスポンスボディの表示を防ぐため 1> /dev/nullを書いてます 

  2. s_clientは標準入力を受け取ろうとするので、そのまま表示するように < /dev/null としています。