2013-04-30 54 views
5

這裏是打開一個SSL套接字準備發送HTTP請求一個簡單的PHP腳本:PHP和SSL CA驗證 - 與操作系統無關

 
$contextOptions = array(); 

$socketUrl = 'ssl://google.com:443'; 
$streamContext = stream_context_create($contextOptions); 
$socket = stream_socket_client($socketUrl, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $streamContext); 

if (!$socket || $errno !== 0) { 
    var_dump($socket, $errstr); 
    exit; 
} 

var_dump($socket); 
exit('Socket created.'); 

這工作 - 我只是測試它 - 但沒有驗證針對受信任的CA商店。

我們可以修改腳本,以使用PHP的SSL Context options

 
$contextOptions = array(
    'ssl' => array(
     'cafile' => 'C:\xampp\cacerts.pem', 
     'CN_match' => '*.google.com', // CN_match will only be checked if 'verify_peer' is set to TRUE. See https://bugs.php.net/bug.php?id=47030. 
     'verify_peer' => TRUE, 
    ) 
); 

$socketUrl = 'ssl://google.com:443'; 
$streamContext = stream_context_create($contextOptions); 
$socket = stream_socket_client($socketUrl, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $streamContext); 

if (!$socket || $errno !== 0) { 
    var_dump($socket, $errstr); 
    exit; 
} 

var_dump($socket); 
exit('Socket created.'); 

只要「憑證檔案錯誤」存在並具有正確的CA那麼這個例子也適用...

...但我們如何在不對CA文件名/文件路徑進行硬編碼的情況下做到這一點?我們試圖創建一些獨立於操作系統的SSL證書驗證,而不需要爲運行此腳本的每臺服務器單獨配置。

我知道Linux有一個CA的目錄,我們可以把它作爲'capath'。 Windows怎麼樣?它在哪裏存儲其可信CA?我搜索了,這些不幸似乎在註冊表中,那麼我們沒有辦法從PHP訪問它們嗎?其他操作系統呢?

回答

12

敗局...

沒有辦法進行PHP中的安全加密傳輸,而無需手動設置之前,PHP 5.6 "cafile""CN_match"上下文選項。不幸的是,即使你正確設置這些值,您的傳輸仍然很有可能失敗,因爲在驗證主機名時,5.6之前的版本不會查閱對等證書中日益流行的SAN(subjectAltName)擴展。因此,通過PHP的內置流封裝進行「安全」加密在很大程度上是一種誤用。與老版本的PHP相比,你最安全的選擇就是curl擴展。

關於窗戶證書...

Windows使用它自己的證書存儲,並從不同的OpenSSL編碼格式的證書。相比之下,openssl應用程序使用開放的.PEM格式。 5.6之前版本的PHP無法以任何方式與Windows證書商店進行交互。出於這個原因,使用內置流封裝功能以跨OS的方式進行可靠和安全的加密是不可能的。

PHP 5.6是openssl.cafile向前

  • 了一大步新openssl.capath php.ini配置讓您全局分配證書的位置,而不必設置他們在每流上下文

  • 默認情況下,所有加密的流都會驗證對等證書和主機名,如果沒有提供"CN_match"上下文選項,則會自動從URI中分析主機名。現在

  • 如果流上下文 PHP沒有指定CA文件/路徑驗證主機名時

  • 流加密操作檢查對證書SAN項。INI指令PHP自動退回到操作系統的證書存儲(在Windows,也!)

舉例來說,這是所有你需要做的,安全的連接到github.com在PHP- 5.6:

<?php 
$socket = stream_socket_client("tls://github.com:443"); 

是的。這就是它。不用擔心上下文設置和驗證參數。 PHP現在在這方面的功能與您的瀏覽器相同。

更多閱讀關於這一主題

這些PHP 5.6變化是僅針對SSL/TLS改進冰山的一角。迄今爲止,我們一直在努力使5.6最安全的PHP版本與加密通信有關。

如果您想了解更多關於這些新功能也通過官方渠道

提供了豐富的信息

5.4/5.5

在SAN匹配的說明我們合作,反向移植至少SAN匹配到5.4和5.5的分支,因爲它是極難使用的加密封裝以任何有意義的方式(作爲客戶端)沒有這個功能。雖然這種後援工作很大程度上取決於我作爲志願者的空閒時間,但提高這個答案可能會更快地發生:)

+0

rdlowrey是絕對正確的。但是,您可以從Guzzle中抽出一部分,並在您的代碼中打包自己的CA文件:https://github.com/guzzle/guzzle/blob/master/src/Guzzle/Http/Resources/cacert.pem – Tom 2014-02-27 19:23:02

+1

我應該補充說,當使用curl方法時,您需要負擔確保您的CA證書是最新的。這些通常每年都會發生一些變化,如果不更新,可能存在潛在的問題,您可以使用受到攻擊的CA來驗證對等方。 5.6使用操作系統管理的證書的能力是向前邁進的一大步,因爲您不必知道這些。但是,這也與您安裝最新的操作系統更新的傾向一樣好,因此您的證書不會過時。不幸的是,這是一個很快不會出現在libcurl中的功能。 – rdlowrey 2014-02-27 19:56:39

+0

如果您需要最大限度的安全性(針對偏執狂和NSA意識),最好的解決方案是使用已知的指紋哈希來驗證對等方的證書。這是在PHP 5.6中也可用於加密流的功能。也就是說,有關這些事情的文檔有很多工作要做,所以我們可以在發佈之前的幾個月內發佈這些信息。是的:我們意識到這一點,是的,如果你想保護你的轉賬,我們將努力工作,使手冊成爲一個有用的資源:) – rdlowrey 2014-02-27 19:58:26