とあるWebサービスでPHPのcURLを利用してスクレイピングをしていたのですが、突然エラーが出るようになりました。
エラーを再現をしてみるとhttpsのサイトへ暗号化通信する際にエラーが出るようです。
「curl_error()」でエラーを出力してみると「SSL connect errorと出力されます。
試しに別のサーバで同様のプログラムを実行すると正常に終了します。どうやらサーバの環境が原因のようです。
以前、同じエラーが出力された際は、以下のオプションを付けて対処しました。
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
これはサーバの証明書を検証しないオプションで、オレオレ証明書などを使ってSSL通信しているサイトへアクセスする際に有効な対策です。(もちろんセキュリティ上のリスクは上がる)
今回はこれでは改善しません。
そこで似た症状を検索していると、暗号化通信に利用するNSS(Network Security Services)が古いことが原因で同様の症状が出るとのこと。早速バージョンを調べてみます。
# yum info nss
Installed Packages
Name : nss
Arch : x86_64
Version : 3.19.1
Release : 8.el6_7
Size : 2.6 M
Repo : installed
From repo : updates
Summary : Network Security Services
URL : http://www.mozilla.org/projects/security/pki/nss/
License : MPLv2.0
Description : Network Security Services (NSS) is a set of libraries designed to
: support cross-platform development of security-enabled client and
: server applications. Applications built with NSS can support SSL
: v2 and v3, TLS, PKCS #5, PKCS #7, PKCS #11, PKCS #12, S/MIME,
: X.509 v3 certificates, and other security standards.
(省略)
Name : nss
Arch : x86_64
Version : 3.36.0
Release : 9.el6_10
Size : 865 k
Repo : updates
Summary : Network Security Services
URL : http://www.mozilla.org/projects/security/pki/nss/
License : MPLv2.0
Description : Network Security Services (NSS) is a set of libraries designed to
: support cross-platform development of security-enabled client and
: server applications. Applications built with NSS can support SSL
: v2 and v3, TLS, PKCS #5, PKCS #7, PKCS #11, PKCS #12, S/MIME,
: X.509 v3 certificates, and other security standards.
どうやら今入ってるのが3.19.1で、最新は3.36.0とのこと。
調べてみると3.19.1は最新のTLS1.2に対応していないとのこと。これではAWSなどTLS1.2を利用したサイトへ接続できません。
早速アップデートします。
# yum update nss (省略) Dependencies Resolved ================================================================================ Package Arch Version Repository Size ================================================================================ Updating: nss x86_64 3.36.0-9.el6_10 updates 865 k Updating for dependencies: nspr x86_64 4.19.0-1.el6 base 114 k nss-sysinit x86_64 3.36.0-9.el6_10 updates 53 k nss-tools x86_64 3.36.0-9.el6_10 updates 460 k nss-util x86_64 3.36.0-1.el6 base 72 k Transaction Summary ================================================================================ Upgrade 5 Package(s) Total download size: 1.5 M Is this ok [y/N]: y ← yを押してエンター (省略) Complete!
無事インストール完了で治るかと思いきやエラーが出続けています。
TLS handshakeの状態を見るべく「--verbose」オプションを付けてコマンド上で実行します。(ドメインやIPはダミーです)
# curl --verbose --head https://example.com/
* About to connect() to example.com port 443 (#0)
* Trying 198.164.0.0... connected
* Connected to example.com (198.164.0.0) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* NSS error -12286
* Closing connection #0
* SSL connect error
curl: (35) SSL connect error
「NSS error」や「SSL connect error」と出ています。
ひょっとするとnssだけでなくcurlも古いのかもと、見てみます。
# yum info curl
Installed Packages
Name : curl
Arch : x86_64
Version : 7.19.7
Release : 46.el6
Size : 348 k
Repo : installed
From repo : base
Summary : A utility for getting files from remote servers (FTP, HTTP, and
: others)
URL : http://curl.haxx.se/
License : MIT
Description : cURL is a tool for getting files from HTTP, FTP, FILE, LDAP,
: LDAPS, DICT, TELNET and TFTP servers, using any of the supported
: protocols. cURL is designed to work without user interaction or
: any kind of interactivity. cURL offers many useful capabilities,
: like proxy support, user authentication, FTP upload, HTTP post,
: and file transfer resume.
Available Packages
Name : curl
Arch : x86_64
Version : 7.19.7
Release : 53.el6_9
Size : 197 k
Repo : base
Summary : A utility for getting files from remote servers (FTP, HTTP, and
: others)
URL : http://curl.haxx.se/
License : MIT
Description : cURL is a tool for getting files from HTTP, FTP, FILE, LDAP,
: LDAPS, DICT, TELNET and TFTP servers, using any of the supported
: protocols. cURL is designed to work without user interaction or
: any kind of interactivity. cURL offers many useful capabilities,
: like proxy support, user authentication, FTP upload, HTTP post,
: and file transfer resume.
Versionの7.19.7は同じですが、Releaseは46.el6と53.el6_9でかなりバージョンが違うようです。
古いものに固執する理由もないので、アップデートします。
# yum update curl (省略) Dependencies Resolved ================================================================================ Package Arch Version Repository Size ================================================================================ Updating: curl x86_64 7.19.7-53.el6_9 base 197 k Updating for dependencies: libcurl x86_64 7.19.7-53.el6_9 base 169 k Transaction Summary ================================================================================ Upgrade 2 Package(s) Total download size: 367 k Is this ok [y/N]: y (省略) Complete!
そして動作するかチェック。
# curl --verbose --head https://example.com/
* About to connect() to example.com port 443 (#0)
* Trying 198.164.0.0... connected
* Connected to example.com (198.164.0.0) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: CN=*.example.com
* start date: Sep 15 00:00:00 2018 GMT
* expire date: Oct 15 12:00:00 2019 GMT
* common name: *.example.com
* issuer: CN=Amazon,OU=Server CA 1B,O=Amazon,C=US
> HEAD / HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: example.com
> Accept: */*
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
Content-Type: text/html; charset=UTF-8
< Connection: keep-alive
Connection: keep-alive
< Date: Mon, 25 Mar 2019 03:24:03 GMT
Date: Mon, 25 Mar 2019 03:24:03 GMT
< Server: Apache/2.2.34 (Amazon)
Server: Apache/2.2.34 (Amazon)
< Cache-Control: max-age=600
Cache-Control: max-age=600
< Expires: Mon, 25 Mar 2019 03:34:03 GMT
Expires: Mon, 25 Mar 2019 03:34:03 GMT
< Age: 508
Age: 508
< X-Cache: Hit from cloudfront
X-Cache: Hit from cloudfront
< Via: 1.1 debbc427c5c43fa2029c8585e5059a5f.cloudfront.net (CloudFront)
Via: 1.1 debbc427c5c43fa2029c8585e5059a5f.cloudfront.net (CloudFront)
< X-Amz-Cf-Id: oOn_jQKLAgD3lsb2V08siaIc9NvSJ3knLPhqiOsJp-elbHoaIeW4iw==
X-Amz-Cf-Id: oOn_jQKLAgD3lsb2V08siaIc9NvSJ3knLPhqiOsJp-elbHoaIeW4iw==
<
* Connection #0 to host example.com left intact
* Closing connection #0
無事「HTTP/1.1 200 OK」となってます。(ちなみにこのサンプルはAWSを利用したサイトの場合です)
「TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256」となっているのでやはりTLS1.2への対応が必要だったみたいです。
ちなみにコマンドラインで成功してもPHPで失敗する場合は単純にキャッシュの問題かもしれません。
私の場合は半日ほど放置していたらPHPでも正常にスクレイピングできるようになりました。
というわけで、curl_getinfo($ch, CURLINFO_HTTP_CODE)を設定したり、NSSをアップデートしても「SSL connect error」が出る場合はcurl自体のアップデートも必要かもしれないよ。という投稿でした。