ニコニコ動画にhttps(SSL)接続できなかった件
発端としては、某所のOpenSSLのバージョンをあげたら問題が発生するようになった。(1.0.0->1.0.1)
それとは別に、自分の個人サーバー、二箇所でも問題が確認できたので、なにかあるのだと思う。
追記 20140413
ベストプラクティスをサジェストしたい記事ではなかったのですが、以外とブクマついてしまったので、一応。
書きたかった事
・今回オートネゴシエーションが問題があるっぽかった(これが書きたかった)
・気軽にパッケージアップデートすると、挙動が変わって悲しみにくれながらダウングレードしようとしても戻せないことがあってプロダクションコードを調査し、直すハメになる事があってつらいから戻せるように気を付けよう(これも書きたかった)
特に追記しておきたいのは以下
・例でSSLv3指定したのは余り意味はない
・今なら「TLSv1(PHPならtls://)がよい」
オマケ
・SSLv2はそもそも拒否されている(これはまあ当然感ある)
検証環境
個人サーバーその1、さくらのVPS、接続できず。
$ cat /etc/redhat-release CentOS release 6.5 (Final) $ openssl version OpenSSL 1.0.1e-fips 11 Feb 2013 $ rpm -qa |grep openssl openssl-1.0.1e-16.el6_5.7.x86_64
個人サーバーその2、Vultr、接続できず。
そん1と同じ構成。
個人サーバーその3、さくらのVPS、接続できた
$ cat /etc/redhat-release CentOS release 5.10 (Final) $ openssl version OpenSSL 0.9.8e-fips-rhel5 01 Jul 2008 $ rpm -qa |grep openssl openssl-0.9.8e-27.el5_10.1
先に書いておくが、直近のHeartBleedでのパッケージアップデートとは関係がなかった。(ダウングレードしても、接続できなかった)
例
単純に https://secure.nicovideo.jp に接続しにいくことで確かめられた。
# wget https://secure.nicovideo.jp --2014-04-11 21:10:28-- https://secure.nicovideo.jp/ secure.nicovideo.jp をDNSに問いあわせています... 202.248.110.180 secure.nicovideo.jp|202.248.110.180|:443 に接続しています... 接続しました。 SSL による接続が確立できません。
失敗まで結構待つ、タイムアウトをしているようだ。OpenSSL 0.9系、1.0.0系ではこの現象は発生しない模様。
これが、wgetのsecure-protocolで、SSLv3を指定してやると通る。
(追記しましたが、いまなら「TLSv1」のほうが良いでしょう*2)
# wget --secure-protocol=SSLv3 https://secure.nicovideo.jp/ --2014-04-11 22:04:44-- https://secure.nicovideo.jp/ secure.nicovideo.jp をDNSに問いあわせています... 202.248.110.180 secure.nicovideo.jp|202.248.110.180|:443 に接続しています... 接続しました。 HTTP による接続要求を送信しました、応答を待っています... 302 Found 場所: https://secure.nicovideo.jp/secure/ [続く] (以下略)
secure-protocolはいくつか指定できるが、TLSv1、SSLv3は問題無く、SSLv2でエラー、autoは前述のタイムアウト的なエラーになった。
例2
これはPHPのstream_socket_clientでも同様であり、以下コードが動作しない。
<?php $socket = stream_socket_client("ssl://secure.nicovideo.jp" . ':' . "443", $errno, $errstr, (int) 10, STREAM_CLIENT_CONNECT); if (!$socket) { echo "error!"; } -- # php test.php PHP Warning: stream_socket_client(): SSL: crypto enabling timeout in /root/tmp/test.php on line 6 PHP Warning: stream_socket_client(): Failed to enable crypto in /root/tmp/test.php on line 6 PHP Warning: stream_socket_client(): unable to connect to ssl://secure.nicovideo.jp:443 (Unknown error) in /root/tmp/test.php on line 6
以下のようにsslv3を指定すると動く。
(追記しましたが、いまなら「tls://」のほうが良いでしょう*3)
<?php $socket = stream_socket_client("sslv3://secure.nicovideo.jp" . ':' . "443", $errno, $errstr, (int) 10, STREAM_CLIENT_CONNECT); if (!$socket) { echo "error!"; }
このほかに、wget同様に指定できるものがあるが、sslはwgetのauto相当っぽくタイムアウト待ちになり、sslv2は同様にエラーになった。