発生した問題
Rubyでopen-uriライブラリを使用してWebスクレイビングをしていたところ、openメソッド実行時に以下のエラーが表示され、サイトにアクセスできなかった。
/home/user/.rbenv/versions/3.0.3/lib/ruby/3.0.0/net/protocol.rb:46:in `connect_nonblock': SSL_connect returned=1 errno=0 state=error: dh key too small (OpenSSL::SSL::SSLError)
この後、Ubuntu上でcurlコマンド使用時に
$ curl (URL)
[1] 3589
curl: (35) error:141A318A:SSL routines:tls_process_ske_dhe:dh key too small
というエラーが表示され、curlコマンドでもサイトにアクセスできなかった。
私が取った解決法を2パターンまとめる。
また、この問題はUbuntuの設定の問題なので、Ruby以外の言語で同様のことが起きた際も解決に役立つかもしれない。
Ubuntu上でcurlコマンドを使ったときに上と同様の表示になる場合は、以下の解決法を試してみてほしい。
前提条件
筆者の環境はWindows11上のWSL2を用いてUbuntu20.04LTSを起動している。また、Ruby3.03を使用して開発している。
$ uname -a
Linux LAPTOP-01OUKT07 5.15.57.1-microsoft-standard-WSL2 #1 SMP Wed Jul 27 02:20:31 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.5 LTS"
$ ruby -v
ruby 3.0.3p157 (2021-11-24 revision 3fb7d2cadc) [x86_64-linux]
2つの解決法の概説
解決法1. OSの設定を変更する
Ubuntuの設定ファイルであるopenssl.cnfを書き換える方法
- 良い点: 設定が一度で終わり、以降は気にしなくてよくなる
- 悪い点: OS全体のセキュリティレベルが下がる
解決法2. Rubyのソースコード中に設定を書き込む
ソースコード中で一時的に設定を行う方法
- 良い点: プログラムの中で設定が完結し、他に影響を与えない
- 悪い点: プログラムを書くたびにソースコード中に設定を記載しないといけない
開発環境なら解決法1が楽で良いが、プログラムをお客様に納品する場合などは解決法2が適しているだろう。
解決法1
こちらの記事と全く同じ方法なのでこちらを確認してほしい。
https://qiita.com/sidious/items/f9a6eaaf6b1786d6a92c
筆者の場合、openssl.cnfはこの記事の通り"/usr/lib/ssl"配下にあった。
ファイルの編集はviコマンドやnanoコマンドなどでできる。
分からなければ「Ubuntu ファイル編集」などで検索してほしい。
筆者はnanoコマンドが好みなのでそれを使う。
$ sudo nano /usr/lib/ssl
ファイルの冒頭に
openssl_conf = default_conf
を追加し、ファイルの末尾に
[ default_conf ]
ssl_conf = ssl_sect
[ssl_sect]
system_default = system_default_sect
[system_default_sect]
MinProtocol = TLSv1.2
CipherString = DEFAULT:@SECLEVEL=1
を追加する。
Ubuntu等の再起動は不要で、openssl.cnfを書き換えた直後からcurlコマンドが通るようになる。
解決法2
こちらの記事を参考にした。
https://blog.n-z.jp/blog/2020-12-18-dh-key-too-small-workaround-open-uri.html
細かいことは記事を確認してほしいが、要はソースコード中(openメソッド実行前)に
require 'net/http'
Net::HTTP.prepend Module.new {
def use_ssl=(flag)
super
self.ciphers = "DEFAULT:!DH"
end
}
を貼り付けることで解決できる。
このコードは、cipher(サイファー)の設定からDHを除外するという内容である。
open-uriからはこの設定変更ができないため、net/httpから変更する。
どうしてこのエラーが起こるのか
opensslのセキュリティ設定が強化されたからである。
(参考:https://github.com/openssl/openssl/commit/70b0b977f73cd70e17538af3095d18e0cf59132e)
opensslのバージョンが1.1.1になったタイミングでこの変更が適用され、暗号化に用いる鍵長がデフォルトで2048ビットとなった。
記事冒頭に示したエラー文は、SSL/TLSの暗号化で使われている鍵長が短すぎることを示しており、接続が弾かれている。