RubyにおけるHTTPS通信

HTTPS (SSL)のお勉強

Ruby (OpenSSL)におけるルートCA証明書

% ruby -r openssl -e 'p OpenSSL::X509::DEFAULT_CERT_FILE'
"/usr/lib/ssl/cert.pem"
% ls /usr/lib/ssl/cert.pem
ls: cannot access /usr/lib/ssl/cert.pem: そのようなファイルやディレクトリはありません
% ruby -r openssl -e 'p OpenSSL::X509::DEFAULT_CERT_DIR'
"/usr/lib/ssl/certs"
% ls /usr/lib/ssl/certs/
02b73561.0@
0481cb65.0@
052e396b.0@
06d75f4b.0@
0c364b2d.0@
0dbd0096.0@
0e82f83a.0@
10d149a2.0@
11a09b38.0@
11f154d6.0@
(ry
      • DebianではFILEの方は存在しないがDIRには大量の証明書があるようだ
      • ちなみにmswinとcygwin用のRubyでは証明書はないようだ

net/httpsを使ったHTTPS通信

#!/usr/bin/ruby

require 'net/https'

https = Net::HTTP.new('secure.nicovideo.jp', 443)
https.use_ssl = true
https.ca_file = 'GTE_CyberTrust_Global_Root.pem'
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
https.verify_depth = 5

https.start {|w|
  response = w.get('/')
  puts response.body
}
  • ca_fileは絶対パスで指定する必要があるようだ
    • OpenSSL::X509::DEFAULT_CERT_DIRに同名のファイルが存在しても読んでくれないようだ
      • ソース読んで確認したわけではないので間違っているかも
  • GTE_CyberTrust_Global_Root.pemはDebianの上記のディレクトリ(/usr/lib/ssl/certs)からコピーしてきたもの
    • あるいはFirefox3.6からも取得可能
      1. https://secure.nicovideo.jp/にアクセス
      2. URLの左隣の緑の部分をクリック
      3. 「詳細を表示」をクリック
      4. 「証明書を表示」をクリック
      5. 「詳細」タブを開く
      6. 証明書の階層から「GTE Cyber Trust Global Root」を選択
      7. 「エクスポート」をクリック
      8. ファイルの種類「X509 証明書 (PEM)」で保存
    • IE8の場合・・・がうまくいかない
      • 似たような感じでファイルのエクスポートができるようだがそのファイルを使うとうまくアクセスできない
      • 基本が分かってないのでこういうとこで躓いちゃうなあ
  • うまく行くと下記のような出力が得られる
<HTML>
<HEAD>
</HEAD>
<BODY>
<A HREF="payment">payment</A>
</BODY>
</HTML>
  • 失敗した場合は以下のようなエラーが出力される
/usr/lib/ruby/1.8/net/http.rb:586:in `connect': SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (OpenSSL::SSL::SSLError)
        from /usr/lib/ruby/1.8/net/http.rb:586:in `connect'
        from /usr/lib/ruby/1.8/net/http.rb:553:in `do_start'
        from /usr/lib/ruby/1.8/net/http.rb:542:in `start'
        from ./hoge.rb:12
  • 証明書なしでも以下のようにすると接続できてしまう
#!/usr/bin/ruby

require 'net/https'

https = Net::HTTP.new('secure.nicovideo.jp', 443)
https.use_ssl = true
https.verify_mode = OpenSSL::SSL::VERIFY_NONE    # ←ここをPEERからNONEに変更
https.verify_depth = 5

https.start {|w|
  response = w.get('/')
  puts response.body
}
    • ブラウザでいうところの安全ではない接続に相当するか

Mechanizeを用いたHTTPS接続

  • MechanizeのSSL周りのデフォルトの設定を確認
#!/usr/bin/ruby

require 'rubygems'
require 'mechanize'

agent = WWW::Mechanize.new
puts agent.ca_file
puts agent.cert
puts agent.key
puts agent.pass
puts agent.verify_callback
    • 結果は全部nil
nil
nil
nil
nil
nil

どれも設定されてない https アクセスである場合は、検証されないアクセスである OpenSSL::SSL::VERIFY_NONE による通信が行われます。

  • つまり以下の例は検証されないアクセスになっているらしい
#!/usr/bin/ruby

require 'rubygems'
require 'mechanize'

agent = WWW::Mechanize.new
puts agent.get('https://secure.nicovideo.jp/').body
  • 安全なアクセスを行うには以下のように証明書を指定する必要があるらしい
#!/usr/bin/ruby

require 'rubygems'
require 'mechanize'

agent = WWW::Mechanize.new
agent.ca_file = 'GTE_CyberTrust_Global_Root.pem'
puts agent.get('https://secure.nicovideo.jp/').body

TLS/SSL ハンドシェイクの結果は SSL_get_verify_result を使ってチェックできる

    • [TODO] まだ関数の使い方が分からず未調査