這篇文章主要給大家介紹了PHP利用Socket擷取網站的SSL認證與公開金鑰的相關資料,文中給出了詳細的範例程式碼供大家參考學習,對大傢具有一定的參考學習價值,需要的朋友們下面來一起看看吧。
通過 php curl 請求網頁並不能擷取到認證資訊,此時需要使用 ssl socket 擷取認證內容。下面來一起看看看詳細的介紹:
範例程式碼:
// 建立 stream context$context = stream_context_create([ 'ssl' => [ 'capture_peer_cert' => true, 'capture_peer_cert_chain' => true, ],]); $resource = stream_socket_client("ssl://$domain:$port", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);$cert = stream_context_get_params($resource); $ssl = $cert['options']['ssl'];$resource = $ssl['peer_certificate']; // 網站認證中只有公開金鑰,通過 openssl_pkey_get_details 匯出公開金鑰 $ret = [ 'crt' => '', 'pub' => '',]; $pkey = openssl_pkey_get_public($resource);$ret['pub'] = openssl_pkey_get_details($pkey)['key']; openssl_x509_export($resource, $pem);$ret['crt'] = $pem; foreach ($ssl['peer_certificate_chain'] as $resource){ openssl_x509_export($resource, $pem); $ret['crt'] .= "\n" . $pem;} // 儲存 $ret['crt'] 為 domain.crt// 儲存 $ret['pub'] 為 domain.pub return $ret;
驗證認證中的公開金鑰A是否正確,通過私密金鑰匯出公開金鑰B,比較兩者發現一致。
$domain = 'blog.zhengxianjun.com';$port = '443';// ...$pub_a = $ret['pub']; $private_key_path = '/conf/ssl/blog.zhengxianjun.com.key'; // 認證沒有設定密碼,$passphrase 為空白字串$pkey = openssl_pkey_get_private(file_get_content($private_key_path), $passphrase = '');$pub_b = openssl_pkey_get_details($pkey)['key']; // 兩者一致var_dump($pub_a === $pub_b);
函數 stream_socket_client 還有一個用途是當知道伺服器 IP 時,能擷取到伺服器可能可以使用的網域名稱。
$resource = stream_socket_client("ssl://$ip:$port", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);$cert = stream_context_get_params($resource); // 解析 X.509 格式認證$info = openssl_x509_parse($cert['options']['ssl']['peer_certificate']); // 擷取認證中的可信網域名稱列表$domain = str_replace('DNS:', '', $info['extensions']['subjectAltName']);
以上可以看到擷取網站認證並不能獲得私密金鑰。
在一些使用 CDN 的網站,如果使用了 HTTPS 同時又希望使用自有網域名稱,是否需要將自己的私密金鑰提供給 CDN 廠商呢?實際上憑證路徑與使用者名稱(支援 https 的網域名稱)並不需要一致。
也就是使用自有網域名稱並進行 CDN 加速時不需要使用自有的 ssl 認證,只需將自己的 CDN 網域名稱加到廠商認證的網域名稱列表即可。