uzullaがブログ

uzullaがブログです。

ニコニコ動画にhttps(SSL)接続できなかった件

発端としては、某所のOpenSSLのバージョンをあげたら問題が発生するようになった。(1.0.0->1.0.1)
それとは別に、自分の個人サーバー、二箇所でも問題が確認できたので、なにかあるのだと思う。

追記 20140413

ベストプラクティスをサジェストしたい記事ではなかったのですが、以外とブクマついてしまったので、一応。


書きたかった事
・今回オートネゴシエーションが問題があるっぽかった(これが書きたかった)
・気軽にパッケージアップデートすると、挙動が変わって悲しみにくれながらダウングレードしようとしても戻せないことがあってプロダクションコードを調査し、直すハメになる事があってつらいから戻せるように気を付けよう(これも書きたかった)


特に追記しておきたいのは以下
・例でSSLv3指定したのは余り意味はない
・今なら「TLSv1(PHPならtls://)がよい」


オマケ
・SSLv2はそもそも拒否されている(これはまあ当然感ある)


今ではもうTLSサポートしてないサーバーもすくない*1


検証環境

個人サーバーその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は同様にエラーになった。

まとめ

特にまとめるようなことはないが、SSLで接続できないときは、SSL/TLSのバージョンをかえてみるのもよいとおもいます。

番外まとめ

こういったよくわからないことはたまに発生するので、rpmをアップグレードするときは、現在のrpmのバージョンIDをきちんと書き残しておこう。
さらに、その過去バージョンのRPMが本当に入手できるか(downgradeなどで引けるか?)をきちんと確認してからやらないと、じつは手に入らないとかそう言う事があるので気をつけましょう。

*1:むしろSSLv3を切ってるサーバーの方が多いか

*2:ごく希にいけないサーバーもありますが

*3:ごく希にいけないサーバーもありますが