簡體   English   中英

SSL錯誤SSL3_GET_SERVER_CERTIFICATE:證書驗證失敗

[英]SSL error SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

升級到PHP 5.6后,嘗試通過fsockopen()連接到服務器時出錯。

服務器(主機)上的證書是自簽名的

PHP警告:fsockopen():SSL操作失敗,代碼為1. OpenSSL錯誤消息:錯誤:14090086:SSL例程:SSL3_GET_SERVER_CERTIFICATE:證書驗證失敗

if($fp = fsockopen($host, $port, $errno, $errstr, 20)){
    $this->request = 'POST '.substr($this->url, strlen($this->host)).' HTTP/1.1'.$crlf
        .'Host: '.$this->host.$crlf
        .'Content-Length: '.$content_length.$crlf
        .'Connection: Close'.$crlf.$crlf
        .$body;
    fwrite($fp, $this->request);

    while($line = fgets($fp)){
        if($line !== false){
            $this->response .= $line;
        }
    }

    fclose($fp);
}

試過

# cd /etc/ssl/certs/
# wget http://curl.haxx.se/ca/cacert.pem

php.ini中

openssl.cafile = "/etc/ssl/certs/cacert.pem"

但腳本仍無法正常工作

更新

這有效

echo file_get_contents("/etc/ssl/certs/cacert.pem");

更新2

$contextOptions = array(
    'ssl' => array(
        'verify_peer' => true, // You could skip all of the trouble by changing this to false, but it's WAY uncool for security reasons.
        'cafile' => '/etc/ssl/certs/cacert.pem',
        //'CN_match' => 'example.com', // Change this to your certificates Common Name (or just comment this line out if not needed)
        'ciphers' => 'HIGH:!SSLv2:!SSLv3',
        'disable_compression' => true,
    )
);

$context = stream_context_create($contextOptions);

$fp = stream_socket_client("{$host}:{$port}", $errno, $errstr, 20, STREAM_CLIENT_CONNECT, $context);

錯誤

PHP警告:stream_socket_client():SSL操作失敗,代碼為1. OpenSSL錯誤消息:錯誤:14090086:SSL例程:SSL3_GET_SERVER_CERTIFICATE:證書驗證失敗

