

Rubyでサーバー間通信を行うために以下のコードを実装したのですが、以下のようなエラーが出てしまいます。足りない点などありましたらアドバイスいただけないでしょうか。

[code]

    SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
    
[/code]

実装

[code]

      require 'net/https'
      ～～
      https = Net::HTTP.new('ホスト', 443)
      https.open_timeout = SYSTEM_TIMEOUT_SEC
      https.read_timeout = SYSTEM_TIMEOUT_SEC
      https.use_ssl = true
      https.verify_mode = OpenSSL::SSL::VERIFY_PEER
      https.verify_depth = 5
      https.ca_file = "./cacert.pem" 
    
[/code]

cacert.pemは以下で取得し、上記の実装ファイルと同じ階層に置いています。  
<https://curl.haxx.se/docs/caextract.html>

以下を指定して証明書を無視した場合は通信できており、

[code]

    OpenSSL::SSL::VERIFY_NONE
    
[/code]

cert.pemが本当に存在しているのか以下のコマンドを実行すると、  
証明書情報が出力されていたので保存されているのだと思います。  
$ cat （ファイルパス）/cacert.pem

ちなみに、以下は接続したと出力されたのですが、HTTPSを指定すると  
接続を拒否されています。なにかサーバへの設定が必要なのでしょうか？

[code]

    $ wget -S --spider http://xx.xx.xx.xx
    スパイダーモードが有効です。リモートファイルが存在してるか確認します。
    --2018-05-10 09:27:27--  http://xx.xx.xx.xx/
    xx.xx.xx.xx:80 に接続しています... 接続しました。
    HTTP による接続要求を送信しました、応答を待っています...
      HTTP/1.1 200 OK
    　～～
    
    $  wget -S --spider https://xx.xx.xx.xx
    スパイダーモードが有効です。リモートファイルが存在してるか確認します。
    --2018-05-10 09:28:06--  https://xx.xx.xx.xx/
    xx.xx.xx.xx:443 に接続しています... 失敗しました: 接続を拒否されました.
    
[/code]


CC BY-SA 4.0
2018-06-16T13:29:23.783
44810
2018-12-14T09:02:25.467
2018-11-14T05:55:31.423
3060
12842
question
ruby https
HTTPS通信でcertificate verify failedエラー


原因が解るわけではないのですが、気になる点もありますので、回答としてまとめておきます。

  * `SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed`

CA 証明書(つまり `cacert.pem`)が見つからない場合に発生することが多いようです。  
以下の `https.ca_file = "./cacert.pem"` の項目を確認してください。

  * `https = Net::HTTP.new('ホスト', 443)`

`'ホスト'` と書かれているので判りにくいのですが、ここに IP
アドレスは指定できません。必ずホスト名を指定してください。そしてそのホスト名はサーバ証明書に記載されている必要があります。

  * `https.ca_file = "./cacert.pem"`

`./` の部分は、実装ファイルと同じ階層という意味でなく、実行時のカレントディレクトリを意味します。階層は合っていますか?

  * 「cert.pemが本当に存在しているのか」

`cert.pem` ではなく `cacert.pem` のはずです。

  * `wget -S --spider https://xx.xx.xx.xx`

`https = Net::HTTP.new('ホスト', 443)` の場合と同様、https では IP
アドレスの指定はできません。ホスト名を指定してください。

ただし、IP アドレスで指定したからといって「接続を拒否されました」にはならないはずで、  
nginx (または apache 等) やファイアウォールの設定を確認する必要があるのかもしれません。

以上です。解決につながることを祈ります。

* * *

HTTPS (というか SSL/TLS) では、証明書の検証をします。

例えば `https://example.com` にアクセスすると、example.com
がサーバ証明書を送ってくるので、その証明書が偽造されたものでないことと、その証明書の中の Common Name (CN) または Subject Alt
Name に `example.com` と記載されていることを確認します。

これが証明書の検証です。

`Net::HTTP.new('ホスト名', 443)` の場合、指定した`ホスト名`が証明書の中に記載されていることを確認します。

同様に、`Net::HTTP.new('IPアドレス', 443)`
の場合、指定した`IPアドレス`が証明書の中に記載されていることを確認します。しかし、証明書の中に IP
アドレスは記載されていないため、検証は失敗し、そこでエラーとなります。

この検証は、verify_mode を VERIFY_PEER にすると行われますが、VERIFY_NONE の時は行われません。VERIFY_NONE
にすると実行できるのは証明書を検証していないためです。


CC BY-SA 4.0
2018-06-18T12:59:31.863
44859
2018-06-20T10:57:46.780
2018-06-20T10:57:46.780
5288
5288
44810
answer