微信退款IIS呼叫介面(https)提示錯誤的解決方案
Aps.net在IIS伺服器中使用windows的容器中的證書訪問https服務(在windows服務和COM+服務中有同樣的這個問題)
問題描述:
在使用aps.net開發web應用的時候,我們需要使用證書去訪問https的介面,我們在開發的時候可執行,但是部署到iis伺服器上之後,便發現所有使用證書訪問的地方都拋異常?返回的錯誤大致為:1、webrequest.GetResponse()函式拋異常;2、System.Net.WebException:請求被中止,未能建立 SSL/TLS安全通道;3、store.Certificates.Find 函式查找出來的證書個數為0;
問題分析:
開發環境中直接使用vs除錯工具可以正常執行,不是之後便執行不正常,在排查iis配置問題的情況下,基本上可以判斷是許可權問題,在開發工作下執行,使用的是當前使用者的許可權,安裝在本機的證書基本也是該使用者下安裝的,許可權肯定沒問題,但是在iis伺服器下面,則不是以當前使用者的環境執行,當然沒許可權讀取證書。
Windows中證書存放分析:
Windows存放證書有2種,一種本地計算機證書存取路徑,另一是本地使用者賬戶證書存取路徑,存放的路徑分別為:LOCAL_MACHINE\MY 和 CURRENT_USER\My(My為windows下預設路徑)
1、本地使用者賬戶證書存取路徑表示一般使用者安裝的證書存放地,使用者開啟的程序時,載入證書都從這裡個路徑進行載入;但是服務程序則不能從該路徑載入證書。
2、本地計算機證書存取路徑表示服務型別的程序使用證書的時候,預設從該路徑載入,使用者安裝的證書並不會同步到該路徑。
IIS一般都是以系統內建的一些賬戶啟動,這些賬戶是沒有許可權訪問CURRENT_USER目錄下的證書的,所以我們需要將證書安裝到LOCAL_MACHINE下去。
操作方法:
1、開啟mmc(在搜尋程式中輸入mmc,然後回車)進入如下介面:
2、選擇“檔案 》 新增/刪除管理單元”進入如下介面
3、左邊選擇證書,點選“新增”,出現如下介面
4、選擇計算機賬戶,點選下一步
5、這裡選擇“本地計算機”(預設選擇),點選完成後,再點“確定”,介面成下面樣
6、右“鍵個人 》 證書”,出現匯入證書介面
8、安裝步驟匯入pfx或者.p12格式的證書,導完之後右邊出現剛剛匯入的證書
到這裡證書匯入算是完成了。
證書導完之後,試下自己的網站是否能夠發起https請求,如果能夠,則到此為止,如果不能,還需要將證書許可權給指定的系統使用者。方法如下:
2、在64位系統下,安裝之後工具在C:\Program Files (x86)\Windows ResourceKits\Tools路徑下,使用CD \D指令定位到該目錄下
3、使用剛剛安裝的工具,給指定使用者開證書的訪問許可權,使用指令如下:
winhttpcertcfg.exe -g -c LOCAL_MACHINE\MY -s"jackliu_test_company" -a "NETWORKSERVICE"
這裡引數可以使用--help具體檢視,我只描述幾個最簡單的
-g 表示給該使用者增加證書的訪問許可權,如果將該引數變成-r表示移除使用者的證書訪問許可權
-c 後面引數表示證書的路徑,LOCAL_MACHINE可以替換為CURRENT_USER,但是必須如果使用CURRENT_USER下的證書,即使給了許可權還是不能正常執行。
-s 後面引數表示證書的名稱。注意:證書名稱不是證書的檔名稱,名稱可以從mmc管理工具中證書列表的“頒發給”欄位。
-a 後面引數表示使用者名稱稱,一般IIS執行使用者為:NETWORKSERVICE或者 ASPNET使用者,這裡如果開了這兩個使用者還是不行的話,則需要給windows認證的一個使用者也開下證書訪問許可權。authenticatedUsers
指令如下:(此處是關鍵)
winhttpcertcfg.exe -g -c LOCAL_MACHINE\MY -s"你的證書名稱"-a "NETWORKSERVICE"
winhttpcertcfg.exe -g -c LOCAL_MACHINE\MY -s"你的證書名稱"-a "ASPNET"
winhttpcertcfg.exe -g -c LOCAL_MACHINE\MY -s"你的證書名稱"-a "Authenticated Users"
成功則出現如下字樣:
如果出現如下錯誤資訊:
則表示未找到證書,請安裝我上面講的如何安裝證書到LOCAL_NARCHANT下的說明。
如果出現如下錯誤資訊:
表示證書已經找到,但是沒找到使用者資訊
C#程式碼使用方法(直接使用windows下已經安裝的證書):
HttpWebResponse webreponse;
try
{
//系統必須已經匯入cert指向的證書
X509Store store = newX509Store("My", StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly |OpenFlags.OpenExistingOnly);
System.Security.Cryptography.X509Certificates.X509Certificate2cert =
store.Certificates.Find(X509FindType.FindBySubjectName, "你的證書名稱", false)[0];
HttpWebRequest webrequest =(HttpWebRequest)HttpWebRequest.Create(url);
webrequest.ClientCertificates.Add(cert);
webrequest.Method = "post";
webrequest.KeepAlive = true;
webreponse = (HttpWebResponse)webrequest.GetResponse();
Stream stream =webreponse.GetResponseStream();
string resp = string.Empty;
using (StreamReader reader = newStreamReader(stream))
{
resp = reader.ReadToEnd();
}
strHtml = resp;
}
catch (Exception exp)
{
strHtml = exp.ToString();
}
幾個關鍵點:
1、X509Storestore = new X509Store("My", StoreLocation.LocalMachine);
這裡,My為證書安裝的模組邏輯,windows7下預設為My,StoreLocation.LocalMachine使用這個型別。
2、System.Security.Cryptography.X509Certificates.X509Certificate2cert =
store.Certificates.Find(X509FindType.FindBySubjectName,"你的證書名稱",false)[0];
這裡通過證書名稱查詢證書,證書名稱為證書列表中“頒發給欄位”。這裡返回是一個數組,如果你安裝多個相同名稱的證書,這裡可能會返回多個,這種情況需要根據證書具體定位是那個。