您下載的文件( http://curl.haxx.se/ca/cacert.pem )是來自主要受信任證書頒發機構的一組根證書。 您說遠程主機具有自簽名SSL證書,因此它不使用可信證書。 openssl.cafile設置需要指向用於在遠程主機上簽署SSL證書的CA證書。 PHP 5.6比以前的PHP版本有所改進,現在默認驗證對等證書和主機名( http://php.net/manual/en/migration56.openssl.php

您需要找到在簽署SSL證書的服務器上生成的CA證書,並將其復制到此服務器。 唯一的另一種選擇是禁用驗證對等體,但這會破壞SSL安全性。 如果您想嘗試禁用驗證,請使用我之前的答案中的代碼嘗試此數組:

$contextOptions = array(
    'ssl' => array(
        'verify_peer' => false,
        'verify_peer_name' => false
    )
);

無論哪種方式,如果您使用的是自簽名證書,則需要將用於簽署遠程主機SSL證書的CA證書添加到您要連接的服務器上的受信任存儲中,或者使用流上下文來使用每個請求的證書。 將其添加到可信證書是最簡單的解決方案。 只需將遠程主機CA證書的內容添加到您下載的cacert.pem文件的末尾即可。

以前:

fsockopen不支持流上下文,因此請改用stream_socket_client。 它返回一個資源,可以與fsockopen資源可以使用的所有命令一起使用。

這應該是您在問題中的代碼段的替代品:

<?php

$contextOptions = array(
    'ssl' => array(
        'verify_peer' => true, // You could skip all of the trouble by changing this to false, but it's WAY uncool for security reasons.
        'cafile' => '/etc/ssl/certs/cacert.pem',
        'CN_match' => 'example.com', // Change this to your certificates Common Name (or just comment this line out if not needed)
        'ciphers' => 'HIGH:!SSLv2:!SSLv3',
        'disable_compression' => true,
    )
);

$context = stream_context_create($contextOptions);

$fp = stream_socket_client("tcp://{$host}:{$port}", $errno, $errstr, 20, STREAM_CLIENT_CONNECT, $context);

if (!$fp) {

    echo "$errstr ({$errno})<br />\n";

}else{

    $this->request = 'POST '.substr($this->url, strlen($this->host)).' HTTP/1.1'.$crlf
        .'Host: '.$this->host.$crlf
        .'Content-Length: '.$content_length.$crlf
        .'Connection: Close'.$crlf.$crlf
        .$body;

    fwrite($fp, $this->request);

    while (!feof($fp)) {
        $this->response .= fgets($fp);
    }

    fclose($fp);

}

問題出在macOS Sierra的新PHP版本中

請加

stream_context_set_option($ctx, 'ssl', 'verify_peer', false);

我使用Docker在使用Ubuntu 16.04時遇到了類似的問題。 在我的情況下,這是Composer的問題,但錯誤消息(因此問題)是相同的。

由於極簡主義的面向Docker的基本映像,我缺少ca-certificates包和簡單的apt-get install ca-certificates幫助了我。

$mail->SMTPOptions = array(
'ssl' => array(
    'verify_peer' => false,
    'verify_peer_name' => false,
    'allow_self_signed' => true
));

之前

mail->send()

並替換

require "mailer/class.phpmailer.php";

require "mailer/PHPMailerAutoload.php";

Firstable,確保您的防病毒軟件不會阻止SSL2。
因為我長時間無法解決問題,只有禁用防病毒幫助了我

你提到證書是自簽名的(由你)? 那你有兩個選擇:

  • 將證書添加到您的信任存儲區(從cURL網站獲取cacert.pem將不會執行任何操作,因為它是自簽名的)
  • 不要打擾驗證證書:你相信自己,不是嗎?

以下是PHP中的SSL上下文選項列表: https//secure.php.net/manual/en/context.ssl.php

設置allow_self_signed如果導入您的證書到您的信任存儲,或者設置verify_peer為false以跳過驗證。

我們信任特定證書的原因是因為我們信任其發行人 由於您的證書是自簽名的,因此簽名者(您)不受信任,因此任何客戶都不會信任該證書。 如果在簽署證書時創建了自己的CA,則可以將CA添加到信任庫。 如果您的證書不包含任何CA,那么您不能指望任何人連接到您的服務器。

在我的情況下,我在CentOS 7上,我的php安裝指向通過update-ca-trust生成的證書。 符號鏈接是/etc/pki/tls/cert.pem指向/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem 這只是一個測試服務器,我希望我的自簽名證書能夠正常工作。 所以在我的情況下......

# My root ca-trust folder was here. I coped the .crt file to this location
# and renamed it to a .pem
/etc/pki/ca-trust/source/anchors/self-signed-cert.pem

# Then run this command and it will regenerate the certs for you and
# include your self signed cert file.
update-ca-trust

然后我的一些api調用開始工作,因為我的證書現在已被信任。 此外,如果您的ca-trust通過yum或其他內容進行更新,這將重建您的根證書並仍然包含您的自簽名證書。 運行man update-ca-trust以獲取有關如何操作以及如何執行操作的更多信息。 :)

如果您使用的是macOS sierra,則會有PHP版本的更新。 您需要將Entrust.net證書頒發機構(2048)文件添加到PHP代碼中。 更多信息檢查接受的答案在這里使用PEM文件在PHP中推送通知

您是否嘗試過使用stream_context_set_option()方法?

$context = stream_context_create();
$result = stream_context_set_option($context, 'ssl', 'local_cert', '/etc/ssl/certs/cacert.pem');
$fp = fsockopen($host, $port, $errno, $errstr, 20, $context);

此外,請嘗試pem文件的file_get_contents() ,以確保您有權訪問它,並確保主機名與證書匹配。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM