建立已簽署的 AWS API 要求 - AWS Identity and Access Management

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

建立已簽署的 AWS API 要求

重要

如果您使用 AWS SDK (請參閱範例程式碼和程式庫) 或 AWS 命令列 (CLI) 工具將 API 要求傳送至 AWS,您可以略過此區段,因為 SDK 和 CLI 用戶端會使用您提供的存取金鑰來驗證您的要求。除非有充分的理由不這樣做,否則建議您始終使用 SDK 或 CLI。

在支援多個簽章版本的區域中,手動簽署要求意味著您必須指定要使用的簽章版本。當您向多區域存取點提供請求時,SDK 和 CLI 會自動切換為使用第 4A 版簽署程序,而不需其他組態。

以下是建立已簽署請求的程序概觀。若要計算簽章,首先需要一個要簽名的字串。然後,您可以使用簽署金鑰計算要簽署的字串的 HMAC-SHA256 雜湊。下圖說明此程序,包括您為簽署建立的字串的各種元件。

正式請求、要簽署的字串、簽署金鑰和簽章的部分的影像。

下表描述圖表中顯示的函數。您需要為這些函數實作程式碼。如需詳細資訊,請參閱 AWS SDK 中的程式碼範例

函式 描述

Lowercase()

將字串轉換成小寫。

Hex()

小寫基數 16 編碼。

SHA256Hash()

安全雜湊演算法 (SHA) 加密雜湊函數。

HMAC-SHA256()

使用 SHA256 演算法搭配提供的簽署金鑰來計算 HMAC。這是最後的簽章。

Trim()

移除任何前置和結尾空格。

UriEncode()

URI 編碼每個字節。 UriEncode()必須執行以下規則:

  • URI 對除未預留字元之外的每個位元組進行編碼:'A'-'Z', 'a'-'z', '0'-'9', '-', '.', '_', and '~'。

  • 空格字元是預留字元,必須編碼為 "%20" (而不是 "+")。

  • 每個 URI 編碼的位元組都是由 '%' 和位元組的兩位數十六進位值組成。

  • 十六進位值中的字母必須為大寫,例如 "%1A"。

  • 對所有位置的正斜線字元 '/' 進行編碼 (物件索引鍵名稱除外)。例如,如果物件索引鍵名稱為 photos/Jan/sample.jpg,則不會對索引鍵名稱中的正斜線進行編碼。

重要

您的開發平台提供的標準 UriEncode 功能可能因為基礎 RFC 中的實作和相關模糊性的差異而無法運作。我們建議您編寫自己的自定義 UriEncode 函數,以確保您的編碼能夠正常工作。

若要查看 Java 中 UriEncode 函數的範例,請參閱 GitHub 網站上的 Java 公用程式

注意

簽署請求時,您可以使用 AWS 簽名版本 4 或 AWS 簽名版本 4A。兩者之間的主要差異取決於簽章的計算方式。使用「 AWS 簽名版本 4A」時,簽章不包含區域特定資訊,並使用演算法計算。AWS 4-ECDSA-P256-SHA256

暫時安全憑證

您可以使用 AWS Security Token Service (AWS STS) 提供的臨時安全登入資料,而不是使用長期認證來簽署要求。

當您使用臨時安全憑證時,必須將 X-Amz-Security-Token 新增至授權標頭或查詢字串,以保留工作階段權杖。某些服務會要求您將 X-Amz-Security-Token 新增至正式請求。其他服務只需要您在計算簽章之後於結尾新增 X-Amz-Security-Token。請查看每個文檔以獲取 AWS 服務 詳細信息。

簽署步驟摘要

步驟 1:建立正式請求

將您的請求內容 (主機、動作、標頭等) 編排為標準正式格式。正式請求就是其中一個用於建立登入字串的輸入。如需詳細資訊,請參閱 AWS API 請求簽名的元素

步驟 2:建立正式請求雜湊

透過在要求日期、區域和服務執行連續的金鑰加上金鑰的金鑰做為初始雜湊作業的 AWS 金鑰,以衍生簽署金鑰。

步驟 3:建立要簽署的字串

使用正式請求和額外資訊,例如演算法、請求日期、登入資料範圍及正式請求的摘要 (雜湊),建立登入字串。

步驟 4:計算簽章

您衍生簽署金鑰之後,可在登入字串上執行金鑰式雜湊操作,即可計算簽章。使用衍生的金鑰做為此操作的雜湊金鑰。

步驟 5:將簽章新增至請求

在您計算簽章、將簽章加到 HTTP 標頭,或加到請求的查詢字串之後。

步驟 1:建立正式請求

透過串連以下字串 (以換行符號字元分隔) 建立正式請求。這有助於確保您計算的簽名和計 AWS 算的簽名可以相符。

