開発しているサービスの1つで、クレジットカード決済にStripeを利用しているものがあるのですが、サーバサイド(Ubuntu 12.04, PHP)とStripe APIとの間で通信を行う際に、ルート証明書が読み込めておらず決済が完了できない問題がありました。
同じ問題に遭遇する方がどれくらいいるか分からないのですが、少しハマってしまったので解決ログを残しておきます。
起こったこと
クライアントサイドのjs(公式ライブラリ)で決済用のトークンを発行したのち、そのトークンを使ってサーバサイド(公式のPHPライブラリ)で決済を完了させる際に、以下のエラーが発生しました。
Stripe\Error\ApiConnection: Could not verify Stripe's SSL certificate. Please make sure that your network is not intercepting certificates. (Try going to https://api.stripe.com/v1/charges in your browser.) If this problem persists, let us know at support@stripe.com.
(Network error [errno 60]: SSL certificate problem, verify that the CA cert is OK. Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed)
StripeのPHPライブラリは通信にcurlを利用していますが、CA証明書(/etc/ssl/certs/ca-certificates.crtなど)を読み込めておらず、Stripeの証明書チェックが通らなかったようです。
困ったこと
少しググると、この問題が起こるケースの多くはローカルにあるルート証明書が古すぎることで起こっているようでした。その場合は、例えばUbuntuであれば
sudo update-ca-certificates
としてやれば解決しているようです。
しかし、僕のケースではCA証明書は最新だったので、やはりcurl通信時に正しく読み込めていないようでした。
ですので、方法としては
curl_setopt($handler, [
CURLOPT_CAINFO => '/etc/ssl/certs/ca-certificates.crt'
]);
などのようにcurlを叩く前に明示的にCA証明書の場所を指定してやることが考えられます。が、curlのハンドラはStripeのライブラリ内に隠蔽されているのでこれはできず、うーんどうしたものかと思っていました。
解決した方法
Stripeは、\Stripe\HttpClient\CurlClientのインスタンスを別途用意し、カスタマイズすることができるようになっています。
さらに、わりと最近まではcurlのオプションまでは変更できなかったのですが、つい先日v3.12.0でこんなコードが追加され、事前にcurlのオプションを渡すことができるようになりました。ありがたい。
これがあればもう解決です。CurlClientのインスタンスを作る際にCURLOPT_CAINFOをセットしておき、そうやって用意したクライアントをStripeのライブラリに知らせます。
$curl = new \Stripe\HttpClient\CurlClient([
CURLOPT_CAINFO => '/etc/ssl/certs/ca-certificates.crt'
]);
\Stripe\ApiRequestor::setHttpClient($curl);
あとは、いつも通りに
\Stripe\Charge::create([...]);
することができました。
以上、何かのお役に立てれば幸いです。