合格的web后端程序員,除搬磚技能,還必須會給各種web服務器配置Https,本文結合ASP.NET Core部署模型聊一聊啟用Https的方式。
溫故知新
目前常見的Http請求明文傳輸,請求可能被篡改,訪問的站點可能被偽造。
HTTPS是HTTP加上TLS/SSL協議構建的可進行加密傳輸、身份認證的網絡協議,主要通過數字證書、加密算法、非對稱密鑰等技術完成互聯網數據傳輸加密,實現互聯網傳輸安全保護。
HTTPS是應用層協議
注意,HTTPS是與DNS平級的應用層協議, 一個常見HTTPS請求的過程:
由DNS解析出IP地址-----> 瀏覽器向服務器ip地址發起請求----> 服務器向瀏覽器下發證書(該證書有公鑰,並綁定了域名)-----> 瀏覽器驗證證書---->....
HTTPS 流程解讀
① 傳輸密鑰是對稱密鑰,用於雙方對傳輸數據的加解密
② 怎么在傳輸之前確立傳輸密鑰呢?
答:針對普遍的多客戶端訪問受信web服務器的場景, 提出非對稱密鑰(公鑰下發給客戶端,私鑰存於web服務器),雙方能互相加解密,說明中間數據(傳輸密鑰)沒被篡改。
③ 再拋出疑問,客戶端如何認定下發的公鑰是目標web服務器的公鑰?又如何確定公鑰下發過程沒被截取篡改?
答:追溯到握手階段的證書驗證過程,瀏覽器從證書提取(證書頒發機構,證書綁定的域名,證書簽名,證書有效期),
瀏覽器先驗證證書綁定的域名是否與目標域名匹配;瀏覽器內置證書頒發機構認定該證書是其有效下發;通過簽名認定該證書沒被篡改。
④ 所以瀏覽器內置的證書機構(根證書)的權威性相當重要, 瀏覽器中毒或劣質瀏覽器可能攜帶 非法的根證書。
如果面向面試記憶Https原理,恐怕有些難度,所以個人用一種 【雞生蛋還是蛋生雞】的方式向上追溯流程, 方便大家知其然更知其所以然
⑤ 是不是只有CA機構才能簽發證書 ?
不是的,服務器上存儲的證書和公鑰,只要是匹配的就可以下發;由瀏覽器決定是否信任證書。
所以在測試和開發階段,通常在服務器上申請 自簽名證書,瀏覽器會提示你證書無效,但是你可手動忽略,或添加到信任列表。
下面演示對ASP.NET Core程序兩種最常見部署模型強制應用HTTPS.
常規反向代理模型
由nginx反向代理請求到后端https://receiver.server, nginx上添加HTTPS證書, 並強制瀏覽器使用 HTTPS。
worker_processes 4; events { worker_connections 1024; } http { sendfile on; upstream receiver_server { server receiver:80; } server { listen 80; listen [::]:80; server_name eqid.******.com; return 301 https://$host$request_uri; } server { listen 443 ssl; listen [::]:443 ssl; ssl on; server_name eqid.******.com; ssl_certificate /conf.crt/live/******.com.crt; ssl_certificate_key /conf.crt/live/******.com.key; location / { proxy_pass http://receiver_server; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_redirect off; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } }
黃色背景行顯示: nginx對http:80 請求返回301(重定向,Moved Permanently), 要求瀏覽器使用Https發起請求。
綠色背景行顯示: nginx對此次 https請求,在協商階段會下發ssl_certificate證書, 會使用 ssl_certificate_key 私鑰進行非對稱解密。
dotnet.exe自宿模型
Kestrel用作邊緣(面向Internet)Web服務器, 這個部署模型不常見,但依舊存在。
我們利用 Visual Studio 2019項目模板構建 ASP.NetCore項目--- 勾選HTTPS支持, 會默認添加Https支持;
- app.UseHttpsRedirection() 要求瀏覽器的Http請求 重定向使用 HTTPS協議
- app.UseHsts()
HSTS(HTTP Strict Transport Protocol)的作用是強制瀏覽器使用HTTPS與服務器創建連接,避免原有的301重定向Https時可能發生中間人劫持
服務器開啟HSTS的方法是,當客戶端通過HTTPS發出請求時,在服務器返回的超文本傳輸協議響應頭中包含Strict-Transport-Security字段。非加密傳輸時設置的HSTS字段無效。
它告訴瀏覽器為特定的主機頭和特定的時間范圍緩存證書。
開發證書
VS模板構建的web會使用dotnet cli 提供的開發證書在https://localhost:5001 地址接收請求。
關於開發證書, 可倒騰 dotnet dev-certs https --help 命令:
dotnet dev-certs https --clean 清除證書,啟動程序會報 System.InvalidOperationException:“Unable to configure HTTPS endpoint. No server certificate was specified, and the default developer certificate could not be found or is out of date. To generate a developer certificate run 'dotnet dev-certs https'. To trust the certificate (Windows and macOS only) run 'dotnet dev-certs https --trust'.
dotnet dev-certs https -t 信任證書,會彈窗提示安裝名為localhost的根證書:
- 否,web能正常啟動,瀏覽器Https請求能獲取證書,但會警示 ▲不安全 (瀏覽器不信任localhost根證書,證書無效)
- 是,web正常啟動,瀏覽器發起的Https請求,顯示正常的顯示♎ 圖標
在Windows上,最安全方式是使用certificate store來注冊已認證的HTTPS,但是有時候希望在程序內綁定證書+私鑰, 這樣便於在不同平台上部署。
文件證書
ASP.NET Core支持使用硬盤上文件證書來建立Https連接(這在linux上很常見)。
以下代碼允許Kestrel 傳入文件證書和私鑰,並建立Https連接。
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseKestrel(options => { options.Listen(IPAddress.Loopback, 5000); options.Listen(IPAddress.Loopback, 5001, listenOptions => { listenOptions.UseHttps("certificate.pfx", "topsecret"); }); }) .UseStartup<Startup>();
務必確保不要將私鑰存儲在配置文件中:在開發模式,可使用 user secrets 存儲此類密鑰;在生產模式,可考慮Azure Key Vault或環境變量。
完整密鑰分離請參考: https://www.cnblogs.com/JulianHuang/p/11462607.html
編程允許HttpClient發起不安全的請求
有時候你會使用HttpClient等客戶端去請求 受信HTTPS站點, 但是因為某些原因(自簽名證書,證書過期), 下發的證書無效 (這個時候瀏覽器會提示,你可選擇忽略,或者手動添加到受信列表繼續請求),
但是編程方式的HttpClinet 會立刻終止請求。
給栗子:
使用默認的HttpClient BaseAddress=https://127.0.0.1:5001,訪問ASP.NET Core 默認站點https://localhost:5001, 會出現:
這個時候你可考慮重寫HttpClient ServerCertificateCustomValidationCallback屬性 忽略無效證書報錯。
[Route("test")] public async Task<string> Get() { var client = new HttpClient(new HttpClientHandler() { AllowAutoRedirect = true, ServerCertificateCustomValidationCallback = (x1, x2, x3, x4) => true }); var resp = await client.GetAsync("https://127.0.0.1:5001"); return await resp.Content.ReadAsStringAsync(); }
總結
希望本文有助於您大致了解 HTTPS的協議原理,常見的HTTPS的應用方式,
結合.NETCore 說明開發證書 和 文件證書的使用方式, 最后指出允許HttpClient發起不安全請求的方式。