<HTTPMethod>\n <CanonicalURI>\n <CanonicalQueryString>\n <CanonicalHeaders>\n <SignedHeaders>\n <HashedPayload>
  • HTTPMethod – HTTP 方法,例如 GETPUTHEADDELETE

  • CanonicalUri— 絕對路徑元件 URI 的 URI 編碼版本,從網域名稱後面的「/」開始,直到字串結尾或問號字元 ('?') 如果你有查詢字符串參數。如果絕對路徑空白,請使用斜線字元 (/)。下列範例中的 URI /examplebucket/myphoto.jpg 是絕對路徑,您不會在絕對路徑中編碼 "/":

    http://s3.amazonaws.com/examplebucket/myphoto.jpg
  • CanonicalQueryString— URI 編碼的查詢字串參數。您可以個別對每個名稱和值進行 URI 編碼。您還必須依索引鍵名稱的字母順序來排序正式查詢字串中的參數。編碼後進行排序。下列 URI 範例中的查詢字串為:

    http://s3.amazonaws.com/examplebucket?prefix=somePrefix&marker=someMarker&max-keys=2

    正式查詢字串如下所示 (為了便於閱讀,向此範例新增了分行符號):

    UriEncode("marker")+"="+UriEncode("someMarker")+"&"+ UriEncode("max-keys")+"="+UriEncode("20") + "&" + UriEncode("prefix")+"="+UriEncode("somePrefix")

    請求以子資源為目標時,對應的查詢參數值將是空字串 ("")。例如,下列 URI 會識別 examplebucket 儲存貯體上的 ACL 子資源:

    http://s3.amazonaws.com/examplebucket?acl

    CanonicalQueryString 在這種情況下,如下所示:

    UriEncode("acl") + "=" + ""

    如果 URI 不包含 '?',則請求中沒有查詢字串,並且您將正式查詢字串設定為空字串 ("")。您仍然需要包含 "\n"。

  • CanonicalHeaders— 請求標頭及其值的清單。個別標頭名稱和值對以新行字元 ("\n") 分隔。以下是 canonicalheader 的範例:

    Lowercase(<HeaderName1>)+":"+Trim(<value>)+"\n" Lowercase(<HeaderName2>)+":"+Trim(<value>)+"\n" ... Lowercase(<HeaderNameN>)+":"+Trim(<value>)+"\n"

    CanonicalHeaders 列表必須包括以下內容:

    • HTTP host 標頭。

    • 如果標Content-Type頭存在於請求中,則必須將其添加到CanonicalHeaders列表中。

    • 還必須新增您計劃包含在請求中的任何 x-amz-* 標頭。例如,如果您使用的是暫時安全憑證,需要將 x-amz-security-token 包含在您的請求中。您必須在的清單中新增此標頭CanonicalHeaders

    注意

    Amazon S3 AWS 請求需要x-amz-content-sha256標頭。其提供請求承載的雜湊。如果沒有承載,您必須提供空字串的雜湊。

    每個標頭名稱必須:

    • 使用小寫字元。

    • 依字母順序顯示。

    • 後接冒號 (:)。

    對於值,您必須:

    • 修剪任何前置或結尾空格。

    • 將連續空格轉換為單一空格。

    • 使用逗號分隔多值標頭的值。

    • 簽章中必須包含主機標頭 (HTTP/1.1) 或 :authority 標頭 (HTTP/2),以及簽章中的任何 x-amz-* 標頭。可以選擇性地在簽章中包含其他標準標頭,例如 content-type。

    本範例中使用的 Lowercase()Trim() 函數在上一節中進行了描述。

    以下是 CanonicalHeaders 字串範例。標頭名稱為小寫且已排序。

    host:s3.amazonaws.com x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 x-amz-date:20130708T220855Z

    注意

    對於計算授權簽章而言,僅需要主機和任何 x-amz-* 標頭;但是,為了防止資料竄改,您應考慮在簽章計算中包含所有標頭。

  • SignedHeaders— 按字母順序排序、以分號分隔的小寫要求標頭名稱清單。清單中的請求標頭與您在 CanonicalHeaders 字串中包含的標頭相同。例如,對於上一個範例,的值SignedHeaders將如下所示:

    host;x-amz-content-sha256;x-amz-date
  • HashedPayload— 使用 HTTP 要求主體中的有效負載建立的字串,做為雜湊函數的輸入。此字串使用小寫十六進位字元。

    Hex(SHA256Hash(<payload>)

    如果請求中沒有承載,則計算空字串的雜湊,如下所示:

    Hex(SHA256Hash(""))

    雜湊會傳回下列值:

    e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

    例如,使用 PUT 請求上傳物件時,請在主體中提供物件資料。使用 GET 請求擷取物件時,請計算空字串雜湊。

步驟 2:建立正式請求雜湊

使用與您用來建立承載雜湊相同的演算法,建立正式請求的雜湊 (摘要)。正式請求的雜湊是小寫十六進位字元字串。

步驟 3:建立登入字串

透過串連以下字串 (以換行符號字元分隔) 建立字串。請勿以換行符號字元結束此字串。

Algorithm \n RequestDateTime \n CredentialScope \n HashedCanonicalRequest
  • Algorithm - 用來建立正式請求雜湊的演算法。對於 SHA-256 而言,演算法為 AWS4-HMAC-SHA256

  • RequestDateTime— 認證範圍中使用的日期和時間。此值是 ISO 8601 格式的目前 UTC 時間 (例如,20130524T000000Z)。

  • CredentialScope— 認證範圍。這會將產生的簽章限制到指定的區域和服務。該字串具有以下格式:YYYYMMDD/region/service/aws4_request。

  • HashedCanonicalRequest— 規範要求的雜湊值。此值是在步驟 2 中計算的。

以下是登入字串範例。

"AWS4-HMAC-SHA256" + "\n" + timeStampISO8601Format + "\n" + <Scope> + "\n" + Hex(SHA256Hash(<CanonicalRequest>))

步驟 4:計算簽章

在 S AWS ignature Version 版本 4 中,您不需要使用 AWS 存取金鑰來簽署請求,而是建立範圍為特定區域和服務的簽署金鑰,做為要新增至要求的驗證資訊。

DateKey = HMAC-SHA256("AWS4"+"<SecretAccessKey>", "<YYYYMMDD>") DateRegionKey = HMAC-SHA256(<DateKey>, "<aws-region>") DateRegionServiceKey = HMAC-SHA256(<DateRegionKey>, "<aws-service>") SigningKey = HMAC-SHA256(<DateRegionServiceKey>, "aws4_request")

如需區域字串清單,請參閱《AWS 一般參考》中的區域端點

對於每個步驟,使用所需金鑰和資料呼叫雜湊函數。對雜湊函數的每次呼叫結果都會變成雜湊函數的下一次呼叫輸入。

需要輸入
  • 包含私密存取金鑰的字串 Key

  • 字串 Date,其中包含憑證範圍中使用的日期,格式為 YYYYMMDD

  • 包含區域代碼 (例如,us-east-1) 的字串 Region

  • 包含服務代碼 (例如,ec2) 的字串 Service

  • 在之前步驟中建立的登入字串。

若要計算簽章。
  1. 串連 "AWS4" 和私密存取金鑰。呼叫雜湊函數,將串連的字串作為索引鍵,日期字串做為資料。

    kDate = hash("AWS4" + Key, Date)
  2. 呼叫雜湊函數,將上一次呼叫的結果作為索引鍵,區域字串作為資料。

    kRegion = hash(kDate, Region)
  3. 呼叫雜湊函數,將上一次呼叫的結果作為索引鍵,服務字串作為資料。

    kService = hash(kRegion, Service)
  4. 呼叫雜湊函數,將上一次呼叫的結果作為索引鍵,"aws4_request" 作為資料。

    kSigning = hash(kService, "aws4_request")
  5. 呼叫雜湊函數,將上一次呼叫的結果作為索引鍵,登入字串作為資料。結果是作為二進位值的簽章。

    signature = hash(kSigning, string-to-sign)
  6. 將簽章的表示形式從二進位轉換為十六進位,使用小寫字元。

步驟 5:將簽章新增至請求

範例:授權標頭

以下範例顯示針對 DescribeInstances 動作的 Authorization 標頭。為了便於閱讀,此範例使用換行符號進行格式化。在代碼中,這必須是一個連續字串。演算法和 Credential 之間沒有逗號。但是,必須使用逗號分隔其他元素。

Authorization: AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20220830/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=calculated-signature
範例:查詢字串中包含身分驗證參數的請求

以下範例顯示針對 DescribeInstances 動作的查詢,其中包含身分驗證資訊。為了便於閱讀,此範例使用換行符號進行格式化,而不是 URL 編碼。在程式碼中,查詢字串必須是 URL 編碼的連續字串。

https://ec2.amazonaws.com/? Action=DescribeInstances& Version=2016-11-15& X-Amz-Algorithm=AWS4-HMAC-SHA256& X-Amz-Credential=AKIAIOSFODNN7EXAMPLE/20220830/us-east-1/ec2/aws4_request& X-Amz-Date=20220830T123600Z& X-Amz-SignedHeaders=host;x-amz-date& X-Amz-Signature=calculated-signature

AWS 軟體開發套件中的原始程式碼

AWS SDK 包含 GitHub 用於簽署 AWS API 要求的原始程式碼。如需程式碼範例,請參閱 範例儲存庫中的 AWS 範例專案