線上到 Web 服務
重要
這是 Azure Sphere (舊版) 檔。 Azure Sphere(舊版)將於 2027 年 9 月 27 日淘汰,且使用者此時必須移轉至 Azure Sphere(整合式)。 使用位於 TOC 上方的版本選取器來檢視 Azure Sphere (整合式) 檔。
Azure Sphere SDK 包含 libcurl 連結庫,高階應用程式可用來連線及驗證 HTTP 和 HTTPS Web 服務。 同時支援伺服器和客戶端驗證,讓應用程式可以驗證它們與預期的伺服器通訊,並可向伺服器證明其裝置和 Azure Sphere 租使用者是合法的。 相互驗證 結合了兩者。
GitHub 上的 Azure Sphere 範例存放庫包含下列 curl 範例:
- HTTPS_Curl_Easy使用同步(封鎖)API 進行伺服器驗證。
- HTTPS_Curl_Multi範例 會使用異步(非封鎖)API 進行伺服器驗證。
雖然HTTPS_Curl_Easy中伺服器驗證的同步方法相當簡單,但 Azure Sphere 應用程式通常應該使用HTTPS_Curl_Multi範例中顯示的更複雜的異步技術,以及以 epoll 為基礎的單個線程事件驅動模式。
libcurl 網站提供 libcurl C API 的完整檔,以及許多範例。 cURL 連結庫與 Azure Sphere SDK 運行時間連結庫之間的差異如下:
常數名稱 ( 定義 ) |
cURL 範圍限制 | Azure Sphere 範圍限制 |
---|---|---|
CURLOPT_BUFFERSIZE (緩衝區大小) |
預設值:16 KB | 預設值:1536 KB |
CURLOPT_UPLOAD_BUFFERSIZE (上傳緩衝區大小) |
預設值:64 KB 最大值:2MB 最小值:16 KB |
預設值:1536 KB 最大值:64 KB 最小值:1536 KB |
CURLOPT_HEADERFUNCTION (傳遞至此函式的完整 HTTP 標頭) |
最大值:100 KB | 最大值:16 KB |
CURLOPT_DNS_CACHE_TIMEOUT | 默認值:快取結果 60 秒 最大值:永遠快取結果 最小值:0(不快取結果) |
所有值都會覆寫為 0,而且不會快取結果。 |
使用 curl 的應用程式需求
使用 curl 連結庫的應用程式必須包含適當的頭檔,並在應用程式指令清單中提供租使用者和因特網主機資訊。
標頭檔
若要使用 curl,請在您的應用程式中包含這些標頭檔:
#include <applibs/storage.h> // required only if you supply a certificate in the image package
#include <tlsutils/deviceauth_curl.h> // required only for mutual authentication
#include <curl/curl.h>
#include <applibs/networking_curl.h> // required only if using proxy to connect to the internet
只有在應用程式映像套件中提供一或多個憑證時,才需要 storage.h 頭檔。 執行相互驗證需要 deviceauth_curl.h 標頭。 如果應用程式使用 Proxy 連線到因特網,則需要networking_curl.h 標頭。
應用程式資訊清單
應用程式指令清單的 AllowedConnections 字段必須指定應用程式連接的主機。 它也必須包含連線在重新導向時可能會遇到的每個網域名稱。 例如, microsoft.com
連接到Microsoft首頁的應用程式需要 和 www.microsoft.com
。
如果應用程式使用相互驗證, 指令清單的 DeviceAuthentication 欄位必須包含 Azure Sphere 租使用者識別碼。 只有在裝置的租使用者標識元符合應用程式指令清單中的租使用者標識符時,才會發出裝置驗證憑證。 此限制提供深層防禦:在不同租使用者裝置上執行的應用程式(例如,不同客戶或流氓實體的應用程式無法向伺服器進行驗證。
如果應用程式使用 Proxy,ReadNetworkProxyConfig 欄位會指出應用程式是否具有擷取 Proxy 設定的許可權。
在開發期間,您可以使用 azsphere tenant show-selected 命令來尋找目前 Azure Sphere 租使用者的標識碼。
在下列範例中,AllowedConnections 字段會指定應用程式只聯機到 www.example.com
,DeviceAuthentication 字段會指定 Azure Sphere 租使用者標識符,讓應用程式能夠使用裝置憑證進行相互驗證,而 ReadNetworkProxyConfig 字段會指定應用程式可以重新擷取 Proxy 設定資訊。
"Capabilities": {
"AllowedConnections": [ "www.example.com" ],
"Gpio": [],
"Uart": [],
"WifiConfig": false,
"DeviceAuthentication": "00000000-0000-0000-0000-000000000000",
"ReadNetworkProxyConfig": true
}
支援的功能
適用於 Azure Sphere 的 Libcurl 僅支援 HTTP 和 HTTPS 通訊協定。 此外,Azure Sphere OS 不支援某些功能,例如可寫入的檔案 (cookies) 或 UNIX 套接字。 未來 libcurl 版本不支援的功能,例如 mprintf() 系列,無法使用。
適用於 Azure Sphere 的 Libcurl 支援 TLS 1.2 和 TLS 1.3,並已淘汰 TLS 1.0 和 TLS 1.1,以符合更廣泛的Microsoft TLS 安全性策略。
以下是支援的加密套件:
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
- TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
- TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
嘗試使用不支援的 TLS 版本傳回錯誤 CyaSSL does not support <version>
。
伺服器驗證
Azure Sphere 支援透過 libcurl 進行伺服器驗證。 伺服器的憑證必須由裝置信任的證書頒發機構單位 (CA) 簽署。 若要讓 libcurl 驗證伺服器,應用程式必須提供 CA 檔案的路徑。
將 CA 憑證新增至映像套件
若要使用一或多個 CA,您必須將憑證新增至映像套件。 每個憑證都必須以base-64編碼。 最簡單的方法是建立包含所有其他憑證的單一檔案。 檔案必須具有 .pem 擴展名。 若要新增憑證:
- 在應用程式的項目資料夾中建立 certs 資料夾。 專案資料夾包含應用程式的 CMakeLists 檔案。
- 在 certs 資料夾中,建立擴展名為 .pem 的文字檔、將每個憑證複製到其中,然後儲存盤案。
- 在CMakeLists.txt檔案中,將憑證檔案新增至映像套件作為資源檔。 例如:
azsphere_target_add_image_package(${PROJECT_NAME} RESOURCE_FILES "certs/DigiCertGlobalRootCA.pem")
憑證檔案現在應該會出現在映像套件的 certs 資料夾中。
設定憑證位置
在您的應用程式中,使用 CURLOPT_CAPATH 和 CURLOPT_CAINFO 選項來設定憑證的位置。 呼叫 Storage_GetAbsolutePathInImagePackage 以擷取映像套件中憑證的絕對路徑,然後呼叫 curl_easy_setopt。
CURLOPT_CAPATH設定憑證的預設資料夾。 例如,下列程式代碼會指示 curl 在映像的 certs 資料夾中尋找憑證:
char *path = Storage_GetAbsolutePathInImagePackage("certs");
curl_easy_setopt(curl_handle, CURLOPT_CAPATH, path);
CURLOPT_CAINFO設定包含一或多個憑證之檔案的路徑。 Curl 除了在 CURLOPT_CAPATH 中設定的預設資料夾之外,也會搜尋此檔案。例如:
char *path = Storage_GetAbsolutePathInImagePackage("CAs/mycertificates.pem");
curl_easy_setopt(curl_handle, CURLOPT_CAINFO, path);
此程式代碼會告知 curl 信任 mycertificates.pem 檔案中定義的任何 CA,除了在 CURLOPT_CAPATH 中設定的目錄集內定義的 CA 之外。
相互驗證
相互驗證會驗證伺服器和用戶端裝置是否合法。 這是一個多步驟的程式:
- 應用程式會使用 CA 憑證來驗證伺服器,如伺服器驗證中所述。
- 應用程式會將 x509 用戶端驗證憑證呈現給伺服器,讓伺服器能夠驗證裝置。
- 伺服器會使用 Azure Sphere 租使用者的憑證鏈結來確認裝置是否屬於租使用者。
應用程式可以使用兩種方式之一來設定相互驗證的裝置驗證端:
- 將 Azure Sphere DeviceAuth_CurlSslFunc 函式設定為執行驗證的 SSL 函式。
- 建立自定義 SSL 函式,以呼叫 Azure Sphere DeviceAuth_SslCtxFunc 函式進行驗證。
注意
Azure Sphere 不支援 SSL/TLS 重新談判。
使用任一函式之前,您必須更新應用程式的 CMakeLists.txt 檔案,以將 curl 和 tlsutils 新增至TARGET_LINK_LIBRARIES:
TARGET_LINK_LIBRARIES(${PROJECT_NAME} applibs pthread gcc_s c curl tlsutils)
使用 DeviceAuth_CurlSslFunc
執行裝置驗證最簡單的方式是將 DeviceAuth_CurlSslFunc 設定為 curl SSL 驗證的回呼函式:
// Set DeviceAuth_CurlSslFunc to perform authentication
CURLcode err = curl_easy_setopt(_curl, CURLOPT_SSL_CTX_FUNCTION, DeviceAuth_CurlSslFunc);
if (err) {
// Set ssl function failed
return err;
}
DeviceAuth_CurlSslFunc函 式 會擷取目前 Azure Sphere 租使用者的憑證鏈結,並設定 curl 連線以執行相互驗證。 如果驗證失敗,函式會傳回CURLE_SSL_CERTPROBLEM。
使用 DeviceAuth_SslCtxFunc
應用程式也可以使用自定義 SSL 回呼函式,呼叫 Azure Sphere DeviceAuth_SslCtxFunc 函式 進行驗證。
您的自定義 SSL 函式必須呼叫 DeviceAuth_SslCtxFunc 來執行驗證,但也可能會執行與驗證相關的其他工作。 DeviceAuth_SslCtxFunc傳回 列舉值DeviceAuthSslResult
,其中提供失敗的詳細資訊。 例如:
static CURLcode MyCallback(CURL *curl, void *sslctx, void *userCtx)
{
int err = DeviceAuth_SslCtxFunc(sslctx);
Log_Debug("ssl func callback error %d\n", err);
if (err) {
// detailed error handling code goes here
}
return CURLE_OK;
}
...
err = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, MyCallback);
if (err) {
goto cleanupLabel;
}
在您的伺服器上使用租用戶憑證鏈結
若要執行相互驗證,伺服器必須能夠驗證裝置是否屬於您的 Azure Sphere 租使用者,而且租使用者本身是合法的。 若要執行此驗證,伺服器需要 Azure Sphere 租使用者的憑證鏈結,以簽署您的所有 Azure Sphere 裝置:
若要取得租用戶的憑證鏈結,請將它下載至 .p7b 檔案,如下列範例所示:
azsphere ca-certificate download-chain --destination CA-cert-chain.p7b
然後,您可以在伺服器上使用 .p7b 檔案。
使用 curl 的其他秘訣
以下是在 Azure Sphere 應用程式中使用 curl 的一些其他秘訣。
若要確保 curl 遵循重新導向,請將下列內容新增至您的程式代碼:
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
若要新增在偵錯期間可能有説明之 curl 作業的詳細資訊:
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
如果要求不包含使用者代理程式,某些伺服器會傳回錯誤。 若要設定使用者代理程式:
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
處理curl_multi定時器回呼時,請避免在回報逾時為 0 毫秒時遞歸呼叫,因為這可能會造成無法預測的行為。 相反地,藉由觸髮 EventLoopTimer 將 0 毫秒視為 1 毫秒(0 毫秒 EventLoopTimers 也是遞歸的,應該避免)。
static int CurlTimerCallback(CURLM *multi, long timeoutMillis, void *unused) { // A value of -1 means the timer does not need to be started. if (timeoutMillis != -1) { if (timeoutMillis == 0) { // We cannot queue an event for 0ms in the future (the timer never fires) // So defer it very slightly (see https://curl.se/libcurl/c/multi-event.html) timeoutMillis = 1; } // Start a single shot timer with the period as provided by cURL. // The timer handler will invoke cURL to process the web transfers. const struct timespec timeout = {.tv_sec = timeoutMillis / 1000, .tv_nsec = (timeoutMillis % 1000) * 1000000}; SetEventLoopTimerOneShot(curlTimer, &timeout); } return 0; }