【PHP8.x】CURLOPT_PINNEDPUBLICKEY定数の使い方
CURLOPT_PINNEDPUBLICKEY定数の使い方について、初心者にもわかりやすく解説します。
基本的な使い方
CURLOPT_PINNEDPUBLICKEY定数は、PHPのcURL拡張機能でSSL/TLS通信のセキュリティを強化するための公開鍵ピンニングを設定する際に使用します。公開鍵ピンニングは、接続先のサーバーが提示する公開鍵と、あらかじめ登録された信頼できる鍵を照合することで、中間者攻撃などのセキュリティ脅威から通信を保護する仕組みです。
この定数には、信頼する公開鍵の情報を文字列として指定します。指定方法は主に二通りあります。一つは、公開鍵を含むPEM形式またはDER形式の証明書ファイルへのパスです。もう一つは、検証したい公開鍵のSPKI(Subject Public Key Info)のSHA256ハッシュ値を直接指定する方法です。ハッシュ値を指定する際は、「sha256//」というプレフィックスに続けて、Base64でエンコードされたSHA256ハッシュ値を記述します。複数の公開鍵を信頼する場合には、これらをセミコロン(;)で区切って列挙できます。
CURLOPT_PINNEDPUBLICKEYが設定されている場合、cURLは接続先のサーバーの公開鍵と、このオプションで指定された情報を照合します。サーバーの公開鍵が、指定されたいずれの鍵とも一致しない場合、cURLは接続を拒否します。これにより、偽装された公開鍵を持つサーバーへの接続が未然に防がれ、通信の安全性が高まります。
構文(syntax)
1<?php 2$ch = curl_init(); 3curl_setopt($ch, CURLOPT_URL, "https://example.com"); 4curl_setopt($ch, CURLOPT_PINNEDPUBLICKEY, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="); 5$response = curl_exec($ch); 6curl_close($ch); 7?>
引数(parameters)
引数なし
引数はありません
戻り値(return)
戻り値なし
戻り値はありません
サンプルコード
PHP cURL:CA証明書と公開鍵ピンニングを設定する
1<?php 2 3/** 4 * 安全なHTTPSリクエストをcURLを使用して実行します。 5 * SSL/TLS証明書検証 (CURLOPT_CAINFO) と公開鍵ピンニング (CURLOPT_PINNEDPUBLICKEY) の設定方法を示します。 6 * 7 * @param string $url リクエストを送信するターゲットURL。 8 * @param string|null $caInfoPath CA証明書バンドルファイルへのパス。nullの場合、PHPのデフォルトCAストアが使用されます。 9 * @param string|null $pinnedPublicKey 公開鍵ピンニングのパス (ファイルパス) またはBase64エンコードされたSHA256ハッシュ (例: "sha256//...")。 10 * @return string|false 成功した場合はレスポンス本文、失敗した場合はfalse。 11 */ 12function performSecureCurlRequest( 13 string $url, 14 ?string $caInfoPath = null, 15 ?string $pinnedPublicKey = null 16): string|false { 17 // cURLセッションを初期化します。 18 $ch = curl_init(); 19 20 // cURLオプションを設定します。 21 curl_setopt($ch, CURLOPT_URL, $url); 22 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 実行結果を文字列で取得するように設定します。 23 24 // --- SSL/TLS検証の基本設定 (推奨) --- 25 // ピア(サーバー)の証明書を検証することを有効にします。セキュリティのために強く推奨されます。 26 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); 27 // ホスト名の検証を有効にします。PHP 8では '2' が推奨され、証明書のCN/SANとホスト名を比較します。 28 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); 29 30 // CA証明書バンドルファイルを指定 (キーワード: CURLOPT_CAINFO) 31 // ここには、信頼するルート証明書を含む実際のCAバンドルファイルへのパスを指定します。 32 // この設定により、サーバー証明書が指定された信頼できるCAによって発行されたものであることを検証します。 33 if ($caInfoPath !== null && file_exists($caInfoPath)) { 34 curl_setopt($ch, CURLOPT_CAINFO, $caInfoPath); 35 } elseif ($caInfoPath !== null) { 36 // ファイルが見つからない場合は警告をログに出力します。 37 error_log("警告: CA証明書ファイル '{$caInfoPath}' が見つかりません。CURLOPT_CAINFOは設定されません。", 0); 38 } 39 40 // サーバーの公開鍵のピンニングを設定 (キーワード: CURLOPT_PINNEDPUBLICKEY) 41 // ここには、サーバーの公開鍵のハッシュ(Base64エンコードされたSHA256など)を含むファイルへのパス、 42 // または直接ハッシュ文字列(例: "sha256//<base64-encoded-hash>")を指定します。 43 // 公開鍵ピンニングは、特定の公開鍵のみを信頼することで中間者攻撃 (MITM) を防ぐのに役立ちますが、 44 // サーバーの公開鍵が変更された際のメンテナンスが必要です。 45 // 正しいハッシュは、`openssl s_client -connect example.com:443 | openssl x509 -pubkey -noout | openssl pkey -pubin -outform DER | openssl dgst -sha256 -binary | openssl enc -base64` 46 // のようなコマンドで取得できます。 47 if ($pinnedPublicKey !== null) { 48 if (file_exists($pinnedPublicKey) || str_starts_with($pinnedPublicKey, 'sha256//')) { 49 curl_setopt($ch, CURLOPT_PINNEDPUBLICKEY, $pinnedPublicKey); 50 } else { 51 // 無効なパスまたは形式の場合は警告をログに出力します。 52 error_log("警告: ピンニング公開鍵の設定 '{$pinnedPublicKey}' は無効なパスまたは形式です。CURLOPT_PINNEDPUBLICKEYは設定されません。", 0); 53 } 54 } 55 56 // cURLリクエストを実行します。 57 $response = curl_exec($ch); 58 59 // cURL実行中にエラーが発生したかチェックします。 60 if (curl_errno($ch)) { 61 $error_msg = curl_error($ch); 62 error_log("cURLエラー ({$url}): " . $error_msg, 0); 63 curl_close($ch); 64 return false; 65 } 66 67 // HTTPステータスコードを取得し、エラーかどうかをチェックします。 68 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); 69 if ($httpCode >= 400) { 70 error_log("HTTPエラー ({$url}): ステータスコード {$httpCode}", 0); 71 curl_close($ch); 72 return false; 73 } 74 75 // cURLセッションを閉じます。 76 curl_close($ch); 77 78 return $response; 79} 80 81// --- サンプルコードの使用例 --- 82 83// 実際のリクエスト先URLを指定してください。安全な検証のためにはHTTPSサイトを指定することを推奨します。 84$targetUrl = "https://example.com"; 85 86// コードが単体で動作し、初心者にも理解しやすいようにダミーファイルを生成します。 87// 実際の運用では、信頼できるCA証明書ファイルと適切な公開鍵ハッシュを準備してください。 88$dummyCaInfoPath = __DIR__ . '/dummy_cacert.pem'; 89// このハッシュは 'example.com' の実際の公開鍵ハッシュではありません。 90// 実際のハッシュは、上記コメントのopensslコマンドなどで取得してください。 91$dummyPinnedPublicKeyPath = __DIR__ . '/dummy_pinned_public_key.txt'; 92 93// ダミーのCA証明書ファイルを作成 94file_put_contents($dummyCaInfoPath, "This is a dummy CA certificate file for demonstration purposes."); 95// ダミーの公開鍵ピンニングファイルを作成(Base64エンコードされたSHA256ハッシュを含む) 96file_put_contents($dummyPinnedPublicKeyPath, "sha256//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="); // ダミーのハッシュ 97 98echo "URL: {$targetUrl} へのセキュアなcURLリクエストを試行中...\n\n"; 99 100// CA証明書と公開鍵ピンニングを設定してリクエストを実行します。 101$result = performSecureCurlRequest($targetUrl, $dummyCaInfoPath, $dummyPinnedPublicKeyPath); 102 103if ($result !== false) { 104 echo "cURLリクエスト成功!\n"; 105 // レスポンスが長い場合は一部のみ表示します。 106 echo "レスポンスの一部:\n" . substr($result, 0, 500) . "...\n"; 107} else { 108 echo "cURLリクエスト失敗。詳細についてはPHPのエラーログを確認してください。\n"; 109} 110 111// 作成したダミーファイルをクリーンアップとして削除します。 112// 実際の運用でこれらのファイルを使用する場合は削除しないでください。 113if (file_exists($dummyCaInfoPath)) { 114 unlink($dummyCaInfoPath); 115} 116if (file_exists($dummyPinnedPublicKeyPath)) { 117 unlink($dummyPinnedPublicKeyPath); 118} 119 120?>
このPHPサンプルコードは、cURLライブラリを用いて安全なHTTPSリクエストを実行する方法を示しています。特にSSL/TLS証明書の検証と公開鍵ピンニングという二つの重要なセキュリティ設定に焦点を当てています。
performSecureCurlRequest関数は、ターゲットURL ($url) に対し、より信頼性の高い通信を確立するためのオプションを設定します。CURLOPT_CAINFO定数を用いることで、サーバーから提示される証明書が、指定された信頼できる認証局(CA)によって発行されたものであるかを確認し、通信相手の正当性を検証します。
さらに、CURLOPT_PINNEDPUBLICKEY定数を使用すると「公開鍵ピンニング」という高度な検証を設定できます。これは、アクセス先のサーバーが、あらかじめ指定した特定の公開鍵のみを使用しているかを厳密に検証する仕組みです。これにより、中間者攻撃(MITM)によるサーバーのなりすましを防ぎ、より強固なセキュリティを実現します。設定には、公開鍵のハッシュ値またはそのファイルパスを指定します。
この関数は、リクエストが成功した場合はサーバーからの応答文字列を、何らかの問題が発生した場合はfalseを戻り値として返します。これらの設定を適切に活用することで、外部APIとの安全な連携が可能となります。
CURLOPT_CAINFOとCURLOPT_PINNEDPUBLICKEYは、HTTPS通信のセキュリティを強化する重要な設定です。CURLOPT_CAINFOには信頼できるCA証明書バンドルの正しいパスを指定し、サーバー証明書の正当性を検証します。CURLOPT_PINNEDPUBLICKEYは特定のサーバーの公開鍵の同一性を確認しますが、サーバーの鍵が変更された際は設定の更新が必要です。サンプルコード内のダミーファイルやハッシュは学習用であり、本番環境での使用はセキュリティリスクが非常に高いため絶対に避けてください。CURLOPT_SSL_VERIFYPEERとCURLOPT_SSL_VERIFYHOSTは必ず有効にし、エラーログとHTTPステータスコードのチェックも忘れずに行ってください。
PHP cURLでSSL証明書検証と公開鍵ピンニングを行う
1<?php 2 3/** 4 * SSL証明書検証と公開鍵ピンニングを伴うcURLリクエストを実行します。 5 * 6 * この関数はCURLOPT_SSL_VERIFYPEERとCURLOPT_PINNEDPUBLICKEYオプションを使用し、 7 * HTTPSリクエストのセキュリティを強化する方法を示します。 8 * 9 * @param string $url リクエスト先のURL。 10 * @param string $pinnedPublicKey ピンニングする公開鍵の情報を指定する文字列。 11 * 例: "sha256//<Base64エンコードされたSHA256ハッシュ>"、 12 * またはPEM/DER形式の公開鍵ファイルへのパス。 13 * @return string|false 成功した場合はレスポンスボディ、失敗した場合はfalseを返します。 14 */ 15function performSecureCurlRequestWithPinning(string $url, string $pinnedPublicKey) 16{ 17 $ch = curl_init(); 18 19 // cURLオプションを設定 20 curl_setopt($ch, CURLOPT_URL, $url); 21 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // レスポンスを文字列として取得 22 23 // SSLピア証明書の検証を有効にする 24 // CURLOPT_PINNEDPUBLICKEYは、このオプションがtrueの場合にのみ有効です。 25 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); 26 // ホスト名の検証レベルを設定 (2は一般的な推奨値) 27 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); 28 29 // 公開鍵ピンニングを設定 30 // ここで指定する値は、アクセス先のサーバーの公開鍵のハッシュ値、 31 // またはPEM/DER形式の公開鍵ファイルへのパスです。 32 // 正しい値を設定しない場合、cURLリクエストは失敗します。 33 curl_setopt($ch, CURLOPT_PINNEDPUBLICKEY, $pinnedPublicKey); 34 35 $response = curl_exec($ch); 36 37 // エラーチェック 38 if (curl_errno($ch)) { 39 echo 'cURL Error: ' . curl_error($ch) . PHP_EOL; 40 $response = false; 41 } 42 43 curl_close($ch); 44 45 return $response; 46} 47 48// === 使用例 === 49// 注意: 以下の $dummyPinnedPublicKey はサンプル用のダミー値です。 50// 実際のターゲットサーバーの公開鍵ハッシュに置き換える必要があります。 51// 正しく設定しないと、cURLリクエストは通常失敗し、SSL検証エラーが発生します。 52 53$targetUrl = 'https://www.google.com'; 54// 実際の公開鍵ハッシュ値の例(これはダミーです。実際にはターゲットサーバーから取得します) 55// 例: sha256//<Base64エンコードされた64文字のSHA256ハッシュ> 56$dummyPinnedPublicKey = 'sha256//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'; 57 58$result = performSecureCurlRequestWithPinning($targetUrl, $dummyPinnedPublicKey); 59 60if ($result !== false) { 61 // このブロックが実行されることは、ダミーの公開鍵ハッシュを使用している場合、通常ありません。 62 echo "cURLリクエスト成功 (ピンニング検証も成功)" . PHP_EOL; 63 echo "レスポンスの一部: " . substr($result, 0, 200) . "..." . PHP_EOL; 64} else { 65 // ダミーの公開鍵ハッシュを使用した場合、通常はこのブロックが実行されます。 66 echo "cURLリクエスト失敗" . PHP_EOL; 67} 68
このサンプルコードは、PHPのcURLライブラリを使ってHTTPS通信のセキュリティを強化する「公開鍵ピンニング」という技術を実装する方法を示しています。CURLOPT_PINNEDPUBLICKEYオプションは、アクセス先のサーバーが提示するSSL証明書に含まれる公開鍵が、事前に指定した公開鍵と一致するかどうかを検証するために使用されます。これにより、悪意のある第三者による「中間者攻撃」を防ぎ、よりセキュアな通信を実現します。
この公開鍵ピンニングは、通常のSSL証明書検証オプションであるCURLOPT_SSL_VERIFYPEERがtrueに設定されている場合にのみ有効です。まず標準の証明書検証が行われ、その後に公開鍵のピンニング検証が追加で行われる仕組みです。
performSecureCurlRequestWithPinning関数は、リクエスト先のURLを引数$urlとして、ピンニングする公開鍵の情報を引数$pinnedPublicKeyとして受け取ります。$pinnedPublicKeyには、対象サーバーの公開鍵のハッシュ値(例: "sha256//<ハッシュ値>")や、PEM/DER形式の公開鍵ファイルへのパスを指定します。
関数は、cURLリクエストが成功し、公開鍵ピンニング検証も通過した場合にはサーバーからのレスポンスボディを文字列として返します。検証に失敗したり、cURL自体でエラーが発生した場合にはfalseを返します。
特に重要な点として、CURLOPT_PINNEDPUBLICKEYに設定する値は、接続したいサーバーの実際の公開鍵情報と完全に一致している必要があります。サンプルコードで使用している$dummyPinnedPublicKeyはダミー値であり、実際にはターゲットサーバーから正しい情報を取得して設定しないと、セキュリティ検証に失敗し、リクエストは成功しませんのでご注意ください。
このサンプルコードで最も重要な注意点は、CURLOPT_PINNEDPUBLICKEYに設定する値が、アクセス先のサーバーの正しい公開鍵の情報でなければならないことです。サンプルコード中の$dummyPinnedPublicKeyはあくまで例示であり、実際のサーバーの公開鍵とは異なります。そのため、このコードをそのまま実行すると通常は検証エラーでリクエストが失敗します。
安全に利用するためには、通信先のサーバーから正確な公開鍵のハッシュ値(sha256//<Base64エンコードされたハッシュ>形式など)またはPEM/DER形式の公開鍵ファイルパスを事前に取得し、設定する必要があります。誤った値を設定すると、セキュリティが低下するだけでなく、リクエスト自体が認証エラーで失敗しますのでご注意ください。また、CURLOPT_PINNEDPUBLICKEYはCURLOPT_SSL_VERIFYPEERがtrueの場合にのみ機能することを理解し、両方を正しく設定することが重要です。