

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

# 使用已簽署 URL 和已簽署 Cookie 提供私有內容
<a name="PrivateContent"></a>

許多透過網際網路分配內容的公司想要限制對所選使用者的文件、業務資料、媒體串流，或內容的存取許可，例如已付費的使用者。若要使用 CloudFront 安全地提供這類私有內容，請執行以下操作：
+ 請求使用者使用特殊 CloudFront 已簽署的 URL 或已簽署的 Cookie 存取私有內容。
+ 請求您的使用者使用 CloudFront URL 來存取您的內容，而不要使用直接在原始伺服器上存取內容的 URL (例如，Amazon S3 或私有 HTTP 伺服器)。CloudFront URL 非屬必要但建議使用，可防止使用者略過已簽署的 URL 或已簽署的 Cookie 中指定的限制。

如需詳細資訊，請參閱[限制檔案存取](private-content-overview.md)。

## 如何提供私有內容
<a name="private-content-task-list"></a>

若要設定 CloudFront 以提供私有內容，請執行以下任務：

1. (選用建議) 請求您的使用者只能透過 CloudFront 存取內容。您使用的方法取決於您使用的是 Amazon S3 或自訂原始伺服器：
   + ** Amazon S3** – 請參閱 [限制對 Amazon S3 原始伺服器的存取](private-content-restricting-access-to-s3.md)。
   + **自訂原始伺服器** – 請參閱 [在自訂原始伺服器上限制存取檔案](private-content-overview.md#forward-custom-headers-restrict-access)。

   自訂原始伺服器包括 Amazon EC2、設定為網站端點的 Amazon S3 儲存貯體、Elastic Load Balancing，以及您自己的 HTTP Web 伺服器。

1. 指定您要用來建立已簽署 URL 或已簽署 Cookie 的*信任金鑰群組*或*可信簽署者*。建議您使用信任的金鑰群組。如需詳細資訊，請參閱 [指定可以建立已簽署 URL 和已簽署 Cookie 的簽署者](private-content-trusted-signers.md)。

1. 撰寫您的應用程式，使用已簽章的 URL或使用已設定簽章的 Cookie 的 `Set-Cookie` 標頭，以回應來自已獲授權使用者的請求。請遵循下列其中一個主題中的步驟進行：
   + [使用已簽署 URL](private-content-signed-urls.md)
   + [使用已簽署 Cookie](private-content-signed-cookies.md)

   如果您不確定要使用哪個方法，請參閱 [決定使用已簽署 URL 或已簽署 Cookie](private-content-choosing-signed-urls-cookies.md)。

**Topics**
+ [如何提供私有內容](#private-content-task-list)
+ [限制檔案存取](private-content-overview.md)
+ [指定可以建立已簽署 URL 和已簽署 Cookie 的簽署者](private-content-trusted-signers.md)
+ [決定使用已簽署 URL 或已簽署 Cookie](private-content-choosing-signed-urls-cookies.md)
+ [使用已簽署 URL](private-content-signed-urls.md)
+ [使用已簽署 Cookie](private-content-signed-cookies.md)
+ [用於 Base64 編碼和加密的 Linux 命令和 OpenSSL](private-content-linux-openssl.md)
+ [為已簽署 URL 建立簽章的程式碼範例](PrivateCFSignatureCodeAndExamples.md)

# 限制檔案存取
<a name="private-content-overview"></a>

您可以透過兩種方式控制使用者對私人內容的存取權：
+ [限制存取 CloudFront 快取中的檔案](#private-content-overview-edge-caches)。
+ 執行以下其中一項以在您的原始伺服器中限制存取檔案：
  + [為您的 Amazon S3 儲存貯體設定原始存取控制 (OAC)](private-content-restricting-access-to-s3.md)。
  + [為私有 HTTP 伺服器 (自訂原始伺服器) 設定自訂標頭。](#forward-custom-headers-restrict-access)

## 限制存取 CloudFront 快取中的檔案
<a name="private-content-overview-edge-caches"></a>

您可以設定 CloudFront，來請求使用者使用*已簽署的 URL* 或*已簽署的 Cookie*，以存取您的檔案。然後，您可以開發應用程式，以建立和分配已簽署的 URL 給驗證過的使用者，或傳送 `Set-Cookie` 標頭，這是經驗證之使用者設定的已簽署 Cookie。(若要提供一些使用者長期存取少量檔案，您還可以手動建立簽章的 URL。) 

當您建立已簽章的 URL 或已簽章的 Cookie，以控制存取您的檔案時，可以指定下列限制：
+ 結束日期和時間，之後 URL 不再有效。
+ (選用) URL 生效的日期和時間。
+ (選用) 可用於存取內容的電腦的 IP 位址或地址範圍。

使用公有-私有金鑰對中的私有金鑰對已簽署的 URL 或已簽署的 Cookie 的一部分進行雜湊和簽名。當有人使用已簽署的 URL 或已簽署的 Cookie 存取檔案時，CloudFront 會比較 URL 或 Cookie 的已簽署和未簽署部分。如果它們不相符， CloudFront 就不會提供檔案。

您必須使用 RSA 2048 或 ECDSA 256 私有金鑰來簽署 URL 或 Cookie。

## 限制對 Amazon S3 儲存貯體中檔案的存取
<a name="private-content-overview-s3"></a>

您可以選擇性地保護 Amazon S3 儲存貯體中的內容，以便使用者可以透過指定的 CloudFront 分佈，但無法使用 Amazon S3 URL 直接進行存取。這可防止某些人繞過 CloudFront 並利用 Amazon S3 URL 來取得您想要限制其存取的內容。使用簽章 URL 不需要此步驟，但我們建議執行此作業。

若要請求使用者透過 CloudFront URL 存取您的內容，請執行下列任務：
+ 授予 CloudFront *原始存取控制*許可，以讀取 S3 儲存貯體中的檔案。
+ 建立原始存取控制，並將其與您的 CloudFront 分佈產生關聯。
+ 移除其他人使用 Amazon S3 URL 讀取檔案的許可。

如需詳細資訊，請參閱 [限制對 Amazon S3 原始伺服器的存取](private-content-restricting-access-to-s3.md) 或 [限制對 Amazon S3 多區域存取點原始伺服器的存取](private-content-restricting-access-to-s3-mrap.md) 。

## 在自訂原始伺服器上限制存取檔案
<a name="forward-custom-headers-restrict-access"></a>

如果您使用自訂原始伺服器，您可以選擇性設定自訂標頭來限制存取。若要使 CloudFront 從自訂原始伺服器取得您的檔案，必須使用標準 HTTP (或 HTTPS) 請求來提供 CloudFront 檔案的存取權限限。然而透過自訂標頭，您可以限制存取內容，讓使用者只能透過 CloudFront，而無法直接進行存取。使用簽章 URL 不需要此步驟，但我們建議執行此作業。

若要請求使用者透過 CloudFront 存取內容，請在您的 CloudFront 分佈中變更下列設定：

**原始伺服器自訂標頭**  
設定 CloudFront 以將自訂標頭轉送至原始伺服器 請參閱 [設定 CloudFront 以將自訂標頭新增到原始伺服器請求](add-origin-custom-headers.md#add-origin-custom-headers-configure)。

**檢視器通訊協定政策**  
設定您的分佈以請求檢視器使用 HTTPS 來存取 CloudFront。請參閱 [檢視器通訊協定政策](DownloadDistValuesCacheBehavior.md#DownloadDistValuesViewerProtocolPolicy)。

**原始伺服器通訊協定政策**  
將分佈設定為請求 CloudFront 使用與檢視器相同的協定將請求轉傳到原始伺服器。請參閱 [通訊協定 (僅限自訂原始伺服器)](DownloadDistValuesOrigin.md#DownloadDistValuesOriginProtocolPolicy)。

完成這些變更之後，請在自訂原始伺服器上更新應用程式，以僅接受包含您已設定 CloudFront 要傳送之自訂標頭的請求。

**檢視器通訊協定政策**與**原始伺服器通訊協定政策**的組合可確保自訂標頭在傳輸過程中加密。但是，我們建議您定期執行以下任務來輪換 CloudFront 轉傳到您原始伺服器的自訂標頭：

1. 更新您的 CloudFront 分佈以開始將新標頭轉送至您的自訂原始伺服器。

1. 更新您的應用程式以接受新標頭，以確認請求來自 CloudFront。

1. 當檢視器請求不再包括要替換的標頭時，請更新應用程式至不再接受的舊標頭，以確認請求來自 CloudFront。

# 指定可以建立已簽署 URL 和已簽署 Cookie 的簽署者
<a name="private-content-trusted-signers"></a>

**Topics**
+ [在信任的金鑰群組 （建議） 和 之間進行選擇 AWS 帳戶](#choosing-key-groups-or-AWS-accounts)
+ [為您的簽署者建立金鑰對](#private-content-creating-cloudfront-key-pairs)
+ [重新格式化私有金鑰 (僅限 .NET 和 Java)](#private-content-reformatting-private-key)
+ [將簽署者新增至分佈](#private-content-adding-trusted-signers)
+ [輪換金鑰對](#private-content-rotating-key-pairs)

若要建立已簽署 URL 或已簽署 Cookie，您需要 *簽署者*。簽署者是您在 CloudFront 中建立的受信任金鑰群組，或是包含 CloudFront 金鑰對 AWS 的帳戶。建議您使用具有已簽署 URL 和已簽署 Cookie 信任的金鑰群組。如需詳細資訊，請參閱 [在信任的金鑰群組 （建議） 和 之間進行選擇 AWS 帳戶](#choosing-key-groups-or-AWS-accounts)。

簽署者有兩個用途：
+ 一旦您將簽署者新增至您的分佈，CloudFront 就會開始請求檢視器使用已簽署的 URL 或已簽署的 Cookie 來存取您的檔案。
+ 當您建立已簽署 URL 或已簽署 Cookie 時，您可以使用簽署者金鑰對中的私有金鑰對 URL 或 Cookie 的一部分進行簽署。當有人請求受限制的檔案時，CloudFront 會將 URL 或 Cookie 中的簽章與未簽署的 URL 或 Cookie 進行比較，以確認檔案未遭竄改。CloudFront 也可以驗證 URL 或 Cookie 是否有效，也就是好比說到期日期時間到期了嗎？

當您指定簽署者時，您也可以透過將簽署者新增至快取行為，以間接指定需要簽署 URL 或簽署 Cookie 的檔案。如果分佈只有一個快取行為，則使用者必須使用已簽署 URL 或已簽署 Cookie 來存取該分佈中的任何檔案。如果您建立多個快取行為，並將簽署者新增到一些快取行為，而非其他快取行為，則可以請求檢視器使用已簽署 URL 或已簽署 Cookie 來存取這些物件，而非其他檔案。

若要指定允許建立已簽署 URL 或已簽署 Cookie 的簽署者 (私有金鑰)，並將帳戶新增到 CloudFront 分佈中，請執行以下任務：

1. 決定要使用信任的金鑰群組或 AWS 帳戶 做為簽署者。建議您使用信任的金鑰群組。如需詳細資訊，請參閱 [在信任的金鑰群組 （建議） 和 之間進行選擇 AWS 帳戶](#choosing-key-groups-or-AWS-accounts)。

1. 針對您在步驟 1 中選擇的簽署者，建立公有-私有金鑰對。如需詳細資訊，請參閱 [為您的簽署者建立金鑰對](#private-content-creating-cloudfront-key-pairs)。

1. 如果您使用 .NET 或 Java 建立已簽署 URL 或已簽署 Cookie，請重新格式化私有金鑰。如需詳細資訊，請參閱 [重新格式化私有金鑰 (僅限 .NET 和 Java)](#private-content-reformatting-private-key)。

1. 在您要為其建立已簽署 URL 或已簽署 Cookie 的分佈中，指定簽署者。如需詳細資訊，請參閱[將簽署者新增至分佈](#private-content-adding-trusted-signers)。

## 在信任的金鑰群組 （建議） 和 之間進行選擇 AWS 帳戶
<a name="choosing-key-groups-or-AWS-accounts"></a>

若要使用已簽署 URL 或已簽署 Cookie，您需要 *簽署者*。簽署者可以是您在 CloudFront 中建立的可信金鑰群組，也可以是包含 CloudFront 金鑰對的 AWS 帳戶 。基於下列原因，建議您使用信任的金鑰群組：
+ 使用 CloudFront 金鑰群組時，您不需要使用 AWS 帳戶根使用者來管理 CloudFront 已簽章 URLs公有金鑰。 [AWS 最佳實務](https://docs.aws.amazon.com/general/latest/gr/root-vs-iam.html#aws_tasks-that-require-root)建議您不需要使用根使用者。
+ 透過 CloudFront 金鑰群組，您可以使用 CloudFront API 管理公有金鑰、金鑰群組和受信任的簽署者。您可以使用 API 自動化金鑰建立和金鑰輪換。當您使用 AWS 根使用者時，必須使用 AWS 管理主控台 來管理 CloudFront 金鑰對，因此您無法自動化程序。
+ 由於您可以使用 CloudFront API 管理金鑰群組，因此您也可以使用 AWS Identity and Access Management (IAM) 許可原則來限制不同使用者可執行的動作。例如，您可以允許使用者上傳公有金鑰，但不能刪除公有金鑰。或者，您可以允許使用者刪除公有金鑰，但只有在符合特定條件時，例如使用多因素驗證、從特定網路傳送請求，或是在特定日期和時間範圍內傳送請求。
+ 透過 CloudFront 金鑰群組，您可以將較多數目的公有金鑰與您的 CloudFront 分佈產生關聯，讓您在使用和管理公有金鑰方面擁有更大的彈性。根據預設，您最多可以將四個金鑰群組與單一分佈產生關聯，而且一個金鑰群組中最多可以有五個公有金鑰。

  當您使用 AWS 帳戶根使用者管理 CloudFront 金鑰對時，每個 AWS 帳戶最多只能有兩個作用中的 CloudFront 金鑰對。

## 為您的簽署者建立金鑰對
<a name="private-content-creating-cloudfront-key-pairs"></a>

您用來建立 CloudFront 已簽署 URL 或已簽署 Cookie 的每個簽署者都必須具有公有-私有金鑰對。簽署者使用其私有金鑰來簽署 URL 或 Cookie，並且 CloudFront 會使用公有金鑰來驗證簽章。

建立金鑰對的方式視您使用信任的金鑰群組做為簽署者 (建議使用) 或是 CloudFront 金鑰對而定。如需詳細資訊，請參閱下列區段。您建立的金鑰對必須符合下列需求：
+ 它必須是 SSH-2 RSA 2048 或 ECDSA 256 金鑰對。
+ 它必須是 base64 編碼的 PEM 格式。

為了協助保護應用程式的安全，建議您定期輪換金鑰對。如需詳細資訊，請參閱 [輪換金鑰對](#private-content-rotating-key-pairs)。

### 為信任的金鑰群組建立金鑰對 (建議使用)
<a name="create-key-pair-and-key-group"></a>

若要為信任的金鑰群組建立金鑰對，請執行下列步驟：

1. 建立公有-私有金鑰對。

1. 將公有金鑰上傳至 CloudFront 。

1. 將公有金鑰新增至 CloudFront 金鑰群組。

如需詳細資訊，請參閱下列程序。<a name="private-content-uploading-cloudfront-public-key-procedure"></a>

**建立一組金鑰對**
**注意**  
下列步驟會使用 OpenSSL 做為建立金鑰對的一種方式來示範。還有許多其他方法可以建立 RSA 或 ECDSA 金鑰對。

1. 請執行下列其中一個範例命令：
   + 下列範例命令會使用 OpenSSL 產生長度為 2048 位元的 RSA 金鑰對，並儲存至名為 `private_key.pem` 的檔案。

     ```
     openssl genrsa -out private_key.pem 2048
     ```
   + 下列範例命令會使用 OpenSSL 產生具備 `prime256v1` 曲線的 ECDSA 金鑰對，並儲存至名為 `private_key.pem` 的檔案。

     ```
     openssl ecparam -name prime256v1 -genkey -noout -out privatekey.pem
     ```

1. 產生的檔案同時包含公有和私有金鑰。下列範例命令會從名為 `private_key.pem` 的檔案擷取公有金鑰。

   ```
   openssl rsa -pubout -in private_key.pem -out public_key.pem
   ```

   您稍後會在下列程序中上傳公有金鑰 (在 `public_key.pem` 檔案中)。

**將公有金鑰上傳至 CloudFront**

1. 登入 AWS 管理主控台 ，並在 開啟 CloudFront 主控台[https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)。

1. 在導覽功能表中，選擇**公有金鑰**。

1. 選擇**建立公有金鑰**。

1. 在**建立公有金鑰**視窗中，執行下列動作：

   1. 在**金鑰名稱**中，輸入識別公有金鑰的名稱。

   1. 對於 **Key value** (鍵值)，貼上公有金鑰。如果您遵循上述程序中的步驟，則公有金鑰位於名為 `public_key.pem` 的檔案中。若要複製並貼上公有金鑰的內容，您可以：
      + 在 macOS 或 Linux **cat** 命令列上使用這個命令，如下所示：

        ```
        cat public_key.pem
        ```

        複製該命令的輸出，然後將其貼 **Key value** (鍵值) 欄位中。
      + 使用像「記事本」(在 Windows 上) 或「文字編輯」(在 macOS 上) 等純文字編輯器開啟 `public_key.pem` 檔案。複製檔案內容，然後將其貼到 **Key value** (鍵值) 欄位中。

   1. (選用) 對於**註解**，請新增註解以描述公有金鑰。

   完成時，請選擇**新增**。

1. 記錄公有金鑰 ID。您稍後在建立已簽署 URL 或已簽署 Cookie 時使用它，以做為 `Key-Pair-Id` 欄位的值。

**將公有金鑰新增至金鑰群組**

1. 在 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home) 中開啟 CloudFront 主控台。

1. 在導覽功能表中，選擇**金鑰群組**。

1. 選擇**新增金鑰群組**。

1. 在**建立金鑰群組**頁面上，執行下列動作：

   1. 在**金鑰群組名稱**中，輸入識別金鑰群組的名稱。

   1. (選用) 在**註解**中，輸入註解以描述金鑰群組。

   1. 在**公有金鑰**中，選取要新增至金鑰群組的公有金鑰，然後選擇**新增**。針對您要新增至金鑰群組的每個公有金鑰重複此步驟。

1. 選擇**建立金鑰對**。

1. 記錄金鑰群組名稱。稍後您可以使用它來將金鑰群組與 CloudFront 分佈中的快取行為產生關聯。(在 CloudFront API 中，您可以使用金鑰群組 ID，將金鑰群組與快取行為產生關聯。)

### 建立 CloudFront 金鑰對 （不建議，需要 AWS 帳戶 根使用者）
<a name="create-key-pair-aws-account"></a>

**重要**  
建議您建立信任金鑰群組的公有金鑰，而不是遵循下列步驟。如需建立已簽署 URL 和已簽署 Cookie 之公有金鑰的建議方式，請參閱[為信任的金鑰群組建立金鑰對 (建議使用)](#create-key-pair-and-key-group)。

您可以使用下列方式建立 CloudFront 金鑰對：
+ 在 中建立金鑰對 AWS 管理主控台 並下載私有金鑰。請參見下列步驟：
+ 使用諸如 OpenSSL 的應用程式建立 RSA 金鑰對，並將公有金鑰上傳到 AWS 管理主控台。如需有關建立 RSA 金鑰對的詳細資訊，請參閱 [為信任的金鑰群組建立金鑰對 (建議使用)](#create-key-pair-and-key-group)。<a name="private-content-creating-cloudfront-key-pairs-procedure"></a>

**在 中建立 CloudFront 金鑰對 AWS 管理主控台**

1.  AWS 管理主控台 使用帳戶根使用者的登入資料 AWS 登入 。
**重要**  
IAM 使用者無法建立 CloudFront 金鑰對。您必須使用根使用者登入資料登入，才能建立金鑰對。

1. 選擇您的帳戶名稱，然後選擇**我的安全登入資料**。

1. 選擇 **CloudFront 金鑰對**。

1. 確認您沒有多個作用中的金鑰對。如果您已經有兩個使用中的金鑰對，則無法建立金鑰對。

1. 選擇**建立新的金鑰對**。
**注意**  
您也可以選擇建立自己的金鑰對並上傳公有金鑰。CloudFront 金鑰對支援 1024、2048 或 4096 位元金鑰。

1. 在**建立金鑰對**的對話方塊中，選擇**下載私有金鑰檔案**，然後將檔案儲存在電腦上。
**重要**  
在安全的位置儲存 CloudFront 金鑰對的私有金鑰，並設定該檔案的許可，以便只有所需的管理員可以讀取該金鑰。如果有人取得您的私有金鑰，他們可以產生有效已簽章的 URL 和已簽章的 Cookie 並下載您的內容。您不能再次取得私有金鑰，因此如果您遺失或刪除它，則必須建立新的 CloudFront 金鑰對。

1. 記錄您的金鑰對的金鑰對 ID。（在 中 AWS 管理主控台，這稱為**存取金鑰 ID**。) 您將在建立已簽署 URL 或已簽署 Cookie 時使用它。

## 重新格式化私有金鑰 (僅限 .NET 和 Java)
<a name="private-content-reformatting-private-key"></a>

如果您正使用 .NET 或 Java 以建立已簽署 URL 或已簽署 Cookie，則無法在預設 PEM 格式中，使用金鑰對的私有金鑰來建立簽章。相反地，請執行下列動作：
+ **.NET 框架** – 將私有金鑰轉換為 .NET 框架使用的 XML 格式。有幾種工具可用。
+ **Java** – 將私有金鑰轉換為 DER 格式。執行此操作的一種方法是使用以下 OpenSSL 命令。在下列命令中，`private_key.pem` 是包含 PEM 格式化的私有金鑰的檔案名稱，而且 `private_key.der` 是執行命令之後包含 DER 格式化的私有金鑰的檔案名稱。

  ```
  openssl pkcs8 -topk8 -nocrypt -in private_key.pem -inform PEM -out private_key.der -outform DER
  ```

  為了確保編碼器能正確運作，請將 Bouncy Castle Java 的密碼編譯 API 的 JAR 新增到專案中，然後再新增 Bouncy Castle 供應商。

## 將簽署者新增至分佈
<a name="private-content-adding-trusted-signers"></a>

簽署者是信任的金鑰群組 (建議使用) 或 CloudFront 金鑰對，可為分佈建立已簽署 URL 和已簽署 Cookie。若要在 CloudFront 分佈中使用已簽署 URL 或已簽署 Cookie，您必須指定簽署者。

簽署者與快取行為相關聯。在某些物件或不用於相同分佈之其他檔案下，這允許您要求簽章 URL 或簽章 Cookie。只有和對應快取行為相關聯的檔案，分佈才會要求已簽署的 URL 或 Cookie。

同樣地，簽署者只能為與對應快取行為相關聯的檔案簽署 URL 或 Cookie。例如，如果您有一個快取行為下的簽署者和不同快取行為下的不同簽署者，則這兩個簽署者都不能為與其他快取行為的相關檔案建立簽署 URL 或 Cookie。

**重要**  
在您將簽署者新增至分佈之前，請執行下列動作：  
請仔細定義快取行為中的路徑模式，以及快取行為順序，這樣您就不會讓使用者意外地存取您的內容，也不會讓他們存取您希望所有人都能使用的內容。  
例如，假設請求與兩個快取行為的路徑模式相符合。第一個快取行為不需要已簽章的 URL 或已簽章的 Cookie，而第二個快取行為則需要。使用者將能夠在不使用已簽署的 URL 或已簽署的 Cookie 的情況下存取檔案，因為 CloudFront 處理與第一個符合相關聯的快取行為。  
如需喲歐冠路徑模式的詳細資訊，請參閱 [路徑模式](DownloadDistValuesCacheBehavior.md#DownloadDistValuesPathPattern)。
對於您已經用來分佈內容的分配內容，請在新增簽署者之前，確定您已準備好開始產生已簽署 URL 和已簽署 Cookie。當您新增簽署者時，CloudFront 會拒絕未包含有效的已簽署 URL 或已簽署 Cookie 請求。

您可以使用 CloudFront 主控台或 CloudFront API 會將簽署者新增至您的分佈。

------
#### [ Console ]

下列步驟說明如何將信任的金鑰群組新增為簽署者。您也可以將 新增 AWS 帳戶 為信任的簽署者，但不建議這麼做。<a name="private-content-adding-trusted-signers-console-procedure"></a>

**使用主控台將簽署者新增至分佈**

1. 記錄要用作信任的簽署者之金鑰群組的金鑰群組 ID。如需詳細資訊，請參閱 [為信任的金鑰群組建立金鑰對 (建議使用)](#create-key-pair-and-key-group)。

1. 在 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home) 中開啟 CloudFront 主控台。

1. 使用已簽署 URL 或已簽署 Cookie，選擇要保護其檔案的分佈。
**注意**  
若要將簽署者新增至新的發行套件，您可以指定建立發行套件時步驟 6 所述的相同設定。

1. 選擇 **Behaviors (動作)** 索引標籤。

1. 選取快取行為，其路徑模式符合您要使用已簽署 URL 或已簽署 Cookie 保護的檔案，然後選擇**編輯**。

1. 在**編輯行為**頁面上，執行下列動作：

   1. 針對**限制檢視器存取 (使用已簽署 URL 或已簽署 Cookie)**，按一下**是**。

   1. 針對 **Trusted Key Groups or Trusted Signer** (信任的金鑰群組或可信簽署者)，選擇 **Trusted Key Groups** (信任的金鑰群組)。

   1. 在**信任的金鑰群組**中，選擇要新增的金鑰群組，然後選擇**新增**。如果您要新增多個金鑰群組，請重複此步驟。

1. 選擇**是，編輯**以更新快取行為。

------
#### [ API ]

您可以使用 CloudFront API 將信任的金鑰群組新增為簽署者。您可以將簽署者新增至現有分佈或新分佈。在任一情況下，請在 `TrustedKeyGroups` 元素中指定值。

您也可以將 新增 AWS 帳戶 為信任的簽署者，但不建議這麼做。

請參閱 *Amazon CloudFront API 參考*中的下列主題：
+ **更新現有的分佈** - [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html)
+ **建立新的分佈** – [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html)

------

## 輪換金鑰對
<a name="private-content-rotating-key-pairs"></a>

建議您定期輪換 (變更) 已簽署網址和已簽署 Cookie 的金鑰對。若要輪換您用來建立已簽署 URL 或已簽署 Cookie 的金鑰對，而不會使尚未到期的無效 URL 或 Cookie，請執行以下任務：

1. 建立新的金鑰對，並將公有金鑰新增至金鑰群組。如需詳細資訊，請參閱 [為信任的金鑰群組建立金鑰對 (建議使用)](#create-key-pair-and-key-group)。

1. 如果您在上一個步驟中建立了新的金鑰群組，[請以簽署者的身分將金鑰群組新增到分佈中](#private-content-adding-trusted-signers)。
**重要**  
請勿從金鑰群組中移除任何現有的公有金鑰，或從分佈中移除任何金鑰群組。請僅加入新的。

1. 使用新金鑰對中的私有金鑰來更新應用程式以建立簽章。確認已簽署 URL 或使用新私有金鑰簽署的 Cookie 正在運作。

1. 等待直到已簽署 URL 或 Cookie 過期，而使用先前的金鑰對。然後從金鑰群組中移除舊的公有金鑰。如果您在步驟 2 中建立新的金鑰群組，請從分佈中移除舊的金鑰群組。

# 決定使用已簽署 URL 或已簽署 Cookie
<a name="private-content-choosing-signed-urls-cookies"></a>

CloudFront 已簽署的 URL 和已簽署的 Cookie 提供了相同的基本函數：允許您控制哪些使用者可以存取您的內容。如果您想要透過 CloudFront 提供私有內容，並且正在嘗試決定是否使用已簽署的 URL 或已簽署的 Cookie，請考慮以下事項。

在以下案例使用已簽章的 URL：
+ 您想要限制對個別檔案的存取，例如，適用於您的應用程式安裝下載。
+ 您的使用者正在使用不支援 Cookie 的用戶端 (例如，自訂 HTTP 用戶端)。

在以下案例使用已簽章的 Cookie：
+ 您想要提供對多個限制檔案的存取，例如，HLS 格式視訊的所有檔案或網站中訂閱者區域的所有檔案。
+ 您不想變更目前的 URL。

如果您目前未使用簽章的 URL，並且您的 (未簽署) URL 包含以下任何查詢字串參數，則不能使用已簽章的 URL 或已簽章的 Cookie：
+ `Expires`
+ `Policy`
+ `Signature`
+ `Key-Pair-Id`
+ `Hash-Algorithm`

CloudFront 假設包含任何這些查詢字串參數的 URL 都是簽署的 URL，因此不會查看已簽署的 Cookie。

## 使用已簽署 URL 和已簽署 Cookie
<a name="private-content-using-signed-urls-and-cookies"></a>

已簽署的網址優先於已簽署的 Cookie。如果您同時使用已簽署的 URL 和已簽署的 Cookie 來控制對相同檔案的存取，並且檢視器使用已簽署的 URL 來請求檔案，CloudFront 將判斷是否只根據已簽署的 URL 將該檔案傳回給檢視器。

# 使用已簽署 URL
<a name="private-content-signed-urls"></a>

已簽章的 URL 包含附加資訊，例如到期日期和時間，以便您更有效地控制對內容的存取。此附加資訊顯示在政策聲明中，該政策聲明基於標準政策或自訂政策。標準和自訂政策之間的差異將在接下來的兩節中說明。

**注意**  
您可使用標準政策建立一些簽章的 URL，並使用自訂政策為相同的分佈建立一些簽章的 URL。

**Topics**
+ [決定對已簽署 URL 使用標準或自訂政策](#private-content-choosing-canned-custom-policy)
+ [已簽署 URL 的工作方式](#private-content-how-signed-urls-work)
+ [決定已簽署 URL 的有效時間](#private-content-overview-choosing-duration)
+ [CloudFront 何時檢查已簽署 URL 中的到期日期和時間](#private-content-check-expiration)
+ [範例程式碼和第三方工具](#private-content-overview-sample-code)
+ [使用標準政策建立已簽署 URL](private-content-creating-signed-url-canned-policy.md)
+ [使用自訂政策建立已簽署 URL](private-content-creating-signed-url-custom-policy.md)

## 決定對已簽署 URL 使用標準或自訂政策
<a name="private-content-choosing-canned-custom-policy"></a>

當您建立已簽章的 URL 時，您將編寫一個 JSON 格式的政策聲明來指定對已簽章的 URL 的限制，例如 URL 的有效時間。您可以使用標準政策或自訂政策。以下是標準和自訂政策的比較：


****  

| 描述 | 標準政策 | 自訂政策 | 
| --- | --- | --- | 
| 您可以重複使用多個檔案的政策聲明。要重複使用政策聲明，您必須在 `Resource` 物件中使用萬用字元。如需詳細資訊，請參閱 [您在使用自訂政策的已簽署 URL 政策陳述式中指定的值](private-content-creating-signed-url-custom-policy.md#private-content-custom-policy-statement-values))。 | 否 | 是 | 
| 您可以指定使用者可以開始存取您的內容的日期和時間。 | 否 | 是 (選用) | 
| 您可以指定使用者無法再存取您的內容的日期和時間。 | 是 | 是 | 
| 您可以指定可以存取您的內容的使用者的 IP 位址或 IP 位址範圍。 | 否 | 是 (選用) | 
| 該已簽章的 URL 包含該政策的 base64 編碼版本，這會導致較長的 URL。 | 否 | 是 | 

如需使用*標準*政策建立已簽署的 URL 的詳細資訊，請參閱 [使用標準政策建立已簽署 URL](private-content-creating-signed-url-canned-policy.md)。

如需使用*自訂*政策建立已簽署的 URL 的詳細資訊，請參閱 [使用自訂政策建立已簽署 URL](private-content-creating-signed-url-custom-policy.md)。

## 已簽署 URL 的工作方式
<a name="private-content-how-signed-urls-work"></a>

以下概述您如何為已簽署的 URL 設定 CloudFront 和 Amazon S3，以及當使用者使用已簽署的 URL 要求檔案時，CloudFront 如何回應。

1. 在您的 CloudFront 分佈中，指定一或多個信任的金鑰群組，其中包含 CloudFront 可用來驗證 URL 簽章的公有金鑰。您可以使用對應的私有金鑰來簽署 URL。

   CloudFront 支援具有 RSA 2048 和 ECDSA 256 金鑰簽章的已簽署 URL。

   如需詳細資訊，請參閱[指定可以建立已簽署 URL 和已簽署 Cookie 的簽署者](private-content-trusted-signers.md)。

1. 開發應用程式以判斷使用者是否應該有權存取您的內容，並為您所要限制存取的應用程式的檔案或某些部分建立的簽署 URL。如需詳細資訊，請參閱下列主題：
   + [使用標準政策建立已簽署 URL](private-content-creating-signed-url-canned-policy.md)
   + [使用自訂政策建立已簽署 URL](private-content-creating-signed-url-custom-policy.md)

1. 使用者請求檔案用於所要請求的簽章 URL。

1. 您的應用程式會驗證使用者是否有權存取檔案：他們已經登入，他們已經支付存取內容的費用，或者他們已經滿足其他一些存取要求。

1. 您的應用程式會建立和傳回已簽章的 URL 給使用者。

1. 已簽章的 URL 允許使用者下載或串流內容。

   這個步驟是自動的；使用者通常不需要執行任何額外操作來存取內容。例如，如果使用者在 Web 瀏覽器l中存取您的內容時，則應用程式會將已簽章的 URL 傳回到瀏覽器。瀏覽器立即使用已簽署的 URL 存取 CloudFront 邊緣快取中的檔案，無需使用者的任何干預。

1. CloudFront 使用公有金鑰來驗證簽章，並確認 URL 尚未遭到篡改。如果簽章無效，請求會遭到拒絕。

   如果簽章有效，CloudFront 將查看 URL 中的政策聲明 (或如果使用的是標準政策，則建構一個聲明) 以確認請求仍然有效。例如，如果您為 URL 指定了開始和結束日期和時間，CloudFront 會確認使用者在您希望允許存取的時間段內嘗試存取您的內容。

   如果請求符合政策聲明中的請求，CloudFront 會執行標準操作：決定檔案是否已經在邊緣上快取，如果需要，將請求轉傳到原始伺服器，並將該檔案傳回給使用者。

**注意**  
如果不帶正負號的 URL 包含查詢字串參數，請務必將這些參數包含在您已簽署 URL 部分中。如果在簽署已簽署 URL 之後，將查詢字串新增此 URL，則 URL 會傳回 HTTP 403 狀態。

## 決定已簽署 URL 的有效時間
<a name="private-content-overview-choosing-duration"></a>

您可以分配私有內容以僅在短時間內使用已簽章的有效 URL (可能只有區區幾分鐘)。有效期很短的簽章 URL 適合於為了特定目的而將內容即時分佈給使用者，例如按需要對客戶作電影租賃或音樂下載的分佈。如果已簽章的 URL 僅在短時間內有效，您可能會希望使用您開發的應用程式自動產生他們。當使用者開始下載檔案或開始播放媒體檔案時，CloudFront 會將 URL 中的到期時間與目前時間進行比較，以判斷 URL 是否仍然有效。

您還可以使用有效期較長的 (可能會持續數年) 已簽章的 URL 分配私有內容。有效期較長的已簽章的 URL 對於向已知使用者分佈私有內容非常有用，例如向投資者分佈業務計畫或向員工分佈培訓教材。您可以開發應用程式，為您產生這些長期簽署的 URL。

## CloudFront 何時檢查已簽署 URL 中的到期日期和時間
<a name="private-content-check-expiration"></a>

CloudFront 會在 HTTP 請求時，在已簽署 URL 中檢查過期日期和時間。如果用戶端在到期前一刻才開始下載大型檔案，則即使在下載期間過期了，下載也應該要完成。如果 TCP 連線中斷並且用戶端在到期時間過後嘗試重新啟動下載，則下載將失敗。

如果用戶端使用範圍 GET 以取得較小型的檔案，則到期時間過後發生的任何 GET 請求都將失敗。如需範圍 GET 的詳細資訊，請參閱 [CloudFront 如何處理物件的部分請求 (範圍 GET)](RangeGETs.md)。

## 範例程式碼和第三方工具
<a name="private-content-overview-sample-code"></a>

如需建立已簽署 URL 的雜湊和已簽署部分的範例程式碼，請參閱下列主題：
+ [使用 Perl 建立 URL 簽章](CreateURLPerl.md)
+ [使用 PHP 建立 URL 簽章](CreateURL_PHP.md)
+ [使用 C\$1 和 .NET 架構建立 URL 簽章](CreateSignatureInCSharp.md)
+ [使用 Java 建立 URL 簽章](CFPrivateDistJavaDevelopment.md)

# 使用標準政策建立已簽署 URL
<a name="private-content-creating-signed-url-canned-policy"></a>

若要使用標準政策建立已簽署 URL，請完成以下步驟。<a name="private-content-creating-signed-url-canned-policy-procedure"></a>

**使用標準政策建立簽章的 URL**

1. 如果您使用 .NET 或 Java 建立簽章的 URL，並且您還沒有將金鑰對的私有金鑰從預設的 .pem 格式重新格式化為與 .NET 或 Java 相容的格式，則現在執行此操作。如需詳細資訊，請參閱[重新格式化私有金鑰 (僅限 .NET 和 Java)](private-content-trusted-signers.md#private-content-reformatting-private-key)。

1. 串連下列值。您可以在此已簽署 URL 範例中使用格式。

   ```
   https://d111111abcdef8.cloudfront.net/image.jpg?color=red&size=medium&Expires=1767290400&Signature=nitfHRCrtziwO2HwPfWw~yYDhUF5EwRunQA-j19DzZrvDh6hQ73lDx~-ar3UocvvRQVw6EkC~GdpGQyyOSKQim-TxAnW7d8F5Kkai9HVx0FIu-5jcQb0UEmatEXAMPLE3ReXySpLSMj0yCd3ZAB4UcBCAqEijkytL6f3fVYNGQI6&Key-Pair-Id=K2JCJMDEHXQW5F&Hash-Algorithm=SHA256
   ```

   移除所有空格 (包括標籤和換行字元)。您可能必須在應用程式的程式碼的字串中包含逸出字元。所有值都有一個 `String` 類型。  
**1. *檔案的基本 URL***  
如果您未使用簽署的 URL，包括您自我的查詢字串參數 (如果有)，則基本 URL 是您用來存取檔案的 CloudFront URL。在上述範例中，基本 URL 為 `https://d111111abcdef8.cloudfront.net/image.jpg`。如需有關分佈的 URL 格式的詳細資訊，請參閱 [自訂 CloudFront 中檔案的 URL 格式](LinkFormat.md)。  
   + 下列 CloudFront URL 適用於分佈中的映像檔案 (使用 CloudFront 網域名稱)。請注意，`image.jpg` 位於 `images` 目錄中。在 URL 中檔案的路徑必須與 HTTP 伺服器或 Amazon S3 儲存貯體中的檔案的路徑相符。

     `https://d111111abcdef8.cloudfront.net/images/image.jpg`
   + 下列 CloudFront URL 包含查詢字串：

     `https://d111111abcdef8.cloudfront.net/images/image.jpg?size=large`
   + 下列 CloudFront URL 適用於分佈中的圖片檔案。同時使用替代網域名稱。第二個包含查詢字串：

     `https://www.example.com/images/image.jpg`

     `https://www.example.com/images/image.jpg?color=red`
   + 以下 CloudFront URL 用於分佈中使用備用網域名稱和 HTTPS 通訊協定的圖片檔案：

     `https://www.example.com/images/image.jpg`  
** 2. `?` **  
`?` 代表基本 URL 後面所接的查詢字串參數。即使您未指定任何查詢參數，也請包含 `?`。  
您可以依任何順序指定下列查詢參數。  
**3. *您的查詢字串參數 (如果有的話)*`&`**  
(選用) 您可以輸入自己的查詢字串參數。若要這樣做，請在每個參數之間新增 and (`&`)，例如 `color=red&size=medium`。您可以在 URL 內以任何順序指定查詢字串參數。  
您的查詢字串參數無法命名為 `Expires`、`Key-Pair-Id`、 `Signature`或 `Hash-Algorithm`。  
** 4. `Expires=`*Unix 時間格式的日期和時間 (以秒為單位) 和國際標準時間 (UTC)***  
您希望 URL 停止允許存取檔案的日期和時間。  
以 Unix 時間格式 (以秒為單位) 和國際標準時間 (UTC) 指定過期日期和時間。例如，2026 年 1 月 1 日上午 10:00 UTC 會以 Unix 時間格式轉換為 `1767290400`，如本主題開頭的範例所示。  
若要使用 epoch 時間，請為不晚於 `9223372036854775807` 的日期指定 64 位元整數 (2262 年 4 月 11 日星期五 23:47:16.854 UTC)。  
  
如需世界協調時間的詳細資訊，請參閱 [RFC 3339、網際網路上的日期和時間：時間戳記](https://tools.ietf.org/html/rfc3339)。  
** 5. `&Signature=`*政策陳述式的雜湊和簽署版本***  
JSON 政策聲明的雜湊、簽章和 base64-encoded 版本。如需詳細資訊，請參閱[為使用標準政策的已簽署 URL 建立簽章](#private-content-canned-policy-creating-signature)。  
** 6. `&Key-Pair-Id=`*CloudFront 公有金鑰的公有金鑰 ID，您用來產生簽章的對應私有金鑰***  
CloudFront 公有金鑰的 ID，例如 `K2JCJMDEHXQW5F`。公有金鑰 ID 會告訴 CloudFront 要使用哪個公有金鑰來驗證已簽署的 URL。CloudFront 將簽章中的資訊與政策聲明中的資訊進行比較，以驗證該 URL 尚未遭到篡改。  
此公有金鑰必須屬於分佈中信任的簽署者金鑰群組。如需詳細資訊，請參閱[指定可以建立已簽署 URL 和已簽署 Cookie 的簽署者](private-content-trusted-signers.md)。  
** 7. `&Hash-Algorithm=`*SHA1 或 SHA256***  
（選用） 用來建立簽章的雜湊演算法。支援的值為 `SHA1` 和 `SHA256`。如果您未指定此參數，CloudFront 會預設為 `SHA1`。

## 為使用標準政策的已簽署 URL 建立簽章
<a name="private-content-canned-policy-creating-signature"></a>

若要為使用標準政策的已簽署 URL 建立簽章，請完成下列程序。

**Topics**
+ [為使用標準政策的已簽署 URL 建立政策陳述式](#private-content-canned-policy-creating-policy-statement)
+ [為使用標準政策的已簽署 URL 建立簽章](#private-content-canned-policy-signing-policy-statement)

### 為使用標準政策的已簽署 URL 建立政策陳述式
<a name="private-content-canned-policy-creating-policy-statement"></a>

當您使用標準政策建立已簽章的 URL 時，`Signature` 參數是政策聲明的雜湊和簽章版本。對於使用標準政策的簽章的 URL，您不會將政策聲明包括在 URL 中，就像您使用自訂政策的已簽章的 URL 一樣。若要建立政策聲明，請執行下列程序。<a name="private-content-canned-policy-creating-policy-statement-procedure"></a>

**為使用標準政策的已簽章的 URL 建立政策聲明**

1. 建構政策聲明，使用下列 JSON 格式，並使用 UTF-8 字元編碼。完全按照規定包含所有標點符號和其他常值。如需有關 `Resource` 和 `DateLessThan` 參數的詳細資訊，請參閱 [您在使用標準政策的已簽署 URL 的政策陳述式中指定的值](#private-content-canned-policy-statement-values)。

   ```
   {
       "Statement": [
           {
               "Resource": "base URL or stream name",
               "Condition": {
                   "DateLessThan": {
                       "AWS:EpochTime": ending date and time in Unix time format and UTC
                   }
               }
           }
       ]
   }
   ```

1. 從政策陳述式中刪除所有空格 (包括標籤和新行字元)。您可能必須在應用程式的程式碼的字串中包含逸出字元。

#### 您在使用標準政策的已簽署 URL 的政策陳述式中指定的值
<a name="private-content-canned-policy-statement-values"></a>

當您為標準政策建立政策聲明時，您可以指定以下值。

**資源**  
您只能為 `Resource` 指定一個值。
包含查詢字串的基本 URL，如果有的話，但不包括 CloudFront `Expires`、`Key-Pair-Id`、 `Signature`和 `Hash-Algorithm` 參數，例如：  
`https://d111111abcdef8.cloudfront.net/images/horizon.jpg?size=large&license=yes`  
注意下列事項：  
+ **通訊協定** – 此值必須以 `http://` 或 `https://` 開頭。
+ **查詢字串參數** – 如果沒有查詢字串參數，請省略問號。
+ **替代網域名稱** – 如果在 URL 中指定了替代網域名稱 (CNAME)，則在引用網頁或應用程式中的檔案時，必須指定替代網域名稱。請勿為物件指定 Amazon S3 URL。

**DateLessThan**  
Unix 時間格式 (以秒為單位) 和國際標準時間 (UTC) 的 URL 的到期日期和時間。例如，2026 年 1 月 1 日上午 10:00 UTC 以 Unix 時間格式轉換為 1767290400。  
此值必須與已簽章的 URL 中的 `Expires` 查詢字串參數的值相符。不要將值括在引號中。  
如需詳細資訊，請參閱 [CloudFront 何時檢查已簽署 URL 中的到期日期和時間](private-content-signed-urls.md#private-content-check-expiration)。

#### 使用標準政策的已簽署 URL 範例政策陳述式
<a name="private-content-canned-policy-creating-policy-statement-example"></a>

當您在已簽署 URL 中使用以下範例政策陳述式時，使用者在到 UTC 2026 年 1 月 1 日上午 10:00 之前可以存取檔案 `https://d111111abcdef8.cloudfront.net/horizon.jpg`：

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/horizon.jpg?size=large&license=yes",
            "Condition": {
                "DateLessThan": {
                    "AWS:EpochTime": 1767290400
                }
            }
        }
    ]
}
```

### 為使用標準政策的已簽署 URL 建立簽章
<a name="private-content-canned-policy-signing-policy-statement"></a>

若要在已簽章的 URL 中建立 `Signature` 參數的值，請對您在 [為使用標準政策的已簽署 URL 建立政策陳述式](#private-content-canned-policy-creating-policy-statement) 中建立的政策聲明進行雜湊和簽署。

如需有關如何對政策聲明進行雜湊、簽章和編碼的詳細資訊和範例，請參閱：
+ [用於 Base64 編碼和加密的 Linux 命令和 OpenSSL](private-content-linux-openssl.md)
+ [為已簽署 URL 建立簽章的程式碼範例](PrivateCFSignatureCodeAndExamples.md)

**注意**  
連結的範例預設使用 SHA-1。若要改為使用 SHA-256，請在 OpenSSL 命令`sha256`中將 取代`sha1`為 ，並在簽章的 URL 中包含`Hash-Algorithm=SHA256`查詢參數。<a name="private-content-canned-policy-creating-signature-download-procedure"></a>

**選項 1：使用標準政策建立簽章**

1. 使用 SHA-1 或 SHA-256 雜湊函數和產生的 RSA 或 ECDSA 私有金鑰來雜湊並簽署您在程序 中建立的政策陳述式[為使用標準政策的已簽章的 URL 建立政策聲明](#private-content-canned-policy-creating-policy-statement-procedure)。使用不再包含空格之政策陳述式的版本。

   如果您使用 SHA-256，則必須在簽章的 URL `&Hash-Algorithm=SHA256`中包含 。

   對於雜湊函數所需的私有金鑰，使用其公有金鑰在活動的信任金鑰組中的私有金鑰進行分佈。
**注意**  
用於雜湊和簽名政策聲明的方法取決於您的程式設計語言和平台。如需程式碼範例，請參閱 [為已簽署 URL 建立簽章的程式碼範例](PrivateCFSignatureCodeAndExamples.md)。

1. 從雜湊和已簽署字串中移除所有空格 (包括索引標籤和新行字元)。

1. 使用 MIME base64 編碼的 Base64-encode 字串。如需詳細資訊，請參閱 *RFC 2045，MIME (多用途網際網路郵件延伸) 第一部分：網際網路訊息內文的格式*中的[第 6.8 節：Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8)。

1. 將 URL 查詢字串中無效的字元替換為有效的字元。下表列出無效和有效的字元。  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-canned-policy.html)

1. 在 `&Signature=` 之後，將結果值附加到已簽章的 URL，然後返回到[使用標準政策建立簽章的 URL](#private-content-creating-signed-url-canned-policy-procedure)以完成已簽章的 URL 的各個部分的連接。

# 使用自訂政策建立已簽署 URL
<a name="private-content-creating-signed-url-custom-policy"></a>

若要使用自訂政策建立簽章的 URL，請完成以下程序。<a name="private-content-creating-signed-url-custom-policy-procedure"></a>

**使用自訂政策建立簽章的 URL**

1. 如果您使用 .NET 或 Java 建立簽章的 URL，並且您還沒有將金鑰對的私有金鑰從預設的 .pem 格式重新格式化為與 .NET 或 Java 相容的格式，則現在執行此操作。如需詳細資訊，請參閱[重新格式化私有金鑰 (僅限 .NET 和 Java)](private-content-trusted-signers.md#private-content-reformatting-private-key)。

1. 串連下列值。您可以在此已簽署 URL 範例中使用格式。

   

   ```
   https://d111111abcdef8.cloudfront.net/image.jpg?color=red&size=medium&Policy=eyANCiAgICEXAMPLEW1lbnQiOiBbeyANCiAgICAgICJSZXNvdXJjZSI6Imh0dHA6Ly9kemJlc3FtN3VuMW0wLmNsb3VkZnJvbnQubmV0L2RlbW8ucGhwIiwgDQogICAgICAiQ29uZGl0aW9uIjp7IA0KICAgICAgICAgIklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIyMDcuMTcxLjE4MC4xMDEvMzIifSwNCiAgICAgICAgICJEYXRlR3JlYXRlclRoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTI5Njg2MDE3Nn0sDQogICAgICAgICAiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjEyOTY4NjAyMjZ9DQogICAgICB9IA0KICAgfV0gDQp9DQo&Signature=nitfHRCrtziwO2HwPfWw~yYDhUF5EwRunQA-j19DzZrvDh6hQ73lDx~-ar3UocvvRQVw6EkC~GdpGQyyOSKQim-TxAnW7d8F5Kkai9HVx0FIu-5jcQb0UEmatEXAMPLE3ReXySpLSMj0yCd3ZAB4UcBCAqEijkytL6f3fVYNGQI6&Key-Pair-Id=K2JCJMDEHXQW5F&Hash-Algorithm=SHA256
   ```

   移除所有空格 (包括標籤和換行字元)。您可能必須在應用程式的程式碼的字串中包含逸出字元。所有值都有一個 `String` 類型。  
**1. *檔案的基本 URL***  
如果您未使用簽署的 URL，包括您自我的查詢字串參數 (如果有)，則基本 URL 是您用來存取檔案的 CloudFront URL。在上述範例中，基本 URL 為 `https://d111111abcdef8.cloudfront.net/image.jpg`。如需有關分佈的 URL 格式的詳細資訊，請參閱 [自訂 CloudFront 中檔案的 URL 格式](LinkFormat.md)。  
以下範例說明您為分佈指定的值。  
   + 下列 CloudFront URL 適用於分佈中的映像檔案 (使用 CloudFront 網域名稱)。請注意，`image.jpg` 位於 `images` 目錄中。在 URL 中檔案的路徑必須與 HTTP 伺服器或 Amazon S3 儲存貯體中的檔案的路徑相符。

     `https://d111111abcdef8.cloudfront.net/images/image.jpg`
   + 下列 CloudFront URL 包含查詢字串：

     `https://d111111abcdef8.cloudfront.net/images/image.jpg?size=large`
   + 下列 CloudFront URL 適用於分佈中的圖片檔案。兩種都使用備用網域名稱，第二個包含查詢字串：

     `https://www.example.com/images/image.jpg`

     `https://www.example.com/images/image.jpg?color=red`
   + 以下 CloudFront URL 用於分佈中使用備用網域名稱和 HTTPS 通訊協定的圖片檔案：

     `https://www.example.com/images/image.jpg`  
**2. `?` **  
`?` 代表基本 URL 後面所接的查詢字串參數。即使您未指定任何查詢參數，也請包含 `?`。  
您可以依任何順序指定下列查詢參數。  
**3. *您的查詢字串參數 (如果有的話)*`&`**  
(選用) 您可以輸入自己的查詢字串參數。若要這樣做，請在每個參數之間新增 and (&)，例如 `color=red&size=medium`。您可以在 URL 內以任何順序指定查詢字串參數。  
您的查詢字串參數無法命名為 `Policy`、`Key-Pair-Id`、 `Signature`或 `Hash-Algorithm`。
如果加入自己的參數，請在每個參數的後面附加一個 `&`，包括最後一個參數。  
**4. `Policy=`*base64 編碼版本的政策陳述式***  
您的政策陳述式採用 JSON 格式，刪除了空格，然後使用 base64 編碼。如需詳細資訊，請參閱[為使用自訂政策的已簽署 URL 建立政策陳述式](#private-content-custom-policy-statement)。  
政策陳述式可控制簽署的 URL 授予使用者的存取權限。它包括檔案的 URL、到期日期和時間、URL 變成有效的選擇性日期和時間，以及允許存取檔案的選用 IP 位址或 IP 位址範圍。  
**5. `&Signature=`*政策陳述式的雜湊和簽署版本***  
JSON 政策聲明的雜湊、簽章和 base64-encoded 版本。如需詳細資訊，請參閱[為使用自訂準政策的已簽署 URL 建立簽章](#private-content-custom-policy-creating-signature)。  
**6. `&Key-Pair-Id=`*CloudFront 公有金鑰的公有金鑰 ID，您用來產生簽章的對應私有金鑰***  
CloudFront 公有金鑰的 ID，例如 `K2JCJMDEHXQW5F`。公有金鑰 ID 會告訴 CloudFront 要使用哪個公有金鑰來驗證已簽署的 URL。CloudFront 將簽章中的資訊與政策聲明中的資訊進行比較，以驗證該 URL 尚未遭到篡改。  
此公有金鑰必須屬於分佈中信任的簽署者金鑰群組。如需詳細資訊，請參閱[指定可以建立已簽署 URL 和已簽署 Cookie 的簽署者](private-content-trusted-signers.md)。  
**7. `&Hash-Algorithm=`*SHA1 或 SHA256***  
（選用） 用來建立簽章的雜湊演算法。支援的值為 `SHA1` 和 `SHA256`。如果您未指定此參數，CloudFront 會預設為 `SHA1`。

## 為使用自訂政策的已簽署 URL 建立政策陳述式
<a name="private-content-custom-policy-statement"></a>

請完成以下步驟，以為使用自訂政策之簽署的 URL 建立政策陳述式。

如需以各種方式控制對檔案存取的政策聲明範例，請參閱 [使用自訂政策的已簽署 URL 範例政策陳述式](#private-content-custom-policy-statement-examples)。<a name="private-content-custom-policy-creating-policy-procedure"></a>

**為使用自訂政策的已簽章的 URL 建立政策聲明**

1. 使用下列 JSON 格式建構政策聲明。使用您自己的值取代小於 (`<`) 和大於 (`>`) 符號及其中的描述。如需詳細資訊，請參閱[您在使用自訂政策的已簽署 URL 政策陳述式中指定的值](#private-content-custom-policy-statement-values)。

   ```
   {
       "Statement": [
           {
               "Resource": "<Optional but recommended: URL of the file>",
               "Condition": {
                   "DateLessThan": {
   	                "AWS:EpochTime": <Required: ending date and time in Unix time format and UTC>
                   },
                   "DateGreaterThan": {
   	                "AWS:EpochTime": <Optional: beginning date and time in Unix time format and UTC>
                   },
                   "IpAddress": {
   	                "AWS:SourceIp": "<Optional: IP address>"
                   }
               }
           }
       ]
   }
   ```

   注意下列事項：
   + 您只能在政策中包含一個陳述式。
   + 使用 UTF-8 字元編碼。
   + 完全按照規定包含所有標點符號和參數名稱。不接受參數名稱的縮寫。
   + `Condition` 部分的參數順序不重要。
   + 如需有關 `Resource`、`DateLessThan`、`DateGreaterThan` 和 `IpAddress` 值的詳細資訊，請參閱 [您在使用自訂政策的已簽署 URL 政策陳述式中指定的值](#private-content-custom-policy-statement-values)。

1. 從政策陳述式中刪除所有空格 (包括標籤和新行字元)。您可能必須在應用程式的程式碼的字串中包含逸出字元。

1. 使用 MIME base64 編碼 Base64-encode 政策聲明。如需詳細資訊，請參閱 *RFC 2045，MIME (多用途網際網路郵件延伸) 第一部分：網際網路訊息內文的格式*中的[第 6.8 節：Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8)。

1. 將 URL 查詢字串中無效的字元替換為有效的字元。下表列出無效和有效的字元。  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html)

1. 在 `Policy=` 之後，將結果值附加到已簽章的 URL。

1. 透過政策聲明進行雜湊、簽名和 base64-encoding 來建立用於簽章 URL 的簽章。如需詳細資訊，請參閱[為使用自訂準政策的已簽署 URL 建立簽章](#private-content-custom-policy-creating-signature)。

### 您在使用自訂政策的已簽署 URL 政策陳述式中指定的值
<a name="private-content-custom-policy-statement-values"></a>

當您為自訂政策建立政策聲明時，您可以指定以下值。

**資源**  
URL，包括任何查詢字串，但不包括 CloudFront `Policy`、`Key-Pair-Id`、 `Signature`和 `Hash-Algorithm` 參數。例如：  
`https://d111111abcdef8.cloudfront.net/images/horizon.jpg\?size=large&license=yes`  
您只能為 `Resource` 指定一個 URL 值。  
您可以省略政策中的 `Resource` 參數，但如此便代表任何擁有已簽署 URL 的人，都可以存取與您建立已簽署 URL 的金鑰對關聯的*任何*分佈中的*所有*檔案。
注意下列事項：  
+ **通訊協定** – 此值必須以 `http://`、`https://` 或 `*://` 開頭。
+ **查詢字串參數** – 如果 URL 具有查詢字串參數，請勿使用反斜線字元 (`\`) 來逸出開始查詢字串的問號字元 (`?`)。例如：

  `https://d111111abcdef8.cloudfront.net/images/horizon.jpg?size=large&license=yes`
+ **萬用字元** – 您可以在政策中的 URL 中使用萬用字元。支援下列萬用字元：
  + 星號 (`*`)，符合零或更多字元
  + 問號 (`?`)，剛好符合一個字元

  在 CloudFront 將政策中的 URL 與 HTTP 要求中的 URL 相符時，政策中的 URL 會分為四個區段－通訊協定、網域、路徑和查詢字串)，如下所示：

  `[protocol]://[domain]/[path]\?[query string]`

  當您在政策的 URL 中使用萬用字元時，萬用字元比對只會套用在包含萬用字元的區段邊界內。例如，在政策中考量此 URL：

  `https://www.example.com/hello*world`

  在此範例中，星號萬用字元 (`*`) 僅適用於路徑區段中，因此它符合 URL `https://www.example.com/helloworld` 和 `https://www.example.com/hello-world`，但與 URL `https://www.example.net/hello?world` 不相符。

  下列例外適用於萬用字元相符的區段邊界：
  + 路徑區段中的結尾星號表示查詢字串區段中的星號。例如，`http://example.com/hello*` 等同於 `http://example.com/hello*\?*`。
  + 網域區段域部分中的結尾星號表示路徑和查詢字串部分中都有星號。例如，`http://example.com*` 等同於 `http://example.com*/*\?*`。
  + 政策中的 URL 可以省略通訊協定區段，並在網域區段中以星號開頭。在這種情況下，通訊協定部分暗中設為星號。例如，策略 `*example.com` 中的 URL 等同於 `*://*example.com/`。
  + 星號本身 (`"Resource": "*"`) 符合任何 URL。

  例如，策略 `https://d111111abcdef8.cloudfront.net/*game_download.zip*` 中的值:符合下列所有 URL：
  + `https://d111111abcdef8.cloudfront.net/game_download.zip`
  + `https://d111111abcdef8.cloudfront.net/example_game_download.zip?license=yes`
  + `https://d111111abcdef8.cloudfront.net/test_game_download.zip?license=temp`
+ **替代網域名稱** – 如果在 URL 中指定了替代網域名稱 (CNAME)，則在引用網頁或應用程式中的檔案時，必須指定替代網域名稱。請勿在政策中為檔案指定 Amazon S3 URL。

**DateLessThan**  
Unix 時間格式 (以秒為單位) 和國際標準時間 (UTC) 的 URL 的到期日期和時間。在政策中，不要將值括在引號中。如需世界協調時間的詳細資訊，請參閱[網際網路上的日期和時間：時間戳記](https://tools.ietf.org/html/rfc3339)。  
例如，2023 年 1 月 31 日上午 10:00 UTC 以 Unix 時間格式轉換為 1675159200。  
這是 `Condition` 部分中唯一需要的參數。CloudFront 請求這個值，以防止使用者永久存取您的私有內容。  
如需詳細資訊，請參閱[CloudFront 何時檢查已簽署 URL 中的到期日期和時間](private-content-signed-urls.md#private-content-check-expiration)

**DateGreaterThan (選用)**  
Unix 時間格式 (以秒為單位) 和國際標準時間 (UTC) 的 URL 的選用日期和時間。不允許使用者在指定的日期和時間之前存取檔案。不要將值括在引號中。

**IpAddress (選用)**  
提出 HTTP 請求的用戶端 IP 位址。注意下列事項：  
+ 要允許任何 IP 位址存取該檔案，請省略 `IpAddress` 參數。
+ 您可以指定一個 IP 位址或一個 IP 位址範圍。如果用戶端的 IP 位址位於兩個不同的範圍之一，則無法設定政策以允許存取。
+ 若要允許從單一 IP 位址存取，您需要指定：

  `"`*IPv4 IP 位址*`/32"`
+ 必須以標準 IPv4 CIDR 格式指定 IP 位址範圍 (例如 `192.0.2.0/24`)。如需詳細資訊，請參閱[《無類別域間路由 (CIDR)：網際網路地址指派和彙總計劃》](https://tools.ietf.org/html/rfc4632)。
**重要**  
不支援 IPv6 格式的 IP 位址，例如 2001:0db8:85a3::8a2e:0370:7334。

  如果您使用的是包括 `IpAddress` 的自訂政策，請不要為分佈啟用 IPv6。如果您希望透過 IP 位址限制對某些內容的存取，並支援對其他內容的 IPv6 請求，則可以建立兩個分佈。如需詳細資訊，請參閱 [所有分佈設定參考](distribution-web-values-specify.md) 主題中的 [啟用 IPv6 (檢視器請求)](DownloadDistValuesGeneral.md#DownloadDistValuesEnableIPv6)。

## 使用自訂政策的已簽署 URL 範例政策陳述式
<a name="private-content-custom-policy-statement-examples"></a>

以下範例說明政策聲明說明了如何控制對特定檔案的存取、目錄中的所有檔案，或與金鑰對 ID 相關聯的所有檔案。此範例還會說明了如何控制來自個別 IP 位址或各種 IP 位址的存取，以及如何防止使用者在指定的日期和時間過期後使用簽章 URL。

如果複製並貼上這些範例中的任何一項，請刪除所有空格 (包括索引標籤和換行符號字元)、用您自我的值取代該值，並在大括弧 (`}`) 的後面加上換行字元。

如需詳細資訊，請參閱[您在使用自訂政策的已簽署 URL 政策陳述式中指定的值](#private-content-custom-policy-statement-values)。

**Topics**
+ [範例政策陳述式：從一個 IP 位址範圍存取一個檔案](#private-content-custom-policy-statement-example-one-object)
+ [範例政策陳述式：從一個 IP 位址範圍存取目錄中的所有檔案](#private-content-custom-policy-statement-example-all-objects)
+ [範例政策陳述式：從一個 IP 位址存取與金鑰對 ID 相關的所有檔案](#private-content-custom-policy-statement-example-one-ip)

### 範例政策陳述式：從一個 IP 位址範圍存取一個檔案
<a name="private-content-custom-policy-statement-example-one-object"></a>

以下範例自訂政策在已簽署的 URL 中指定使用者在到 UTC 2023 年 1 月 31 日上午 10:00 之前可以從 `192.0.2.0/24` 範圍內的 IP 位址存取檔案 `https://d111111abcdef8.cloudfront.net/game_download.zip`：

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/game_download.zip",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.0/24"
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1675159200
                }
            }
        }
    ]
}
```

### 範例政策陳述式：從一個 IP 位址範圍存取目錄中的所有檔案
<a name="private-content-custom-policy-statement-example-all-objects"></a>

以下範例自訂政策允許您為 `training` 目錄中的任何檔案建立簽章的 URL，如 `Resource` 參數中的 (`*`) 萬用字元所示。使用者在到 UTC 2023 年 1 月 31 日上午 10:00 之前可以從 `192.0.2.0/24` 範圍內的 IP 位址存取該檔案：

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/training/*",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.0/24"
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1675159200
                }
            }
        }
    ]
}
```

您使用此政策的每個已簽章的 URL 都包括一個識別特定的檔案的基本 URL，例如：

`https://d111111abcdef8.cloudfront.net/training/orientation.pdf`

### 範例政策陳述式：從一個 IP 位址存取與金鑰對 ID 相關的所有檔案
<a name="private-content-custom-policy-statement-example-one-ip"></a>

以下範例自訂政策允許您為與任何分佈關聯的任何檔案建立簽章的 URL，如 `Resource` 參數中的 (`*`) 萬用字元所示。已簽署的 URL 必須使用 `https://` 通訊協定，而不是 `http://`。使用者必須使用 IP 位址 `192.0.2.10/32`。(CIDR 表示法中的 `192.0.2.10/32` 值是指單個 IP 位址 `192.0.2.10`。) 這些檔案只能在 2023 年 1 月 31 日上午 10:00 UTC 至 2023 年 2 月 2 日上午 10:00 UTC 之間使用：

```
{
    "Statement": [
       {
            "Resource": "https://*",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.10/32"
                },
                "DateGreaterThan": {
                    "AWS:EpochTime": 1675159200
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1675332000
                }
            }
        }
    ]
}
```

您使用此政策的每個已簽署的 URL 都包括一個基本 URL，用於識別特定 CloudFront 分佈中的特定檔案，例如：

`https://d111111abcdef8.cloudfront.net/training/orientation.pdf`

該已簽署 URL 還包括金鑰對 ID，必須與在基本 URL 中指定的分佈 (d111111abcdef8.cloudfront.net) 中的可信金鑰群組相關聯。

## 為使用自訂準政策的已簽署 URL 建立簽章
<a name="private-content-custom-policy-creating-signature"></a>

使用自訂政策的已簽章的 URL 的簽章是政策聲明的雜湊、簽章和 base64-encoded 版本。若要建立自訂政策的簽章，請完成以下步驟。

如需有關如何對政策聲明進行雜湊、簽章和編碼的詳細資訊和範例，請參閱：
+ [用於 Base64 編碼和加密的 Linux 命令和 OpenSSL](private-content-linux-openssl.md)
+ [為已簽署 URL 建立簽章的程式碼範例](PrivateCFSignatureCodeAndExamples.md)

**注意**  
連結的範例預設使用 SHA-1。若要改為使用 SHA-256，請在 OpenSSL 命令`sha256`中將 取代`sha1`為 ，並在簽章的 URL 中包含`Hash-Algorithm=SHA256`查詢參數。<a name="private-content-custom-policy-creating-signature-download-procedure"></a>

**選項 1：使用自訂政策建立簽章**

1. 使用 SHA-1 或 SHA-256 雜湊函數和產生的 RSA 或 ECDSA 私有金鑰來雜湊並簽署您在程序 中建立的 JSON 政策陳述式[為使用自訂政策的已簽章的 URL 建立政策聲明](#private-content-custom-policy-creating-policy-procedure)。使用不再包含空格但尚未進行 base64 編碼的政策陳述式版本。

   如果您使用 SHA-256，則必須在簽章的 URL `&Hash-Algorithm=SHA256`中包含 。

   對於雜湊函數所需的私有金鑰，使用其公有金鑰在活動的信任金鑰組中的私有金鑰進行分佈。
**注意**  
用於雜湊和簽名政策聲明的方法取決於您的程式設計語言和平台。如需程式碼範例，請參閱 [為已簽署 URL 建立簽章的程式碼範例](PrivateCFSignatureCodeAndExamples.md)。

1. 從雜湊和已簽署字串中移除所有空格 (包括索引標籤和新行字元)。

1. 使用 MIME base64 編碼的 Base64-encode 字串。如需詳細資訊，請參閱 *RFC 2045，MIME (多用途網際網路郵件延伸) 第一部分：網際網路訊息內文的格式*中的[第 6.8 節：Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8)。

1. 將 URL 查詢字串中無效的字元替換為有效的字元。下表列出無效和有效的字元。  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html)

1. 在 `&Signature=` 之後，將結果值附加到已簽章的 URL，然後返回到[使用自訂政策建立簽章的 URL](#private-content-creating-signed-url-custom-policy-procedure)以完成已簽章的 URL 的各個部分的連接。

# 使用已簽署 Cookie
<a name="private-content-signed-cookies"></a>

當您不想變更目前 URL 或希望提供存取多個限制檔案 (例如，網站的訂閱者區域中的所有檔案) 時，CloudFront 簽署 Cookie 允許您控制那些可以存取您的內容的使用者。本主題說明使用已簽章的 Cookie 時的注意事項，並介紹如何使用標準和自訂政策設定已簽章的 Cookie。

**Topics**
+ [決定對已簽署 Cookie 使用標準或自訂政策](#private-content-choosing-canned-custom-cookies)
+ [已簽署 Cookie 的工作方式](#private-content-how-signed-cookies-work)
+ [防止濫用已簽署 Cookie](#private-content-signed-cookie-misuse)
+ [CloudFront 何時檢查已簽署 Cookie 中的到期日期和時間](#private-content-check-expiration-cookie)
+ [範例程式碼和第三方工具](#private-content-overview-sample-code-cookies)
+ [使用標準政策設定已簽署 Cookie](private-content-setting-signed-cookie-canned-policy.md)
+ [使用自訂政策設定已簽署 Cookie](private-content-setting-signed-cookie-custom-policy.md)
+ [使用 PHP 建立已簽署 Cookie](signed-cookies-PHP.md)

## 決定對已簽署 Cookie 使用標準或自訂政策
<a name="private-content-choosing-canned-custom-cookies"></a>

當您建立已簽章的 Cookie 時，您將編寫一個 JSON 格式的政策聲明來指定對已簽章的 Cookie 的限制，例如 Cookie 的有效時間。您可以使用標準政策或自訂政策。下表比較了標準和自訂政策：


****  

| 描述 | 標準政策 | 自訂政策 | 
| --- | --- | --- | 
| 您可以重複使用多個檔案的政策聲明。要重複使用政策聲明，您必須在 `Resource` 物件中使用萬用字元。如需詳細資訊，請參閱 [您在政策陳述式中為已簽章 Cookie 的自訂政策指定的值](private-content-setting-signed-cookie-custom-policy.md#private-content-custom-policy-statement-cookies-values))。 | 否 | 是 | 
| 您可以指定使用者可以開始存取您的內容的日期和時間 | 否 | 是 (選用) | 
| 您可以指定使用者無法再存取您的內容的日期和時間 | 是 | 是 | 
| 您可以指定可以存取您的內容的使用者的 IP 位址或 IP 位址範圍 | 否 | 是 (選用) | 

如需有關使用標準政策建立已簽章的 Cookie 的詳細資訊，請參閱 [使用標準政策設定已簽署 Cookie](private-content-setting-signed-cookie-canned-policy.md)。

如需有關使用自訂政策建立已簽章的 Cookie 的詳細資訊，請參閱 [使用自訂政策設定已簽署 Cookie](private-content-setting-signed-cookie-custom-policy.md)。

## 已簽署 Cookie 的工作方式
<a name="private-content-how-signed-cookies-work"></a>

以下概觀了如何為已簽署的 Cookie 設定 CloudFront，以及當使用者提交包含已簽署的 Cookie 的請求時，CloudFront 如何回應。

1. 在您的 CloudFront 分佈中，指定一或多個信任的金鑰群組，其中包含 CloudFront 可用來驗證 URL 簽章的公有金鑰。您可以使用對應的私有金鑰來簽署 URL。

   如需詳細資訊，請參閱 [指定可以建立已簽署 URL 和已簽署 Cookie 的簽署者](private-content-trusted-signers.md)。

1. 您開發應用程式，以判斷使用者是否應該存取您的內容，如果是，則向檢視器傳送三個 `Set-Cookie` 標頭。(每個 `Set-Cookie` 標頭只包含一個名稱值組，而 CloudFront 已簽署的 Cookie 需要三個名稱值組。) 在瀏覽者請求您的私有內容之前，您必須將 `Set-Cookie` 標頭傳送到檢視器。如果您在 Cookie 上設定了較短的到期時間，則可能還需要傳送三個 `Set-Cookie` 標頭以回應後續請求，以便使用者持續存取。

   一般而言，您的 CloudFront 分佈至少有兩個快取行為，一種不需要身分驗證，另一種需要驗證。網站安全部分的錯誤頁面包含重定向器或指向登入頁面的連結。

   如果您將分佈設定為根據 Cookie 的快取檔案，CloudFront 不會根據已簽署的 Cookie 中的屬性快取個別檔案。

1. 使用者登入您的網站，以及付費內容或滿足其他存取需求。

1. 您的應用程式傳回回應中的 `Set-Cookie` 標頭，並且檢視器會儲存名稱值組。

1. 使用者請求了檔案。

   使用者的瀏覽器或其他檢視器從步驟 4 取得名稱值組，並將它們新增至 `Cookie` 標頭中的請求中。這是已簽章的 Cookie。

1. CloudFront 使用公有金鑰來驗證已簽署的 Cookie 中的簽章，並確認該 Cookie 尚未遭到篡改。如果簽章無效，請求會遭到拒絕。

   如果 Cookie 中的簽章有效，CloudFront 將查看 Cookie 中的政策聲明 (或者如果使用的是標準政策，則建構一個聲明) 以確認請求仍然有效。例如，如果您為 Cookie 指定了開始和結束日期和時間，CloudFront 會確認使用者在您希望允許存取的時間段內嘗試存取您的內容。

   如果該請求符合政策聲明中的請求，則 CloudFront 將為您的內容提供服務，就像是不受限制的內容：它決定檔案是否已經在邊緣上快取，若需要，將請求轉傳到原始伺服器，並將該檔案傳回給使用者。

## 防止濫用已簽署 Cookie
<a name="private-content-signed-cookie-misuse"></a>

如果您在 `Domain` 標頭中指定 `Set-Cookie` 參數，請指定可能的最精確值，以降低具有相同根網域名稱之人員的存取可能性。例如，app.example.com 優於 example.com，尤其是當您無法控制 example.com 時。這有助於防止他人從 www.example.com 存取您的內容。

要協助避免發生這種類型的攻擊，請執行下列動作：
+ 排除 `Expires` 和 `Max-Age` 的屬性，以便 `Set-Cookie` 標頭建立工作階段 Cookie。工作階段 Cookie 會在使用者關閉瀏覽器時自動刪除，以降低有人未經授權存取您的內容的可能性。
+ 包含 `Secure` 屬性，以便檢視器在請求中包含該 Cookie 時，將對其進行加密。
+ 如果可能，請使用自訂政策，並包含檢視器的 IP 位址。
+ 在 `CloudFront-Expires` 屬性中，根據您希望使用者訪問您的內容的時間長度，指定最短的合理到期時間。

## CloudFront 何時檢查已簽署 Cookie 中的到期日期和時間
<a name="private-content-check-expiration-cookie"></a>

若要判斷已簽署的 Cookie 是否仍然有效，CloudFront 在 HTTP 請求時會檢查 Cookie 中的到期日期和時間。如果用戶端在到期前一刻才開始下載大型檔案，則即使在下載期間過期了，下載也應該要完成。如果 TCP 連線中斷並且用戶端在到期時間過後嘗試重新啟動下載，則下載將失敗。

如果用戶端使用範圍 GET 以取得較小型的檔案，則到期時間過後發生的任何 GET 請求都將失敗。如需範圍 GET 的詳細資訊，請參閱 [CloudFront 如何處理物件的部分請求 (範圍 GET)](RangeGETs.md)。

## 範例程式碼和第三方工具
<a name="private-content-overview-sample-code-cookies"></a>

私有內容的範本程式碼只說明如何為已簽章的 URL 建立簽章。但是，針對已簽章的 Cookie 建立簽章的程序非常類似，因此大部分範本程式碼仍然相關。如需詳細資訊，請參閱下列主題：
+ [使用 Perl 建立 URL 簽章](CreateURLPerl.md)
+ [使用 PHP 建立 URL 簽章](CreateURL_PHP.md)
+ [使用 C\$1 和 .NET 架構建立 URL 簽章](CreateSignatureInCSharp.md)
+ [使用 Java 建立 URL 簽章](CFPrivateDistJavaDevelopment.md)

# 使用標準政策設定已簽署 Cookie
<a name="private-content-setting-signed-cookie-canned-policy"></a>

若要使用標準政策設定已簽章的 Cookie，請完成以下步驟。若要建立簽章，請參閱 [為使用標準政策的已簽署 Cookie 建立簽章](#private-content-canned-policy-signature-cookies)。<a name="private-content-setting-signed-cookie-canned-policy-procedure"></a>

**使用標準政策設定已簽章的 Cookie**

1. 如果您使用 .NET 或 Java 建立已簽章的 Cookie，而且尚未將金鑰對的私有金鑰從預設的 .pem 格式重新格式化為與 .NET 或 Java 相容的格式，請現在執行此操作。如需詳細資訊，請參閱[重新格式化私有金鑰 (僅限 .NET 和 Java)](private-content-trusted-signers.md#private-content-reformatting-private-key)。

1. 將應用程式設定為傳送三個`Set-Cookie`標頭給核准的檢視器 （如果您想要指定雜湊演算法，則為四個）。您需要三個 `Set-Cookie` 標頭，因為每個 `Set-Cookie` 標頭只能包含一個名稱值組，而 CloudFront 已簽署的 Cookie 需要三個名稱值組。名稱值組是：`CloudFront-Expires`、`CloudFront-Signature` 和 `CloudFront-Key-Pair-Id`。您可以選擇包含第四個名稱值對 `CloudFront-Hash-Algorithm`，以指定用於簽章的雜湊演算法。在使用者對要控制存取的檔案發出第一次請求之前，這些值必須出現在檢視器。
**注意**  
一般而言，建議您排除 `Expires` 和 `Max-Age` 屬性。排除這些屬性會導致瀏覽器在使用者關閉瀏覽器時刪除 Cookie，從而降低有人未經授權存取您的內容的可能性。如需詳細資訊，請參閱[防止濫用已簽署 Cookie](private-content-signed-cookies.md#private-content-signed-cookie-misuse)。

   **Cookie 屬性的名稱區分大小寫**。

   只包含分行符號，以使屬性更易讀。

   ```
   Set-Cookie: 
   CloudFront-Expires=date and time in Unix time format (in seconds) and Coordinated Universal Time (UTC); 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   
   Set-Cookie: 
   CloudFront-Signature=hashed and signed version of the policy statement; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   
   Set-Cookie: 
   CloudFront-Key-Pair-Id=public key ID for the CloudFront public key whose corresponding private key you're using to generate the signature; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   
   Set-Cookie: 
   CloudFront-Hash-Algorithm=SHA1 or SHA256; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   ```  
**(選用) `Domain`**  
請求檔案的網域名稱。如果不指定 `Domain` 屬性，則預設值是 URL 中的網域名稱，並且它僅適用於指定的網域名稱，而不適用於子網域名稱。如果指定 `Domain` 屬性，它也適用於子網域名稱。網域名稱中的前導點 (例如 `Domain=.example.com`) 是可選的。此外，如果指定 `Domain` 屬性，則 URL 中的網域名稱和 `Domain` 屬性的值必須相符。  
您可以指定 CloudFront 指派給您的分佈的網域名稱，例如，d111111abcdef8.cloudfront.net，但不能為網域名稱指定 \$1.cloudfront.net。  
如果要在 URL 中使用備用網域名稱 (如 example.com)，則無論您是否指定了 `Domain` 屬性，都必須將備用網域名稱新增到分佈中。如需詳細資訊，請參閱 [所有分佈設定參考](distribution-web-values-specify.md) 主題中的 [備用網域名稱 (CNAME)](DownloadDistValuesGeneral.md#DownloadDistValuesCNAME)。  
**(選用) `Path`**  
請求檔案的路徑。如果未指定 `Path` 屬性，則預設值為 URL 中的路徑。  
**`Secure`**  
在檢視器傳送請求之前，需要對 Cookie 進行加密。我們建議您透過 HTTPS 連線發送 `Set-Cookie` 標頭，以確保 Cookie 屬性免受中間人攻擊。  
**`HttpOnly`**  
定義瀏覽器 (在支援的情況下) 如何與 Cookie 值互動。使用 `HttpOnly` 時，JavaScript 無法存取 Cookie 值。此預防措施有助於緩解跨網站指令碼 (XSS) 攻擊。如需詳細資訊，請參閱[使用 HTTP cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies)。  
**`CloudFront-Expires`**  
以 Unix 時間格式 (以秒為單位) 和國際標準時間 (UTC) 指定過期日期和時間。例如，2026 年 1 月 1 日上午 10:00 UTC 以 Unix 時間格式轉換為 1767290400。  
若要使用 epoch 時間，請為不晚於 `9223372036854775807` 的日期指定 64 位元整數 (2262 年 4 月 11 日星期五 23:47:16.854 UTC)。  
如需世界協調時間的詳細資訊，請參閱 *RFC 3339、網際網路上的日期和時間：時間戳記*，[https://tools.ietf.org/html/rfc3339](https://tools.ietf.org/html/rfc3339)。  
**`CloudFront-Signature`**  
JSON 政策聲明的雜湊、簽章和 base64-encoded 版本。如需詳細資訊，請參閱 [為使用標準政策的已簽署 Cookie 建立簽章](#private-content-canned-policy-signature-cookies)。  
**`CloudFront-Key-Pair-Id`**  
CloudFront 公有金鑰的 ID，例如 `K2JCJMDEHXQW5F`。公有金鑰 ID 會告訴 CloudFront 要使用哪個公有金鑰來驗證已簽署的 URL。CloudFront 將簽章中的資訊與政策聲明中的資訊進行比較，以驗證該 URL 尚未遭到篡改。  
此公有金鑰必須屬於分佈中信任的簽署者金鑰群組。如需詳細資訊，請參閱[指定可以建立已簽署 URL 和已簽署 Cookie 的簽署者](private-content-trusted-signers.md)。  
**`CloudFront-Hash-Algorithm`**  
（選用） 用來建立簽章的雜湊演算法。支援的值為 `SHA1` 和 `SHA256`。如果您未包含此 Cookie，CloudFront 會預設為 `SHA1`。

以下範例顯示當您使用與檔案的 URL 中的分佈關聯的網域名稱時，一個已簽章的 Cookie 的 `Set-Cookie` 標頭：

```
Set-Cookie: CloudFront-Expires=1426500000; Domain=d111111abcdef8.cloudfront.net; Path=/images/*; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=yXrSIgyQoeE4FBI4eMKF6ho~CA8_; Domain=d111111abcdef8.cloudfront.net; Path=/images/*; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=d111111abcdef8.cloudfront.net; Path=/images/*; Secure; HttpOnly
Set-Cookie: CloudFront-Hash-Algorithm=SHA256; Domain=d111111abcdef8.cloudfront.net; Path=/images/*; Secure; HttpOnly
```

以下範例顯示當您在檔案的 URL 中使用備用網域名稱 example.org 時，一個已簽章的 Cookie 的 `Set-Cookie` 標頭：

```
Set-Cookie: CloudFront-Expires=1426500000; Domain=example.org; Path=/images/*; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=yXrSIgyQoeE4FBI4eMKF6ho~CA8_; Domain=example.org; Path=/images/*; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=example.org; Path=/images/*; Secure; HttpOnly
Set-Cookie: CloudFront-Hash-Algorithm=SHA256; Domain=example.org; Path=/images/*; Secure; HttpOnly
```

如果要在 URL 中使用備用網域名稱 (如 example.com)，則無論您是否指定了 `Domain` 屬性，都必須將備用網域名稱新增到分佈中。如需詳細資訊，請參閱 [所有分佈設定參考](distribution-web-values-specify.md) 主題中的 [備用網域名稱 (CNAME)](DownloadDistValuesGeneral.md#DownloadDistValuesCNAME)。

## 為使用標準政策的已簽署 Cookie 建立簽章
<a name="private-content-canned-policy-signature-cookies"></a>

若要為使用標準政策的已簽署 Cookie 建立簽章，請完成下列程序。

**Topics**
+ [為使用標準政策的已簽署 Cookie 建立政策陳述式](#private-content-canned-policy-statement-cookies)
+ [簽署政策陳述式以為使用標準政策的已簽署 Cookie 建立簽章](#private-content-canned-policy-cookies-signing-policy-statement)

### 為使用標準政策的已簽署 Cookie 建立政策陳述式
<a name="private-content-canned-policy-statement-cookies"></a>

當您設定使用標準政策的簽章 Cookie 時，該 `CloudFront-Signature` 屬性是政策聲明的雜湊及已簽章的版本。對於使用標準政策的已簽章的 Cookie，您不會將政策聲明包括在 `Set-Cookie` 標頭中，就像使用自訂政策的已簽章的 Cookie 一樣。若要建立政策陳述式，請完成下列步驟。<a name="private-content-canned-policy-statement-cookies-procedure"></a>

**為使用標準政策的已簽章的 Cookie 建立政策聲明**

1. 建構政策聲明，使用下列 JSON 格式，並使用 UTF-8 字元編碼。完全按照規定包含所有標點符號和其他常值。如需有關 `Resource` 和 `DateLessThan` 參數的詳細資訊，請參閱 [您在政策陳述式中為已簽署 Cookie 標準政策所指定的值](#private-content-canned-policy-statement-cookies-values)。

   ```
   {
       "Statement": [
           {
               "Resource": "base URL or stream name",
               "Condition": {
                   "DateLessThan": {
                       "AWS:EpochTime": ending date and time in Unix time format and UTC
                   }
               }
           }
       ]
   }
   ```

1. 從政策陳述式中刪除所有空格 (包括標籤和新行字元)。您可能必須在應用程式的程式碼的字串中包含逸出字元。

#### 您在政策陳述式中為已簽署 Cookie 標準政策所指定的值
<a name="private-content-canned-policy-statement-cookies-values"></a>

當您為標準政策建立政策聲明時，您可以指定以下值：

**資源**  
包含查詢字串的基本 URL (如果有)，例如：  
`https://d111111abcdef8.cloudfront.net/images/horizon.jpg?size=large&license=yes`  
您只能為 `Resource` 指定一個值。  
注意下列事項：  
+ **通訊協定** – 此值必須以 `http://` 或 `https://` 開頭。
+ **查詢字串參數** – 如果沒有查詢字串參數，請省略問號。
+ **替代網域名稱** – 如果在 URL 中指定了替代網域名稱 (CNAME)，則在引用網頁或應用程式中的檔案時，必須指定替代網域名稱。請勿為檔案指定 Amazon S3 URL。

**DateLessThan**  
Unix 時間格式 (以秒為單位) 和國際標準時間 (UTC) 的 URL 的到期日期和時間。不要將值括在引號中。  
例如，2015 年 3 月 16 日上午 10:00 UTC 以 Unix 時間格式轉換為 1426500000。  
這個值必須符合 `CloudFront-Expires` 標頭中 `Set-Cookie` 屬性的值。不要將值括在引號中。  
如需詳細資訊，請參閱 [CloudFront 何時檢查已簽署 Cookie 中的到期日期和時間](private-content-signed-cookies.md#private-content-check-expiration-cookie)。

#### 標準政策的範例政策陳述式
<a name="private-content-canned-policy-cookies-sample-policy-statement"></a>

當您在已簽章的 Cookie 中使用以下範例政策聲明時，使用者在到 UTC 2015 年 3 月 16 日上午 10:00 之前可以存取檔案 `https://d111111abcdef8.cloudfront.net/horizon.jpg`：

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/horizon.jpg?size=large&license=yes",
            "Condition": {
                "DateLessThan": {
                    "AWS:EpochTime": 1426500000
                }
            }
        }
    ]
}
```

### 簽署政策陳述式以為使用標準政策的已簽署 Cookie 建立簽章
<a name="private-content-canned-policy-cookies-signing-policy-statement"></a>

要為 `CloudFront-Signature` 標頭中的 `Set-Cookie` 屬性建立值，請對您在 [為使用標準政策的已簽章的 Cookie 建立政策聲明](#private-content-canned-policy-statement-cookies-procedure) 中建立的政策聲明進行雜湊和簽署。

如需有關如何對政策聲明進行雜湊、簽章和編碼的詳細資訊和範例，請參閱以下主題：
+ [用於 Base64 編碼和加密的 Linux 命令和 OpenSSL](private-content-linux-openssl.md)
+ [為已簽署 URL 建立簽章的程式碼範例](PrivateCFSignatureCodeAndExamples.md)

**注意**  
連結的範例預設使用 SHA-1。若要改為使用 SHA-256，請在 OpenSSL 命令`sha256`中`sha1`將 取代為 ，並包含值為 的 `CloudFront-Hash-Algorithm` Cookie`SHA256`。<a name="private-content-canned-policy-cookie-creating-signature-procedure"></a>

**使用標準政策為已簽章的 Cookie 建立簽章**

1. 使用 SHA-1 或 SHA-256 雜湊函數和 RSA 來雜湊和簽署您在程序 中建立的政策陳述式[為使用標準政策的已簽章的 Cookie 建立政策聲明](#private-content-canned-policy-statement-cookies-procedure)。使用不再包含空格之政策陳述式的版本。

   如果您使用 SHA-256，則必須包含值為 的 `CloudFront-Hash-Algorithm` Cookie`SHA256`。

   對於雜湊函數所需的私有金鑰，使用其公有金鑰在活動的信任金鑰組中的私有金鑰進行分佈。
**注意**  
用於雜湊和簽名政策聲明的方法取決於您的程式設計語言和平台。如需程式碼範例，請參閱 [為已簽署 URL 建立簽章的程式碼範例](PrivateCFSignatureCodeAndExamples.md)。

1. 從雜湊和已簽署字串中移除所有空格 (包括索引標籤和新行字元)。

1. 使用 MIME base64 編碼的 Base64-encode 字串。如需詳細資訊，請參閱 *RFC 2045，MIME (多用途網際網路郵件延伸) 第一部分：網際網路訊息內文的格式*中的[第 6.8 節：Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8)。

1. 將 URL 查詢字串中無效的字元替換為有效的字元。下表列出無效和有效的字元。  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-canned-policy.html)

1. 將結果值包含在 `Set-Cookie` 名稱值組的 `CloudFront-Signature` 標頭中。然後返回到 [使用標準政策設定已簽章的 Cookie](#private-content-setting-signed-cookie-canned-policy-procedure) 為 `Set-Cookie` 新增 `CloudFront-Key-Pair-Id` 標頭。

# 使用自訂政策設定已簽署 Cookie
<a name="private-content-setting-signed-cookie-custom-policy"></a>

若要設定使用標準政策的已簽署 Cookie，請完成以下步驟。<a name="private-content-setting-signed-cookie-custom-policy-procedure"></a>

**使用自訂政策設定已簽章的 Cookie**

1. 如果您使用 .NET 或 Java 建立簽章的 URL，並且您還沒有將金鑰對的私有金鑰從預設的 .pem 格式重新格式化為與 .NET 或 Java 相容的格式，則現在執行此操作。如需詳細資訊，請參閱[重新格式化私有金鑰 (僅限 .NET 和 Java)](private-content-trusted-signers.md#private-content-reformatting-private-key)。

1. 將應用程式設定為傳送三個`Set-Cookie`標頭給核准的檢視器 （如果您想要指定雜湊演算法，則為四個）。您需要三個 `Set-Cookie` 標頭，因為每個 `Set-Cookie` 標頭只能包含一個名稱值組，而 CloudFront 已簽署的 Cookie 需要三個名稱值組。名稱值組是：`CloudFront-Policy`、`CloudFront-Signature` 和 `CloudFront-Key-Pair-Id`。您可以選擇包含第四個名稱值對 `CloudFront-Hash-Algorithm`，以指定用於簽章的雜湊演算法。在使用者對要控制存取的檔案發出第一次請求之前，這些值必須出現在檢視器。
**注意**  
一般而言，建議您排除 `Expires` 和 `Max-Age` 屬性。這會導致瀏覽器在使用者關閉瀏覽器時刪除 Cookie，從而降低有人未經授權存取您的內容的可能性。如需詳細資訊，請參閱 [防止濫用已簽署 Cookie](private-content-signed-cookies.md#private-content-signed-cookie-misuse)。

   **Cookie 屬性的名稱區分大小寫**。

   只包含分行符號，以使屬性更易讀。

   ```
   Set-Cookie: 
   CloudFront-Policy=base64 encoded version of the policy statement; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   
   
   Set-Cookie: 
   CloudFront-Signature=hashed and signed version of the policy statement; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   
   Set-Cookie: 
   CloudFront-Key-Pair-Id=public key ID for the CloudFront public key whose corresponding private key you're using to generate the signature; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   
   Set-Cookie: 
   CloudFront-Hash-Algorithm=SHA1 or SHA256; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   ```  
**(選用) `Domain`**  
請求檔案的網域名稱。如果不指定 `Domain` 屬性，則預設值是 URL 中的網域名稱，並且它僅適用於指定的網域名稱，而不適用於子網域名稱。如果指定 `Domain` 屬性，它也適用於子網域名稱。網域名稱中的前導點 (例如 `Domain=.example.com`) 是可選的。此外，如果指定 `Domain` 屬性，則 URL 中的網域名稱和 `Domain` 屬性的值必須相符。  
您可以指定 CloudFront 指派給您的分佈的網域名稱，例如，d111111abcdef8.cloudfront.net，但不能為網域名稱指定 \$1.cloudfront.net。  
如果要在 URL 中使用備用網域名稱 (如 example.com)，則無論您是否指定了 `Domain` 屬性，都必須將備用網域名稱新增到分佈中。如需詳細資訊，請參閱 [所有分佈設定參考](distribution-web-values-specify.md) 主題中的 [備用網域名稱 (CNAME)](DownloadDistValuesGeneral.md#DownloadDistValuesCNAME)。  
**(選用) `Path`**  
請求檔案的路徑。如果未指定 `Path` 屬性，則預設值為 URL 中的路徑。  
**`Secure`**  
在檢視器傳送請求之前，需要對 Cookie 進行加密。我們建議您透過 HTTPS 連線發送 `Set-Cookie` 標頭，以確保 Cookie 屬性免受中間人攻擊。  
**`HttpOnly`**  
要求檢視器僅在 HTTP 或 HTTPS 請求中傳送 Cookie。  
**`CloudFront-Policy`**  
您的政策陳述式採用 JSON 格式，刪除了空格，然後使用 base64 編碼。如需詳細資訊，請參閱[為使用自訂政策的已簽署 Cookie 建立簽章](#private-content-custom-policy-signature-cookies)。  
政策陳述式可控制已簽署 Cookie 授予使用者的存取權限。它包括使用者可以存取的檔案、到期日期和時間、URL 變成有效的選擇性日期和時間，以及允許存取檔案的選用 IP 位址或 IP 位址範圍。  
**`CloudFront-Signature`**  
JSON 政策聲明的雜湊、簽章和 base64-encoded 版本。如需詳細資訊，請參閱 [為使用自訂政策的已簽署 Cookie 建立簽章](#private-content-custom-policy-signature-cookies)。  
**`CloudFront-Key-Pair-Id`**  
CloudFront 公有金鑰的 ID，例如 `K2JCJMDEHXQW5F`。公有金鑰 ID 會告訴 CloudFront 要使用哪個公有金鑰來驗證已簽署的 URL。CloudFront 將簽章中的資訊與政策聲明中的資訊進行比較，以驗證該 URL 尚未遭到篡改。  
此公有金鑰必須屬於分佈中信任的簽署者金鑰群組。如需詳細資訊，請參閱[指定可以建立已簽署 URL 和已簽署 Cookie 的簽署者](private-content-trusted-signers.md)。  
**`CloudFront-Hash-Algorithm`**  
（選用） 用來建立簽章的雜湊演算法。支援的值為 `SHA1` 和 `SHA256`。如果您未包含此 Cookie，CloudFront 會預設為 `SHA1`。

## 自訂政策的 `Set-Cookie` 標頭範例
<a name="example-set-cookie-headers-custom-policy"></a>

請參閱下列 `Set-Cookie` 標頭對的範例。

如果要在 URL 中使用備用網域名稱 (如 example.org)，則無論您是否指定了 `Domain` 屬性，都必須將備用網域名稱新增到分佈中。如需詳細資訊，請參閱 [所有分佈設定參考](distribution-web-values-specify.md) 主題中的 [備用網域名稱 (CNAME)](DownloadDistValuesGeneral.md#DownloadDistValuesCNAME)。

**Example 範例 1**  
當您使用與檔案的 URL 中的分佈關聯的網域名稱時，可以使用一個已簽署 Cookie 的 `Set-Cookie` 標頭。  

```
Set-Cookie: CloudFront-Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=dtKhpJ3aUYxqDIwepczPiDb9NXQ_; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Hash-Algorithm=SHA256; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
```

**Example 範例 2**  
當您在檔案的 URL 中使用備用網域名稱 (example.org) 時，可以使用一個已簽署 Cookie 的 `Set-Cookie` 標頭。  

```
Set-Cookie: CloudFront-Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__; Domain=example.org; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=dtKhpJ3aUYxqDIwepczPiDb9NXQ_; Domain=example.org; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=example.org; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Hash-Algorithm=SHA256; Domain=example.org; Path=/; Secure; HttpOnly
```

**Example 範例 3**  
當您使用與檔案的 URL 中的分佈關聯的網域名稱時，可以使用一個已簽署請求的 `Set-Cookie` 標頭對。  

```
Set-Cookie: CloudFront-Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=dtKhpJ3aUYxqDIwepczPiDb9NXQ_; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=dd111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Hash-Algorithm=SHA256; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
```

**Example 範例 4**  
當您使用與檔案的 URL 中的分佈關聯的替代網域名稱 (example.org) 時，可以使用一個已簽署請求的 `Set-Cookie` 標頭對。  

```
Set-Cookie: CloudFront-Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__; Domain=example.org; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=dtKhpJ3aUYxqDIwepczPiDb9NXQ_; Domain=example.org; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=example.org; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Hash-Algorithm=SHA256; Domain=example.org; Path=/; Secure; HttpOnly
```

## 為使用自訂政策的已簽署 Cookie 建立政策陳述式
<a name="private-content-custom-policy-statement-cookies"></a>

若要為自訂政策建立政策陳述式，請執行以下步驟。如需以各種方式控制對檔案存取的幾個政策聲明範例，請參閱 [使用自訂政策的已簽署 Cookie 範例政策陳述式](#private-content-custom-policy-statement-signed-cookies-examples)。<a name="private-content-custom-policy-statement-cookies-procedure"></a>

**為使用自訂政策的簽章的 Cookie 建立政策聲明**

1. 使用下列 JSON 格式建構政策聲明。

   ```
   {
       "Statement": [
           {
               "Resource": "URL of the file",
               "Condition": {
                   "DateLessThan": {
                       "AWS:EpochTime":required ending date and time in Unix time format and UTC
                   },
                   "DateGreaterThan": {
                       "AWS:EpochTime":optional beginning date and time in Unix time format and UTC
                   },
                   "IpAddress": {
                       "AWS:SourceIp": "optional IP address"
                   }
               }
           }
       ]
   }
   ```

   注意下列事項：
   + 您只能包含一個聲明。
   + 使用 UTF-8 字元編碼。
   + 完全按照規定包含所有標點符號和參數名稱。不接受參數名稱的縮寫。
   + `Condition` 部分的參數順序不重要。
   + 如需有關 `Resource`、`DateLessThan`、`DateGreaterThan` 和 `IpAddress` 值的詳細資訊，請參閱 [您在政策陳述式中為已簽章 Cookie 的自訂政策指定的值](#private-content-custom-policy-statement-cookies-values)。

1. 從政策陳述式中刪除所有空格 (包括標籤和新行字元)。您可能必須在應用程式的程式碼的字串中包含逸出字元。

1. 使用 MIME base64 編碼 Base64-encode 政策聲明。如需詳細資訊，請參閱 *RFC 2045，MIME (多用途網際網路郵件延伸) 第一部分：網際網路訊息內文的格式*中的[第 6.8 節：Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8)。

1. 將 URL 查詢字串中無效的字元替換為有效的字元。下表列出無效和有效的字元。  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-custom-policy.html)

1. 將結果值包含在您的 `Set-Cookie` 標頭後的 `CloudFront-Policy=`。

1. 透過進行雜湊、簽章和 base64 編碼政策聲明來為 `Set-Cookie` 建立`CloudFront-Signature` 標頭的簽章。如需詳細資訊，請參閱 [為使用自訂政策的已簽署 Cookie 建立簽章](#private-content-custom-policy-signature-cookies)。

### 您在政策陳述式中為已簽章 Cookie 的自訂政策指定的值
<a name="private-content-custom-policy-statement-cookies-values"></a>

當您為自訂政策建立政策聲明時，您可以指定以下值。

**資源**  
包含查詢字串的基本 URL (如果有)：  
`https://d111111abcdef8.cloudfront.net/images/horizon.jpg?size=large&license=yes`  
如果省略 `Resource` 參數，則使用者可以存取與用於建立已簽章的 URL 的金鑰對相關聯的任何分佈的所有檔案。
您只能為 `Resource` 指定一個值。  
注意下列事項：  
+ **通訊協定** – 此值必須以 `http://` 或 `https://` 開頭。
+ **查詢字串參數** – 如果沒有查詢字串參數，請省略問號。
+ **萬用字元** – 可以使用比對零或多個字元 (\$1) 的萬用字元，或比對字串中任意位置單一字元 (?) 的萬用字元。例如，值為：

  `https://d111111abcdef8.cloudfront.net/*game_download.zip*`

  將包括 (例如) 下列檔案：
  + `https://d111111abcdef8.cloudfront.net/game_download.zip`
  + `https://d111111abcdef8.cloudfront.net/example_game_download.zip?license=yes`
  + `https://d111111abcdef8.cloudfront.net/test_game_download.zip?license=temp`
+ **替代網域名稱** – 如果在 URL 中指定了替代網域名稱 (CNAME)，則在引用網頁或應用程式中的檔案時，必須指定替代網域名稱。請勿為檔案指定 Amazon S3 URL。

**DateLessThan**  
Unix 時間格式 (以秒為單位) 和國際標準時間 (UTC) 的 URL 的到期日期和時間。不要將值括在引號中。  
例如，2015 年 3 月 16 日上午 10:00 UTC 以 Unix 時間格式轉換為 1426500000。  
如需詳細資訊，請參閱 [CloudFront 何時檢查已簽署 Cookie 中的到期日期和時間](private-content-signed-cookies.md#private-content-check-expiration-cookie)。

**DateGreaterThan (選用)**  
Unix 時間格式 (以秒為單位) 和國際標準時間 (UTC) 的 URL 的選用日期和時間。不允許使用者在指定的日期和時間之前存取檔案。不要將值括在引號中。

**IpAddress (選用)**  
提出 GET 請求的用戶端 IP 位址。注意下列事項：  
+ 要允許任何 IP 位址存取該檔案，請省略 `IpAddress` 參數。
+ 您可以指定一個 IP 位址或一個 IP 位址範圍。例如，如果用戶端的 IP 位址位於兩個不同的範圍之一，則無法設定政策以允許存取。
+ 若要允許從單一 IP 位址存取，您需要指定：

  `"`*IPv4 IP 位址*`/32"`
+ 必須以標準 IPv4 CIDR 格式指定 IP 位址範圍 (例如 `192.0.2.0/24`)。如需詳細資訊，請前往 *RFC 4632，無類別網域間路由選擇 (CIDR)：網際網路地址指派和彙總計劃*，[https://tools.ietf.org/html/rfc4632](https://tools.ietf.org/html/rfc4632)。
**重要**  
不支援 IPv6 格式的 IP 位址，例如 2001:0db8:85a3::8a2e:0370:7334。

  如果您使用的是包括 `IpAddress` 的自訂政策，請不要為分佈啟用 IPv6。如果您希望透過 IP 位址限制對某些內容的存取，並支援對其他內容的 IPv6 請求，則可以建立兩個分佈。如需詳細資訊，請參閱 [所有分佈設定參考](distribution-web-values-specify.md) 主題中的 [啟用 IPv6 (檢視器請求)](DownloadDistValuesGeneral.md#DownloadDistValuesEnableIPv6)。

## 使用自訂政策的已簽署 Cookie 範例政策陳述式
<a name="private-content-custom-policy-statement-signed-cookies-examples"></a>

以下範例說明政策聲明說明了如何控制對特定檔案的存取、目錄中的所有檔案，或與金鑰對 ID 相關聯的所有檔案。此範例還會說明如何控制來自個別的 IP 位址或各種 IP 位址的存取，以及如何防止使用者在指定的日期和時間之後使用已簽章的 Cookie。

如果複製並貼上這些範例中的任何一項，請刪除所有空格 (包括索引標籤和換行符號字元)、用您自我的值取代該值，並在大括弧 ( \$1 ) 的後面加上換行字元。

如需詳細資訊，請參閱[您在政策陳述式中為已簽章 Cookie 的自訂政策指定的值](#private-content-custom-policy-statement-cookies-values)。

**Topics**
+ [範例政策陳述式：從一個 IP 位址範圍存取一個檔案](#private-content-custom-policy-statement-signed-cookies-example-one-object)
+ [範例政策陳述式：從一個 IP 位址範圍存取目錄中的所有檔案](#private-content-custom-policy-statement-signed-cookies-example-all-objects)
+ [範例政策陳述式：從一個 IP 位址存取與金鑰對 ID 相關的所有檔案](#private-content-custom-policy-statement-signed-cookies-example-one-ip)

### 範例政策陳述式：從一個 IP 位址範圍存取一個檔案
<a name="private-content-custom-policy-statement-signed-cookies-example-one-object"></a>

以下範例自訂政策在已簽署的 Cookie 中，其指定使用者在 2023 年 1 月 1 日上午 10:00 (UTC) 之前，可以從 `192.0.2.0/24` 範圍內的 IP 位址存取檔案 `https://d111111abcdef8.cloudfront.net/game_download.zip`：

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/game_download.zip",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.0/24"
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1767290400
                }
            }
        }
    ]
}
```

### 範例政策陳述式：從一個 IP 位址範圍存取目錄中的所有檔案
<a name="private-content-custom-policy-statement-signed-cookies-example-all-objects"></a>

以下範例自訂政策允許您為 `training` 目錄中的任何檔案建立已簽章的 Cookie，如 `Resource` 參數中的 \$1 萬用字元所示。使用者在到 UTC 2013 年 1 月 1 日上午 10:00 之前可以從 `192.0.2.0/24` 範圍內的 IP 位址存取該檔案：

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/training/*",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.0/24"
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1767290400
                }
            }
        }
    ]
}
```

您使用此政策的每個已簽章的 Cookie 都包括一個識別特定的檔案的基本 URL，例如：

`https://d111111abcdef8.cloudfront.net/training/orientation.pdf`

### 範例政策陳述式：從一個 IP 位址存取與金鑰對 ID 相關的所有檔案
<a name="private-content-custom-policy-statement-signed-cookies-example-one-ip"></a>

以下範例自訂政策允許您為與任何分佈關聯的任何檔案設定已簽章的 Cookie，如 `Resource` 參數中的 \$1 萬用字元所示。使用者必須使用 IP 位址 `192.0.2.10/32`。(CIDR 表示法中的 `192.0.2.10/32` 值是指單個 IP 位址 `192.0.2.10`。) 這些檔案只能在 2013 年 1 月 1 日上午 10:00 UTC 至 2013 年 1 月 2 日上午 10:00 UTC 之間可用：

```
{
    "Statement": [
        {
            "Resource": "https://*",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.10/32"
                },
                "DateGreaterThan": {
                    "AWS:EpochTime": 1767290400
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1767376800
                }
            }
        }
    ]
}
```

您使用此政策的每個已簽署的 Cookie 都包括一個基本 URL，用於識別特定 CloudFront 分佈中的特定檔案，例如：

`https://d111111abcdef8.cloudfront.net/training/orientation.pdf`

該已簽署 Cookie 還包括金鑰對 ID，必須與在基本 URL 中指定的分佈 (d111111abcdef8.cloudfront.net) 內信任的簽署者相關聯。

## 為使用自訂政策的已簽署 Cookie 建立簽章
<a name="private-content-custom-policy-signature-cookies"></a>

使用自訂政策的已簽章的 Cookie 的簽章是政策聲明的雜湊、簽章和 base64-encoded 版本。

如需有關如何對政策聲明進行雜湊、簽章和編碼的詳細資訊和範例，請參閱：
+ [用於 Base64 編碼和加密的 Linux 命令和 OpenSSL](private-content-linux-openssl.md)
+ [為已簽署 URL 建立簽章的程式碼範例](PrivateCFSignatureCodeAndExamples.md)

**注意**  
連結的範例預設使用 SHA-1。若要改為使用 SHA-256，請在 OpenSSL 命令`sha256`中`sha1`將 取代為 ，並包含值為 的 `CloudFront-Hash-Algorithm` Cookie`SHA256`。<a name="private-content-custom-policy-signature-cookies-procedure"></a>

**使用自訂政策為已簽章的 Cookie 建立簽章**

1. 使用 SHA-1 或 SHA-256 雜湊函數和 RSA 來雜湊和簽署您在程序 中建立的 JSON 政策陳述式[為使用自訂政策的已簽章的 URL 建立政策聲明](private-content-creating-signed-url-custom-policy.md#private-content-custom-policy-creating-policy-procedure)。使用不再包含空格但尚未進行 base64 編碼的政策陳述式版本。

   如果您使用 SHA-256，則必須包含值為 的 `CloudFront-Hash-Algorithm` Cookie`SHA256`。

   對於雜湊函數所需的私有金鑰，使用其公有金鑰在活動的信任金鑰組中的私有金鑰進行分佈。
**注意**  
用於雜湊和簽名政策聲明的方法取決於您的程式設計語言和平台。如需程式碼範例，請參閱 [為已簽署 URL 建立簽章的程式碼範例](PrivateCFSignatureCodeAndExamples.md)。

1. 從雜湊和已簽署字串中移除所有空格 (包括索引標籤和新行字元)。

1. 使用 MIME base64 編碼的 Base64-encode 字串。如需詳細資訊，請參閱 *RFC 2045，MIME (多用途網際網路郵件延伸) 第一部分：網際網路訊息內文的格式*中的[第 6.8 節：Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8)。

1. 將 URL 查詢字串中無效的字元替換為有效的字元。下表列出無效和有效的字元。  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-custom-policy.html)

1. 將結果值包含在 `Set-Cookie` 名稱值組的 `CloudFront-Signature=` 標頭中，並返回到 [使用自訂政策設定已簽章的 Cookie](#private-content-setting-signed-cookie-custom-policy-procedure) 為 `Set-Cookie` 新增 `CloudFront-Key-Pair-Id` 標頭。

# 使用 PHP 建立已簽署 Cookie
<a name="signed-cookies-PHP"></a>

下列程式碼範例類似於 [使用 PHP 建立 URL 簽章](CreateURL_PHP.md) 中建立影片連結的範例。不過，此範例不會在程式碼中簽署 URL，而是使用 `create_signed_cookies()` 函數簽署 Cookie。用戶端播放器使用 Cookie 對 CloudFront 分佈的每個請求進行身分驗證。

此方法有助於串流內容，例如 HTTP Live Streaming (HLS) 或透過 HTTP 的動態自適應串流 (DASH)，其中用戶端需要提出多個請求來擷取資訊清單、區段和相關播放資產。透過使用簽署的 Cookie，用戶端可以驗證每個請求，而不需要為每個區段產生新的已簽署 URL。

**注意**  
建立 URL 簽章只是私有內容提供服務的程序的一部分，以使用已簽署 Cookie。如需詳細資訊，請參閱[使用已簽署 Cookie](private-content-signed-cookies.md)。



**Topics**
+ [建立 RSA SHA-1 或 SHA-256 簽章](#create-rsa-sha-1signature-cookies)
+ [建立已簽署 Cookie](#create-the-signed-cookie)
+ [完整程式碼](#full-code-signed-cookies)

下列各節將程式碼範例細分為個別部分。您可以在下面找到完整的[程式碼範例](#full-code-signed-cookies)。

## 建立 RSA SHA-1 或 SHA-256 簽章
<a name="create-rsa-sha-1signature-cookies"></a>

此程式碼會執行下列操作：

1. 函數會使用 SHA-1 雜`rsa_sha1_sign`湊並簽署政策陳述式。若要改用 SHA-256，請使用如下所示的 rsa\$1sha256\$1sign 函數。所需的引數為政策陳述式，以及與您分佈之信任金鑰群組中公有金鑰對應的私有金鑰。

1. 接著，該 `url_safe_base64_encode` 函數會建立已簽章的 URL 安全版本。

   ```
   function rsa_sha1_sign($policy, $private_key_filename) {
       $signature = "";
       $fp = fopen($private_key_filename, "r");
       $priv_key = fread($fp, 8192);
       fclose($fp);
       $pkeyid = openssl_get_privatekey($priv_key);
       openssl_sign($policy, $signature, $pkeyid);
       openssl_free_key($pkeyid);
       return $signature;
   }
   
   function url_safe_base64_encode($value) {
       $encoded = base64_encode($value);
       return str_replace(
           array('+', '=', '/'),
           array('-', '_', '~'),
           $encoded);
   }
   ```

   下列函數使用 SHA-256 而非 SHA-1：

   ```
   function rsa_sha256_sign($policy, $private_key_filename) {
       $signature = "";
       $fp = fopen($private_key_filename, "r");
       $priv_key = fread($fp, 8192);
       fclose($fp);
       $pkeyid = openssl_get_privatekey($priv_key);
       openssl_sign($policy, $signature, $pkeyid, OPENSSL_ALGO_SHA256);
       openssl_free_key($pkeyid);
       return $signature;
   }
   ```

   `rsa_sha256_sign` 函數與 相同`rsa_sha1_sign`，但會傳遞`OPENSSL_ALGO_SHA256`給 `openssl_sign`。當您使用 SHA-256 時，請包含值為 的 `CloudFront-Hash-Algorithm` Cookie`SHA256`。

## 建立已簽署 Cookie
<a name="create-the-signed-cookie"></a>

下列程式碼會使用下列 Cookie 屬性來建構 建立簽章的 Cookie：`CloudFront-Expires`、 `CloudFront-Signature``CloudFront-Key-Pair-Id`和 `CloudFront-Hash-Algorithm`。程式碼使用自訂政策。

```
function create_signed_cookies($resource, $private_key_filename, $key_pair_id, $expires, $client_ip = null, $hash_algorithm = 'SHA1') {
    $policy = array(
        'Statement' => array(
            array(
                'Resource' => $resource,
                'Condition' => array(
                    'DateLessThan' => array('AWS:EpochTime' => $expires)
                )
            )
        )
    );

    if ($client_ip) {
        $policy['Statement'][0]['Condition']['IpAddress'] = array('AWS:SourceIp' => $client_ip . '/32');
    }

    $policy = json_encode($policy);
    $encoded_policy = url_safe_base64_encode($policy);
    if ($hash_algorithm === 'SHA256') {
        $signature = rsa_sha256_sign($policy, $private_key_filename);
    } else {
        $signature = rsa_sha1_sign($policy, $private_key_filename);
    }
    $encoded_signature = url_safe_base64_encode($signature);

    $cookies = array(
        'CloudFront-Policy' => $encoded_policy,
        'CloudFront-Signature' => $encoded_signature,
        'CloudFront-Key-Pair-Id' => $key_pair_id
    );

    if ($hash_algorithm === 'SHA256') {
        $cookies['CloudFront-Hash-Algorithm'] = 'SHA256';
    }

    return $cookies;
}
```

如需詳細資訊，請參閱[使用自訂政策設定已簽署 Cookie](private-content-setting-signed-cookie-custom-policy.md)。

## 完整程式碼
<a name="full-code-signed-cookies"></a>

下面的範例程式碼提供了使用 PHP 建立 CloudFront 已簽署 Cookie 的完整示範。您可以從 [demo-php.zip](samples/demo-php.zip) 檔案下載完整範例。

您可以在下列範例中修改 `$policy Condition` 元素，以允許 IPv4 與 IPv6 位址範圍。如需範例，請參閱《*Amazon Simple Storage Service 使用者指南*》中的[在 IAM 政策中使用 IPv6 位址](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ipv6-access.html#ipv6-access-iam)。

```
<?php

function rsa_sha1_sign($policy, $private_key_filename) {
    $signature = "";
    $fp = fopen($private_key_filename, "r");
    $priv_key = fread($fp, 8192);
    fclose($fp);
    $pkeyid = openssl_get_privatekey($priv_key);
    openssl_sign($policy, $signature, $pkeyid);
    openssl_free_key($pkeyid);
    return $signature;
}

function url_safe_base64_encode($value) {
    $encoded = base64_encode($value);
    return str_replace(
        array('+', '=', '/'),
        array('-', '_', '~'),
        $encoded);
}

function rsa_sha256_sign($policy, $private_key_filename) {
    $signature = "";
    $fp = fopen($private_key_filename, "r");
    $priv_key = fread($fp, 8192);
    fclose($fp);
    $pkeyid = openssl_get_privatekey($priv_key);
    openssl_sign($policy, $signature, $pkeyid, OPENSSL_ALGO_SHA256);
    openssl_free_key($pkeyid);
    return $signature;
}

function create_signed_cookies($resource, $private_key_filename, $key_pair_id, $expires, $client_ip = null, $hash_algorithm = 'SHA1') {
    $policy = array(
        'Statement' => array(
            array(
                'Resource' => $resource,
                'Condition' => array(
                    'DateLessThan' => array('AWS:EpochTime' => $expires)
                )
            )
        )
    );

    if ($client_ip) {
        $policy['Statement'][0]['Condition']['IpAddress'] = array('AWS:SourceIp' => $client_ip . '/32');
    }

    $policy = json_encode($policy);
    $encoded_policy = url_safe_base64_encode($policy);
    if ($hash_algorithm === 'SHA256') {
        $signature = rsa_sha256_sign($policy, $private_key_filename);
    } else {
        $signature = rsa_sha1_sign($policy, $private_key_filename);
    }
    $encoded_signature = url_safe_base64_encode($signature);

    $cookies = array(
        'CloudFront-Policy' => $encoded_policy,
        'CloudFront-Signature' => $encoded_signature,
        'CloudFront-Key-Pair-Id' => $key_pair_id
    );

    if ($hash_algorithm === 'SHA256') {
        $cookies['CloudFront-Hash-Algorithm'] = 'SHA256';
    }

    return $cookies;
}



$private_key_filename = '/home/test/secure/example-priv-key.pem';
$key_pair_id = 'K2JCJMDEHXQW5F';
$base_url = 'https://d1234.cloudfront.net';

$expires = time() + 3600; // 1 hour from now

// Get the viewer real IP from the x-forward-for header as $_SERVER['REMOTE_ADDR'] will return viewer facing IP. An alternative option is to use CloudFront-Viewer-Address header. Note that this header is a trusted CloudFront immutable header. Example format: IP:PORT ("CloudFront-Viewer-Address": "1.2.3.4:12345")
$client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];


// For HLS manifest and segments (using wildcard)
$hls_resource = $base_url . '/sign/*';
$signed_cookies = create_signed_cookies($hls_resource, $private_key_filename, $key_pair_id, $expires, $client_ip, 'SHA256');

// Set the cookies
$cookie_domain = parse_url($base_url, PHP_URL_HOST);
foreach ($signed_cookies as $name => $value) {
    setcookie($name, $value, $expires, '/', $cookie_domain, true, true);
}

?>

<!DOCTYPE html>
<html>
<head>
    <title>CloudFront Signed HLS Stream with Cookies</title>
</head>
<body>
    <h1>Amazon CloudFront Signed HLS Stream with Cookies</h1>
    <h2>Expires at <?php echo gmdate('Y-m-d H:i:s T', $expires); ?> only viewable by IP <?php echo $client_ip; ?></h2>
    
    <div id='hls-video'>
        <video id="video" width="640" height="360" controls></video>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
    <script>
        var video = document.getElementById('video');
        var manifestUrl = '<?php echo $base_url; ?>/sign/manifest.m3u8';
        
        if (Hls.isSupported()) {
            var hls = new Hls();
            hls.loadSource(manifestUrl);
            hls.attachMedia(video);
        }
        else if (video.canPlayType('application/vnd.apple.mpegurl')) {
            video.src = manifestUrl;
        }
    </script>
</body>
</html>
```

您可以使用已簽署 URL，而不是使用已簽署 Cookie。如需詳細資訊，請參閱[使用 PHP 建立 URL 簽章](CreateURL_PHP.md)。

# 用於 Base64 編碼和加密的 Linux 命令和 OpenSSL
<a name="private-content-linux-openssl"></a>

您可以使用以下 Linux 命令列命令和 OpenSSL 來雜湊和簽署政策聲明、base64 編碼簽章，並將 URL 查詢字串參數中無效的字元替換為有效的字元。

如需 OpenSSL 的詳細資訊，請前往 [https://www.openssl.org](https://www.openssl.org)。

SHA-1 （預設）：

```
cat policy | tr -d "\n" | tr -d " \t\n\r" | openssl sha1 -sign private_key.pem | openssl base64 -A | tr -- '+=/' '-_~'
```

SHA-256：

```
cat policy | tr -d "\n" | tr -d " \t\n\r" | openssl sha256 -sign private_key.pem | openssl base64 -A | tr -- '+=/' '-_~'
```

在上述命令中：
+ `cat` 會讀取 `policy` 檔案。
+ `tr -d "\n" | tr -d " \t\n\r"` 會移除 `cat` 所新增的空格和新行字元。
+ OpenSSL 會使用 SHA-1 （或 SHA-256) 雜湊檔案，並使用私有金鑰檔案 簽署該檔案`private_key.pem`。私有金鑰簽章可以是 RSA 2048 或 ECDSA 256。如果您使用 SHA-256，請在已簽章的 URL 中包含`Hash-Algorithm=SHA256`查詢參數，或在已簽章的 `CloudFront-Hash-Algorithm=SHA256` Cookie 中包含 Cookie。
+ 使用 OpenSSL base64 來將經過雜湊演算和簽署的政策陳述式編碼。
+ `tr` 以有效字元取代 URL 查詢字串參數中無效的字元。

如需示範建立簽章的更多程式碼範例，請參閱 [為已簽署 URL 建立簽章的程式碼範例](PrivateCFSignatureCodeAndExamples.md)。

# 為已簽署 URL 建立簽章的程式碼範例
<a name="PrivateCFSignatureCodeAndExamples"></a>

本節包含可下載的應用程式範例，示範如何為已簽章的 URL 建立簽章。範例可在 Perl、PHP、C\$1 和 Java 中找到。您可以使用任何範例來建立簽章的 URL。Perl 指令碼在 Linux 和 macOS 平台上執行。PHP 範例可以在任何執行 PHP 的伺服器上執行。C\$1 範例使用 .NET 架構。

本節中的範例使用 SHA-1 來雜湊和簽署政策陳述式。您也可以使用 SHA-256。若要使用 SHA-256，請在簽署函數中更新雜湊演算法 （例如，在 OpenSSL 呼叫`sha256`中`sha1`將 取代為 ，或在語言的密碼編譯程式庫中使用同等的 SHA-256 常數）。當您使用 SHA-256 時，請在簽章的 URL 中包含`Hash-Algorithm=SHA256`查詢參數。

如需 JavaScript (Node.js) 中的範例程式碼，請參閱 AWS 開發人員部落格上的在 [Node.js 中建立 Amazon CloudFront 簽章 URLs](https://aws.amazon.com/blogs/developer/creating-amazon-cloudfront-signed-urls-in-node-js/)。

例如 Python 中的程式碼，請參閱《*適用於 Python (Boto3) 的AWS SDK API 參考》*中的[為 Amazon CloudFront 產生簽署的 URL](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudfront.html#examples)，以及 Boto3 GitHub 儲存庫中的[此範例程式碼](https://github.com/boto/boto3/blob/develop/boto3/examples/cloudfront.rst)。

**Topics**
+ [使用 Perl 建立 URL 簽章](CreateURLPerl.md)
+ [使用 PHP 建立 URL 簽章](CreateURL_PHP.md)
+ [使用 C\$1 和 .NET 架構建立 URL 簽章](CreateSignatureInCSharp.md)
+ [使用 Java 建立 URL 簽章](CFPrivateDistJavaDevelopment.md)

# 使用 Perl 建立 URL 簽章
<a name="CreateURLPerl"></a>

本節包含適用於 Linux/Mac 平台的 Perl 指令碼，可用來建立私有內容的簽章。若要建立簽章，請使用命令列參數指定 CloudFront URL、簽署者的私有金鑰路徑、金鑰 ID 和 URL 的過期日期，來執行指令碼。此工具也可以解碼簽章的 URL。

**備註**  
建立 URL 簽章只是私有內容提供服務的程序的一部分，以使用簽章 URL。如需端對端程序的詳細資訊，請參閱 [使用已簽署 URL](private-content-signed-urls.md)。
在簽署命令中，請注意 `sha1`可以在 `openssl dgst` 呼叫`sha256`中取代為 。

**Topics**
+ [用於建立已簽署 URL 的 Perl 指令碼來源](#CreateURLPerlScriptSource)

## 用於建立已簽署 URL 的 Perl 指令碼來源
<a name="CreateURLPerlScriptSource"></a>

以下 Perl 原始程式碼可用來建立適用於 CloudFront 簽章的 URL。程式碼中的註解包含有關命令列參數和工具功能的詳細資訊。

```
#!/usr/bin/perl -w

# Copyright 2008 Amazon Technologies, Inc.  Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You may obtain a copy of the License at:
#
# https://aws.amazon.com/apache2.0
#
# This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and limitations under the License.

=head1 cfsign.pl

cfsign.pl - A tool to generate and verify Amazon CloudFront signed URLs

=head1 SYNOPSIS

This script uses an existing RSA key pair to sign and verify Amazon CloudFront signed URLs

View the script source for details as to which CPAN packages are required beforehand. 

For help, try:

cfsign.pl --help

URL signing examples:

cfsign.pl --action encode --url https://images.my-website.com/gallery1.zip --policy sample_policy.json --private-key privkey.pem --key-pair-id mykey

cfsign.pl --action encode --url https://images.my-website.com/gallery1.zip --expires 1257439868 --private-key privkey.pem --key-pair-id mykey

URL decode example:

cfsign.pl --action decode --url "http//mydist.cloudfront.net/?Signature=AGO-PgxkYo99MkJFHvjfGXjG1QDEXeaDb4Qtzmy85wqyJjK7eKojQWa4BCRcow__&Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovLypicmFkbS5qcGciLCJDb25kaXRpb24iOnsiSXBBZGRyZXNzIjp7IkFXUzpTb3VyY2VJcCI6IjEwLjUyLjE3LjkvMCJ9LCJEYXRlR3JlYXRlclRoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTI1MjUyMDgzMH19fV19Cg__&Key-Pair-Id=mykey"


To generate an RSA key pair, you can use openssl and the following commands:

# Generate a 2048 bit key pair
openssl genrsa -out private-key.pem 2048
openssl rsa -in private-key.pem -pubout -out public-key.pem


=head1 OPTIONS

=over 8

=item B<--help>

Print a help message and exits.

=item B<--action> [action]

The action to execute.  action can be one of:

  encode - Generate a signed URL (using a canned policy or a user policy)
  decode - Decode a signed URL

=item B<--url>

The URL to en/decode

=item B<--stream>

The stream to en/decode

=item B<--private-key>

The path to your private key.

=item B<--key-pair-id>

The key pair identifier.

=item B<--policy>

The CloudFront policy document.

=item B<--expires>

The Unix epoch time when the URL is to expire. If both this option and
the --policy option are specified, --policy will be used. Otherwise, this 
option alone will use a canned policy.

=back

=cut

use strict;
use warnings;

# you might need to use CPAN to get these modules.
# run perl -MCPAN -e "install <module>" to get them.
# The openssl command line will also need to be in your $PATH.
use File::Temp qw/tempfile/;
use File::Slurp;
use Getopt::Long;
use IPC::Open2;
use MIME::Base64 qw(encode_base64 decode_base64);
use Pod::Usage;
use URI;

my $CANNED_POLICY 
    = '{"Statement":[{"Resource":"<RESOURCE>","Condition":{"DateLessThan":{"AWS:EpochTime":<EXPIRES>}}}]}';

my $POLICY_PARAM      = "Policy";
my $EXPIRES_PARAM     = "Expires";
my $SIGNATURE_PARAM   = "Signature";
my $KEY_PAIR_ID_PARAM = "Key-Pair-Id";

my $verbose = 0;
my $policy_filename = "";
my $expires_epoch = 0;
my $action = "";
my $help = 0;
my $key_pair_id = "";
my $url = "";
my $stream = "";
my $private_key_filename = "";

my $result = GetOptions("action=s"      => \$action,
                        "policy=s"      => \$policy_filename,
                        "expires=i"     => \$expires_epoch,
                        "private-key=s" => \$private_key_filename,
                        "key-pair-id=s" => \$key_pair_id,
                        "verbose"       => \$verbose,
                        "help"          => \$help,
                        "url=s"         => \$url,
                        "stream=s"      => \$stream,
                    );

if ($help or !$result) {
    pod2usage(1);
    exit;
}

if ($url eq "" and $stream eq "") {
    print STDERR "Must include a stream or a URL to encode or decode with the --stream or --url option\n";
    exit;
}

if ($url ne "" and $stream ne "") {
    print STDERR "Only one of --url and --stream may be specified\n";
    exit;
}

if ($url ne "" and !is_url_valid($url)) {
    exit;
}

if ($stream ne "") {
    exit unless is_stream_valid($stream);

    # The signing mechanism is identical, so from here on just pretend we're
    # dealing with a URL
    $url = $stream;
} 

if ($action eq "encode") {
    # The encode action will generate a private content URL given a base URL, 
    # a policy file (or an expires timestamp) and a key pair id parameter
    my $private_key;
    my $public_key;
    my $public_key_file;
    
    my $policy;
    if ($policy_filename eq "") {
        if ($expires_epoch == 0) {
            print STDERR "Must include policy filename with --policy argument or an expires" . 
                          "time using --expires\n";            
        }
        
        $policy = $CANNED_POLICY;
        $policy =~ s/<EXPIRES>/$expires_epoch/g;
        $policy =~ s/<RESOURCE>/$url/g;
    } else {
        if (! -e $policy_filename) {
            print STDERR "Policy file $policy_filename does not exist\n";
            exit;
        }
        $expires_epoch = 0; # ignore if set
        $policy = read_file($policy_filename);
    }

    if ($private_key_filename eq "") {
        print STDERR "You must specific the path to your private key file with --private-key\n";
        exit;
    }

    if (! -e $private_key_filename) {
        print STDERR "Private key file $private_key_filename does not exist\n";
        exit;
    }

    if ($key_pair_id eq "") {
        print STDERR "You must specify a key pair id with --key-pair-id\n";
        exit;
    }

    my $encoded_policy = url_safe_base64_encode($policy);
    my $signature = rsa_sha1_sign($policy, $private_key_filename);
    my $encoded_signature = url_safe_base64_encode($signature);

    my $generated_url = create_url($url, $encoded_policy, $encoded_signature, $key_pair_id, $expires_epoch);


    if ($stream ne "") {
        print "Encoded stream (for use within a swf):\n" . $generated_url . "\n";
        print "Encoded and escaped stream (for use on a webpage):\n" .  escape_url_for_webpage($generated_url) . "\n"; 
    } else {
        print "Encoded URL:\n" . $generated_url . "\n";
    }
} elsif ($action eq "decode") {
    my $decoded = decode_url($url);
    if (!$decoded) {
        print STDERR "Improperly formed URL\n";
        exit;
    }

    print_decoded_url($decoded);
} else {
    # No action specified, print help.  But only if this is run as a program (caller will be empty)
    pod2usage(1) unless caller();
}

# Decode a private content URL into its component parts
sub decode_url {
    my $url = shift;

    if ($url =~ /(.*)\?(.*)/) {
        my $base_url = $1;
        my $params = $2;

        my @unparsed_params = split(/&/, $params);
        my %params = ();
        foreach my $param (@unparsed_params) {
            my ($key, $val) = split(/=/, $param);
            $params{$key} = $val;
        }

        my $encoded_signature = "";
        if (exists $params{$SIGNATURE_PARAM}) {
            $encoded_signature = $params{"Signature"};
        } else {
            print STDERR "Missing Signature URL parameter\n";
            return 0;
        }

        my $encoded_policy = "";
        if (exists $params{$POLICY_PARAM}) {
            $encoded_policy = $params{$POLICY_PARAM};
        } else {
            if (!exists $params{$EXPIRES_PARAM}) {
                print STDERR "Either the Policy or Expires URL parameter needs to be specified\n";
                return 0;    
            }
            
            my $expires = $params{$EXPIRES_PARAM};
            
            my $policy = $CANNED_POLICY;
            $policy =~ s/<EXPIRES>/$expires/g;
            
            my $url_without_cf_params = $url;
            $url_without_cf_params =~ s/$SIGNATURE_PARAM=[^&]*&?//g;
            $url_without_cf_params =~ s/$POLICY_PARAM=[^&]*&?//g;
            $url_without_cf_params =~ s/$EXPIRES_PARAM=[^&]*&?//g;
            $url_without_cf_params =~ s/$KEY_PAIR_ID_PARAM=[^&]*&?//g;
            
            if ($url_without_cf_params =~ /(.*)\?$/) {
                $url_without_cf_params = $1;
            }
            
            $policy =~ s/<RESOURCE>/$url_without_cf_params/g;
            
            $encoded_policy = url_safe_base64_encode($policy);
        }

        my $key = "";
        if (exists $params{$KEY_PAIR_ID_PARAM}) {
            $key = $params{$KEY_PAIR_ID_PARAM};
        } else {
            print STDERR "Missing $KEY_PAIR_ID_PARAM parameter\n";
            return 0;
        }

        my $policy = url_safe_base64_decode($encoded_policy);

        my %ret = ();
        $ret{"base_url"} = $base_url;
        $ret{"policy"} = $policy;
        $ret{"key"} = $key;

        return \%ret;
    } else {
        return 0;
    }
}

# Print a decoded URL out
sub print_decoded_url {
    my $decoded = shift;

    print "Base URL: \n" . $decoded->{"base_url"} . "\n";
    print "Policy: \n" . $decoded->{"policy"} . "\n";
    print "Key: \n" . $decoded->{"key"} . "\n";
}

# Encode a string with base 64 encoding and replace some invalid URL characters
sub url_safe_base64_encode {
    my ($value) = @_;

    my $result = encode_base64($value);
    $result =~ tr|+=/|-_~|;

    return $result;
}

# Decode a string with base 64 encoding.  URL-decode the string first
# followed by reversing any special character ("+=/") translation.
sub url_safe_base64_decode {
    my ($value) = @_;

    $value =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
    $value =~ tr|-_~|+=/|;

    my $result = decode_base64($value);

    return $result;
}

# Create a private content URL
sub create_url {
    my ($path, $policy, $signature, $key_pair_id, $expires) = @_;
    
    my $result;
    my $separator = $path =~ /\?/ ? '&' : '?';
    if ($expires) {
        $result = "$path$separator$EXPIRES_PARAM=$expires&$SIGNATURE_PARAM=$signature&$KEY_PAIR_ID_PARAM=$key_pair_id";
    } else {
        $result = "$path$separator$POLICY_PARAM=$policy&$SIGNATURE_PARAM=$signature&$KEY_PAIR_ID_PARAM=$key_pair_id";
    }
    $result =~ s/\n//g;

    return $result;
}

# Sign a document with given private key file.
# The first argument is the document to sign
# The second argument is the name of the private key file
sub rsa_sha1_sign {
    my ($to_sign, $pvkFile) = @_;
    print "openssl sha1 -sign $pvkFile $to_sign\n";

    return write_to_program($pvkFile, $to_sign);
}

# Helper function to write data to a program
sub write_to_program {
my ($keyfile, $data) = @_;
unlink "temp_policy.dat" if (-e "temp_policy.dat");
unlink "temp_sign.dat" if (-e "temp_sign.dat");

write_file("temp_policy.dat", $data);

system("openssl dgst -sha1 -sign \"$keyfile\" -out temp_sign.dat temp_policy.dat");

my $output = read_file("temp_sign.dat");

    return $output;
}

# Read a file into a string and return the string
sub read_file {
    my ($file) = @_;

    open(INFILE, "<$file") or die("Failed to open $file: $!");
    my $str = join('', <INFILE>);
    close INFILE;

    return $str;
}

sub is_url_valid {
    my ($url) = @_;

    # HTTP distributions start with http[s]:// and are the correct thing to sign
    if ($url =~ /^https?:\/\//) {
        return 1;
    } else {
        print STDERR "CloudFront requires absolute URLs for HTTP distributions\n";
        return 0;
    }
}

sub is_stream_valid {
    my ($stream) = @_;

    if ($stream =~ /^rtmp:\/\// or $stream =~ /^\/?cfx\/st/) {
        print STDERR "Streaming distributions require that only the stream name is signed.\n";
        print STDERR "The stream name is everything after, but not including, cfx/st/\n";
        return 0;
    } else {
        return 1;
    }
}

# flash requires that the query parameters in the stream name are url
# encoded when passed in through javascript, etc.  This sub handles the minimal
# required url encoding.
sub escape_url_for_webpage {
    my ($url) = @_;

    $url =~ s/\?/%3F/g;
    $url =~ s/=/%3D/g;
    $url =~ s/&/%26/g;

    return $url;
}

1;
```

# 使用 PHP 建立 URL 簽章
<a name="CreateURL_PHP"></a>

任何執行 PHP 的 Web 伺服器都可以使用 PHP 範例程式碼為私有 CloudFront 分佈建立政策聲明和簽章。該完整範例以已簽署 URL 連結建立一個正常運作網頁，該連結使用 CloudFront 串流播放視訊串流。您可以從 [demo-php.zip](samples/demo-php.zip) 檔案下載完整範例。

**備註**  
建立 URL 簽章只是私有內容提供服務的程序的一部分，以使用簽章 URL。如需有關整個程序的詳細資訊，請參閱 [使用已簽署 URL](private-content-signed-urls.md)。
您還可以使用 適用於 PHP 的 AWS SDK中的 `UrlSigner` 類別建立簽章的 URL。如需詳細資訊，請參閱 *適用於 PHP 的 AWS SDK API 參考*中的 [Class UrlSigner](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.CloudFront.UrlSigner.html)。
在`openssl_sign`呼叫中，請注意`OPENSSL_ALGO_SHA256`，做為第四個引數傳遞 會切換到 SHA-256。([使用 PHP 建立已簽署 Cookie](signed-cookies-PHP.md)如需完整範例，另請參閱 。)

**Topics**
+ [建立 RSA SHA-1 簽章](#sample-rsa-sign)
+ [建立標準政策](#sample-canned-policy)
+ [建立自訂政策](#sample-custom-policy)
+ [完整程式碼範例](#full-example)

下列各節將程式碼範例細分為個別部分。您可以在下面找到 [完整程式碼範例](#full-example)。

## 建立 RSA SHA-1 簽章
<a name="sample-rsa-sign"></a>

此程式碼會執行下列操作：
+ `rsa_sha1_sign` 函數會雜湊並簽署政策陳述式。所需的引數為政策陳述式，以及與您分佈之信任金鑰群組中公有金鑰對應的私有金鑰。
+ 接著，該 `url_safe_base64_encode` 函數會建立已簽章的 URL 安全版本。

```
function rsa_sha1_sign($policy, $private_key_filename) {
    $signature = "";

    // load the private key
    $fp = fopen($private_key_filename, "r");
    $priv_key = fread($fp, 8192);
    fclose($fp);
    $pkeyid = openssl_get_privatekey($priv_key);

    // compute signature
    openssl_sign($policy, $signature, $pkeyid);

    // free the key from memory
    openssl_free_key($pkeyid);

    return $signature;
}

function url_safe_base64_encode($value) {
    $encoded = base64_encode($value);
    // replace unsafe characters +, = and / with 
    // the safe characters -, _ and ~
    return str_replace(
        array('+', '=', '/'),
        array('-', '_', '~'),
        $encoded);
}
```

下列程式碼片段使用 `get_canned_policy_stream_name()` 和 `get_custom_policy_stream_name()` 函數來建立標準和自訂政策。CloudFront 使用政策來建立串流影片的 URL，包括指定過期時間。

然後，您可以使用標準政策或自訂政策來決定如何管理對內容的存取。如需選擇哪個項目的詳細資訊，請參閱 [決定對已簽署 URL 使用標準或自訂政策](private-content-signed-urls.md#private-content-choosing-canned-custom-policy) 一節。

## 建立標準政策
<a name="sample-canned-policy"></a>

下列範例程式碼會建構簽章的*標準*政策陳述式。

**注意**  
`$expires` 變數是日期/時間戳記，必須整數，而不是字串。

```
function get_canned_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $expires) {
    // this policy is well known by CloudFront, but you still need to sign it, since it contains your parameters
    $canned_policy = '{"Statement":[{"Resource":"' . $video_path . '","Condition":{"DateLessThan":{"AWS:EpochTime":'. $expires . '}}}]}';
    // the policy contains characters that cannot be part of a URL, so we base64 encode it
    $encoded_policy = url_safe_base64_encode($canned_policy);
    // sign the original policy, not the encoded version
    $signature = rsa_sha1_sign($canned_policy, $private_key_filename);
    // make the signature safe to be included in a URL
    $encoded_signature = url_safe_base64_encode($signature);

    // combine the above into a stream name
    $stream_name = create_stream_name($video_path, null, $encoded_signature, $key_pair_id, $expires);
    // URL-encode the query string characters
    return $stream_name;
}
```

如需有關標準政策的詳細資訊，請參閱 [使用標準政策建立已簽署 URL](private-content-creating-signed-url-canned-policy.md)。

## 建立自訂政策
<a name="sample-custom-policy"></a>

下列範例程式碼會建構簽章的*自訂*政策陳述式。

```
function get_custom_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $policy) {
    // the policy contains characters that cannot be part of a URL, so we base64 encode it
    $encoded_policy = url_safe_base64_encode($policy);
    // sign the original policy, not the encoded version
    $signature = rsa_sha1_sign($policy, $private_key_filename);
    // make the signature safe to be included in a URL
    $encoded_signature = url_safe_base64_encode($signature);

    // combine the above into a stream name
    $stream_name = create_stream_name($video_path, $encoded_policy, $encoded_signature, $key_pair_id, null);
    // URL-encode the query string characters
    return $stream_name;
}
```

如需有關自訂政策的詳細資訊，請參閱 [使用自訂政策建立已簽署 URL](private-content-creating-signed-url-custom-policy.md)。

## 完整程式碼範例
<a name="full-example"></a>

下面的範例程式碼提供了使用 PHP 建立 CloudFront 簽章 URL 的完整示範。您可以從 [demo-php.zip](samples/demo-php.zip) 檔案下載完整範例。

您可以在下列範例中修改 `$policy` `Condition` 元素，以允許 IPv4 與 IPv6 位址範圍。如需範例，請參閱《*Amazon Simple Storage Service 使用者指南*》中的[在 IAM 政策中使用 IPv6 位址](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ipv6-access.html#ipv6-access-iam)。

```
<?php

function rsa_sha1_sign($policy, $private_key_filename) {
    $signature = "";

    // load the private key
    $fp = fopen($private_key_filename, "r");
    $priv_key = fread($fp, 8192);
    fclose($fp);
    $pkeyid = openssl_get_privatekey($priv_key);

    // compute signature
    openssl_sign($policy, $signature, $pkeyid);

    // free the key from memory
    openssl_free_key($pkeyid);

    return $signature;
}

function url_safe_base64_encode($value) {
    $encoded = base64_encode($value);
    // replace unsafe characters +, = and / with the safe characters -, _ and ~
    return str_replace(
        array('+', '=', '/'),
        array('-', '_', '~'),
        $encoded);
}

function create_stream_name($stream, $policy, $signature, $key_pair_id, $expires) {
    $result = $stream;
    // if the stream already contains query parameters, attach the new query parameters to the end
    // otherwise, add the query parameters
    $separator = strpos($stream, '?') == FALSE ? '?' : '&';
    // the presence of an expires time means we're using a canned policy
    if($expires) {
        $result .= $separator . "Expires=" . $expires . "&Signature=" . $signature . "&Key-Pair-Id=" . $key_pair_id;
    }
    // not using a canned policy, include the policy itself in the stream name
    else {
        $result .= $separator . "Policy=" . $policy . "&Signature=" . $signature . "&Key-Pair-Id=" . $key_pair_id;
    }

    // new lines would break us, so remove them
    return str_replace('\n', '', $result);
}


function get_canned_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $expires) {
    // this policy is well known by CloudFront, but you still need to sign it, since it contains your parameters
    $canned_policy = '{"Statement":[{"Resource":"' . $video_path . '","Condition":{"DateLessThan":{"AWS:EpochTime":'. $expires . '}}}]}';
    // the policy contains characters that cannot be part of a URL, so we base64 encode it
    $encoded_policy = url_safe_base64_encode($canned_policy);
    // sign the original policy, not the encoded version
    $signature = rsa_sha1_sign($canned_policy, $private_key_filename);
    // make the signature safe to be included in a URL
    $encoded_signature = url_safe_base64_encode($signature);

    // combine the above into a stream name
    $stream_name = create_stream_name($video_path, null, $encoded_signature, $key_pair_id, $expires);
    // URL-encode the query string characters
    return $stream_name;
}

function get_custom_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $policy) {
    // the policy contains characters that cannot be part of a URL, so we base64 encode it
    $encoded_policy = url_safe_base64_encode($policy);
    // sign the original policy, not the encoded version
    $signature = rsa_sha1_sign($policy, $private_key_filename);
    // make the signature safe to be included in a URL
    $encoded_signature = url_safe_base64_encode($signature);

    // combine the above into a stream name
    $stream_name = create_stream_name($video_path, $encoded_policy, $encoded_signature, $key_pair_id, null);
    // URL-encode the query string characters
    return $stream_name;
}


// Path to your private key.  Be very careful that this file is not accessible
// from the web!

$private_key_filename = '/home/test/secure/example-priv-key.pem';
$key_pair_id = 'K2JCJMDEHXQW5F';

// Make sure you have "Restrict viewer access" enabled on this path behaviour and using the above Trusted key groups (recommended).
$video_path = 'https://example.com/secure/example.mp4';

$expires = time() + 300; // 5 min from now
$canned_policy_stream_name = get_canned_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $expires);

// Get the viewer real IP from the x-forward-for header as $_SERVER['REMOTE_ADDR'] will return viewer facing IP. An alternative option is to use CloudFront-Viewer-Address header. Note that this header is a trusted CloudFront immutable header. Example format: IP:PORT ("CloudFront-Viewer-Address": "1.2.3.4:12345")
$client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
$policy =
'{'.
    '"Statement":['.
        '{'.
            '"Resource":"'. $video_path . '",'.
            '"Condition":{'.
                '"IpAddress":{"AWS:SourceIp":"' . $client_ip . '/32"},'.
                '"DateLessThan":{"AWS:EpochTime":' . $expires . '}'.
            '}'.
        '}'.
    ']' .
    '}';
$custom_policy_stream_name = get_custom_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $policy);

?>

<html>

<head>
    <title>CloudFront</title>
</head>

<body>
    <h1>Amazon CloudFront</h1>
    <h2>Canned Policy</h2>
    <h3>Expires at <?php echo gmdate('Y-m-d H:i:s T', $expires); ?></h3>
    <br />

    <div id='canned'>The canned policy video will be here: <br>
    
        <video width="640" height="360" autoplay muted controls>
        <source src="<?php echo $canned_policy_stream_name; ?>" type="video/mp4">
        Your browser does not support the video tag.
        </video>
    </div>

    <h2>Custom Policy</h2>
    <h3>Expires at <?php echo gmdate('Y-m-d H:i:s T', $expires); ?> only viewable by IP <?php echo $client_ip; ?></h3>
    <div id='custom'>The custom policy video will be here: <br>

         <video width="640" height="360" autoplay muted controls>
         <source src="<?php echo $custom_policy_stream_name; ?>" type="video/mp4">
         Your browser does not support the video tag.
        </video>
    </div> 

</body>

</html>
```

如需其他 URL 簽章範例，請參閱下列主題：
+ [使用 Perl 建立 URL 簽章](CreateURLPerl.md)
+ [使用 C\$1 和 .NET 架構建立 URL 簽章](CreateSignatureInCSharp.md)
+ [使用 Java 建立 URL 簽章](CFPrivateDistJavaDevelopment.md)

您可以使用已簽署 Cookie，而不是使用已簽署 URL 來建立簽章。如需詳細資訊，請參閱[使用 PHP 建立已簽署 Cookie](signed-cookies-PHP.md)。

# 使用 C\$1 和 .NET 架構建立 URL 簽章
<a name="CreateSignatureInCSharp"></a>

本節中的 C\$1 範例實作應用程式範例，示範如何使用標準和自訂政策聲明為 CloudFront 私有分佈建立簽章。此範例包含使用 [適用於 .NET 的 AWS SDK](https://aws.amazon.com/sdkfornet) 的公用程式函數，這些函數在 .NET 應用程式中非常實用。

您也可以使用 適用於 .NET 的 SDK建立已簽章的 URL 和已簽章的 Cookie。在 *適用於 .NET 的 SDK API 參考*中，請參閱下列主題：
+ **已簽署 URL** – [AmazonCloudFrontUrlSigner](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFront/TCloudFrontUrlSigner.html) 
+ **已簽署 Cookie** – [AmazonCloudFrontCookieSigner](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFront/TCloudFrontCookieSigner.html) 

若要下載程式碼，請前往[使用 C\$1 的簽章程式碼](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/samples/AWS_PrivateCF_Distributions.zip)。

**備註**  
`AmazonCloudFrontUrlSigner` 和 `AmazonCloudFrontCookieSigner` 類別已移至單獨的套件。如需有關如何使用的詳細資訊，請參閱《*適用於 .NET 的 AWS SDK (V4) 開發人員指南*》中的 [CookieSigner 和 UrlSigner](https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/net-dg-v4.html#net-dg-v4-CookieSigner-UrlSigner)。
建立 URL 簽章只是私有內容提供服務的程序的一部分，以使用簽章 URL。如需詳細資訊，請參閱[使用已簽署 URL](private-content-signed-urls.md)。若需有關使用已簽署 Cookie 的詳細資訊，請參閱 [使用已簽署 Cookie](private-content-signed-cookies.md)。
在 RSA 簽署呼叫中，請注意 `SHA1`可以在雜湊演算法參數`SHA256`中取代為 。

## 在 .NET Framework 中使用 RSA 金鑰
<a name="rsa-key-sdk-net"></a>

若要在 .NET Framework 中使用 RSA 金鑰，您必須將 AWS 提供的 .pem 檔案轉換為 .NET Framework 使用的 XML 格式。

轉換後，RSA 私有金鑰檔案的格式如下：

**Example ：XML .NET 架構格式的 RSA 私有金鑰**  <a name="RSAPrivateKeyXML.NETFrameworkFormat"></a>

```
<RSAKeyValue>
  <Modulus>
    wO5IvYCP5UcoCKDo1dcspoMehWBZcyfs9QEzGi6Oe5y+ewGr1oW+vB2GPB
    ANBiVPcUHTFWhwaIBd3oglmF0lGQljP/jOfmXHUK2kUUnLnJp+oOBL2NiuFtqcW6h/L5lIpD8Yq+NRHg
    Ty4zDsyr2880MvXv88yEFURCkqEXAMPLE=
  </Modulus>
  <Exponent>AQAB</Exponent>
  <P>
    5bmKDaTz
    npENGVqz4Cea8XPH+sxt+2VaAwYnsarVUoSBeVt8WLloVuZGG9IZYmH5KteXEu7fZveYd9UEXAMPLE==
  </P>
  <Q>
    1v9l/WN1a1N3rOK4VGoCokx7kR2SyTMSbZgF9IWJNOugR/WZw7HTnjipO3c9dy1Ms9pUKwUF4
    6d7049EXAMPLE==
  </Q>
  <DP>
    RgrSKuLWXMyBH+/l1Dx/I4tXuAJIrlPyo+VmiOc7b5NzHptkSHEPfR9s1
    OK0VqjknclqCJ3Ig86OMEtEXAMPLE==
  </DP>
  <DQ>
    pjPjvSFw+RoaTu0pgCA/jwW/FGyfN6iim1RFbkT4
    z49DZb2IM885f3vf35eLTaEYRYUHQgZtChNEV0TEXAMPLE==
  </DQ>
  <InverseQ>
    nkvOJTg5QtGNgWb9i
    cVtzrL/1pFEOHbJXwEJdU99N+7sMK+1066DL/HSBUCD63qD4USpnf0myc24in0EXAMPLE==</InverseQ>
  <D>
      Bc7mp7XYHynuPZxChjWNJZIq+A73gm0ASDv6At7F8Vi9r0xUlQe/v0AQS3ycN8QlyR4XMbzMLYk
      3yjxFDXo4ZKQtOGzLGteCU2srANiLv26/imXA8FVidZftTAtLviWQZBVPTeYIA69ATUYPEq0a5u5wjGy
      UOij9OWyuEXAMPLE=
   </D>
</RSAKeyValue>
```

## C\$1 的標準政策簽章方式
<a name="canned-policy-signed-url-net"></a>

以下 C\$1 程式碼會透過執行以下程序建立使用標準政策簽章的 URL：
+ 建立政策聲明。
+ 使用 SHA1 對政策陳述式進行雜湊處理，並使用 RSA 和其對應的公有金鑰在信任金鑰組中的私有金鑰對結果進行簽署。
+ Base64 編碼雜湊和簽章的政策聲明，並取代特殊字元，以使字串安全地用作 URL 請求參數。
+ 串連值。

如需完整的實作，請參閱[使用 C\$1 的簽章程式碼](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/samples/AWS_PrivateCF_Distributions.zip)範例。

**注意**  
當您將公有金鑰上傳至 CloudFront 時，會傳回 `keyId`。如需詳細資訊，請參閱 ![\[6\]](http://docs.aws.amazon.com/zh_tw/AmazonCloudFront/latest/DeveloperGuide/images/callouts/6.png)[ &Key-Pair-Id](private-content-creating-signed-url-canned-policy.md)。

**Example ：C\$1 的標準政策簽章方式**  <a name="ExampleCannedPolicySigningMethod-CSharp"></a>

```
public static string ToUrlSafeBase64String(byte[] bytes)
{
    return System.Convert.ToBase64String(bytes)
        .Replace('+', '-')
        .Replace('=', '_')
        .Replace('/', '~');
}

public static string CreateCannedPrivateURL(string urlString, 
    string durationUnits, string durationNumber, string pathToPolicyStmnt, 
    string pathToPrivateKey, string keyId)
{
    // args[] 0-thisMethod, 1-resourceUrl, 2-seconds-minutes-hours-days 
    // to expiration, 3-numberOfPreviousUnits, 4-pathToPolicyStmnt, 
    // 5-pathToPrivateKey, 6-keyId

    TimeSpan timeSpanInterval = GetDuration(durationUnits, durationNumber);

    // Create the policy statement.
    string strPolicy = CreatePolicyStatement(pathToPolicyStmnt,
        urlString, 
        DateTime.Now, 
        DateTime.Now.Add(timeSpanInterval), 
        "0.0.0.0/0");
    if ("Error!" == strPolicy) return "Invalid time frame." + 
        "Start time cannot be greater than end time.";

    // Copy the expiration time defined by policy statement.
    string strExpiration = CopyExpirationTimeFromPolicy(strPolicy);

    // Read the policy into a byte buffer.
    byte[] bufferPolicy = Encoding.ASCII.GetBytes(strPolicy);

    // Initialize the SHA1CryptoServiceProvider object and hash the policy data.
    using (SHA1CryptoServiceProvider 
        cryptoSHA1 = new SHA1CryptoServiceProvider())
    {
        bufferPolicy = cryptoSHA1.ComputeHash(bufferPolicy);

        // Initialize the RSACryptoServiceProvider object.
        RSACryptoServiceProvider providerRSA = new RSACryptoServiceProvider();
        XmlDocument xmlPrivateKey = new XmlDocument();

        // Load your private key, which you created by converting your 
        // .pem file to the XML format that the .NET framework uses.  
        // Several tools are available. 
        xmlPrivateKey.Load(pathToPrivateKey);

        // Format the RSACryptoServiceProvider providerRSA and 
        // create the signature.
        providerRSA.FromXmlString(xmlPrivateKey.InnerXml);
        RSAPKCS1SignatureFormatter rsaFormatter = 
            new RSAPKCS1SignatureFormatter(providerRSA);
        rsaFormatter.SetHashAlgorithm("SHA1");
        byte[] signedPolicyHash = rsaFormatter.CreateSignature(bufferPolicy);

        // Convert the signed policy to URL-safe base64 encoding and 
        // replace unsafe characters + = / with the safe characters - _ ~
        string strSignedPolicy = ToUrlSafeBase64String(signedPolicyHash);

        // Concatenate the URL, the timestamp, the signature, 
        // and the key pair ID to form the signed URL.
        return urlString + 
            "?Expires=" + 
            strExpiration + 
            "&Signature=" + 
            strSignedPolicy + 
            "&Key-Pair-Id=" + 
            keyId;
    }
}
```

## C\$1 的自訂政策簽章方式
<a name="custom-policy-signed-url-net"></a>

以下 C\$1 程式碼透過執行以下步驟建立使用自訂政策簽章的 URL：

1. 建立政策聲明。

1. Base64 編碼政策聲明，並取代特殊字元，以使字串安全地用作 URL 請求參數。

1. 使用 SHA1 對政策陳述式進行雜湊處理，並使用 RSA 和其對應的公有金鑰在信任金鑰組中的私有金鑰對結果進行加密。

1. Base64 編碼雜湊政策聲明，並取代特殊字元，以使字串安全地用作 URL 請求參數。

1. 串連值。

如需完整的實作，請參閱[使用 C\$1 的簽章程式碼](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/samples/AWS_PrivateCF_Distributions.zip)範例。

**注意**  
當您將公有金鑰上傳至 CloudFront 時，會傳回 `keyId`。如需詳細資訊，請參閱 ![\[6\]](http://docs.aws.amazon.com/zh_tw/AmazonCloudFront/latest/DeveloperGuide/images/callouts/6.png)[ &Key-Pair-Id](private-content-creating-signed-url-canned-policy.md)。

**Example ：C\$1 的自訂政策簽章方式**  <a name="ExampleCustomPolicySigningMethod-CSharp"></a>

```
public static string ToUrlSafeBase64String(byte[] bytes)
{
    return System.Convert.ToBase64String(bytes)
        .Replace('+', '-')
        .Replace('=', '_')
        .Replace('/', '~');
}

public static string CreateCustomPrivateURL(string urlString, 
    string durationUnits, string durationNumber, string startIntervalFromNow, 
    string ipaddress, string pathToPolicyStmnt, string pathToPrivateKey, 
    string keyId)
{
    // args[] 0-thisMethod, 1-resourceUrl, 2-seconds-minutes-hours-days 
    // to expiration, 3-numberOfPreviousUnits, 4-starttimeFromNow, 
    // 5-ip_address, 6-pathToPolicyStmt, 7-pathToPrivateKey, 8-keyId

    TimeSpan timeSpanInterval = GetDuration(durationUnits, durationNumber);
    TimeSpan timeSpanToStart = GetDurationByUnits(durationUnits, 
        startIntervalFromNow);
    if (null == timeSpanToStart) 
        return "Invalid duration units." + 
            "Valid options: seconds, minutes, hours, or days";
            
    string strPolicy = CreatePolicyStatement(
        pathToPolicyStmnt, urlString, DateTime.Now.Add(timeSpanToStart), 
        DateTime.Now.Add(timeSpanInterval), ipaddress);

    // Read the policy into a byte buffer.
    byte[] bufferPolicy = Encoding.ASCII.GetBytes(strPolicy);

    // Convert the policy statement to URL-safe base64 encoding and 
    // replace unsafe characters + = / with the safe characters - _ ~

    string urlSafePolicy = ToUrlSafeBase64String(bufferPolicy);

    // Initialize the SHA1CryptoServiceProvider object and hash the policy data.
    byte[] bufferPolicyHash;
    using (SHA1CryptoServiceProvider cryptoSHA1 = 
        new SHA1CryptoServiceProvider())
    {
        bufferPolicyHash = cryptoSHA1.ComputeHash(bufferPolicy);

        // Initialize the RSACryptoServiceProvider object.
        RSACryptoServiceProvider providerRSA = new RSACryptoServiceProvider();
        XmlDocument xmlPrivateKey = new XmlDocument();

        // Load your private key, which you created by converting your 
        // .pem file to the XML format that the .NET framework uses.  
        // Several tools are available. 
        xmlPrivateKey.Load(pathToPrivateKey);

        // Format the RSACryptoServiceProvider providerRSA 
        // and create the signature.
        providerRSA.FromXmlString(xmlPrivateKey.InnerXml);
        RSAPKCS1SignatureFormatter RSAFormatter = 
            new RSAPKCS1SignatureFormatter(providerRSA);
        RSAFormatter.SetHashAlgorithm("SHA1");
        byte[] signedHash = RSAFormatter.CreateSignature(bufferPolicyHash);

        // Convert the signed policy to URL-safe base64 encoding and 
        // replace unsafe characters + = / with the safe characters - _ ~
        string strSignedPolicy = ToUrlSafeBase64String(signedHash);

        return urlString + 
            "?Policy=" + 
            urlSafePolicy + 
            "&Signature=" + 
            strSignedPolicy + 
            "&Key-Pair-Id=" + 
            keyId;
    }
}
```

## 適用於簽章產生的公用方法
<a name="utility-methods-signed-url"></a>

以下方法從檔案取得政策聲明和剖析簽章產生的時間間隔。

**Example ：適用於簽章產生的公用方法**  <a name="UtilityMethodsForSignatureGeneration"></a>

```
public static string CreatePolicyStatement(string policyStmnt, 
   string resourceUrl, 
   DateTime startTime, 
   DateTime endTime, 
   string ipAddress)
   
{
   // Create the policy statement.
   FileStream streamPolicy = new FileStream(policyStmnt, FileMode.Open, FileAccess.Read);
   using (StreamReader reader = new StreamReader(streamPolicy))
   {
      string strPolicy = reader.ReadToEnd();

      TimeSpan startTimeSpanFromNow = (startTime - DateTime.Now);
      TimeSpan endTimeSpanFromNow = (endTime - DateTime.Now);
      TimeSpan intervalStart = 
         (DateTime.UtcNow.Add(startTimeSpanFromNow)) - 
         new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
      TimeSpan intervalEnd = 
         (DateTime.UtcNow.Add(endTimeSpanFromNow)) - 
         new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

      int startTimestamp = (int)intervalStart.TotalSeconds; // START_TIME
      int endTimestamp = (int)intervalEnd.TotalSeconds;  // END_TIME

      if (startTimestamp > endTimestamp)
         return "Error!";

      // Replace variables in the policy statement.
      strPolicy = strPolicy.Replace("RESOURCE", resourceUrl);
      strPolicy = strPolicy.Replace("START_TIME", startTimestamp.ToString());
      strPolicy = strPolicy.Replace("END_TIME", endTimestamp.ToString());
      strPolicy = strPolicy.Replace("IP_ADDRESS", ipAddress);
      strPolicy = strPolicy.Replace("EXPIRES", endTimestamp.ToString());
      return strPolicy;
   }   
}

public static TimeSpan GetDuration(string units, string numUnits)
{
   TimeSpan timeSpanInterval = new TimeSpan();
   switch (units)
   {
      case "seconds":
         timeSpanInterval = new TimeSpan(0, 0, 0, int.Parse(numUnits));
         break;
      case "minutes":
         timeSpanInterval = new TimeSpan(0, 0, int.Parse(numUnits), 0);
         break;
      case "hours":
         timeSpanInterval = new TimeSpan(0, int.Parse(numUnits), 0 ,0);
         break;
      case "days":
         timeSpanInterval = new TimeSpan(int.Parse(numUnits),0 ,0 ,0);
         break;
      default:
         Console.WriteLine("Invalid time units;" + 
            "use seconds, minutes, hours, or days");
         break;
   }
   return timeSpanInterval;
}

private static TimeSpan GetDurationByUnits(string durationUnits, 
   string startIntervalFromNow)
{
   switch (durationUnits)
   {
      case "seconds":
         return new TimeSpan(0, 0, int.Parse(startIntervalFromNow));
      case "minutes":
         return new TimeSpan(0, int.Parse(startIntervalFromNow), 0);
      case "hours":
         return new TimeSpan(int.Parse(startIntervalFromNow), 0, 0);
      case "days":
         return new TimeSpan(int.Parse(startIntervalFromNow), 0, 0, 0);
      default:
         return new TimeSpan(0, 0, 0, 0);
   }
}

public static string CopyExpirationTimeFromPolicy(string policyStatement)
{
   int startExpiration = policyStatement.IndexOf("EpochTime");
   string strExpirationRough = policyStatement.Substring(startExpiration + 
      "EpochTime".Length);
   char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
         
   List<char> listDigits = new List<char>(digits);
   StringBuilder buildExpiration = new StringBuilder(20);
         
   foreach (char c in strExpirationRough)
   {
      if (listDigits.Contains(c))
         buildExpiration.Append(c);
   }
   return buildExpiration.ToString();   
}
```

另請參閱
+ [使用 Perl 建立 URL 簽章](CreateURLPerl.md)
+ [使用 PHP 建立 URL 簽章](CreateURL_PHP.md)
+ [使用 Java 建立 URL 簽章](CFPrivateDistJavaDevelopment.md)

# 使用 Java 建立 URL 簽章
<a name="CFPrivateDistJavaDevelopment"></a>

除了下列程式碼範例之外，您還可以使用 [適用於 Java 的 AWS SDK （版本 1) 中的`CloudFrontUrlSigner`公用程式類別](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/cloudfront/CloudFrontUrlSigner.html)來建立 [CloudFront 簽章URLs](private-content-signed-urls.md)。

如需更多範例，請參閱 *AWS SDK 程式碼範例程式碼庫*中的[使用 AWS SDK 建立簽章URLs 和 Cookie](https://docs.aws.amazon.com/code-library/latest/ug/cloudfront_example_cloudfront_CloudFrontUtilities_section.html)。

**備註**  
建立簽署 URL 只是[透過 CloudFront 提供私有內容](PrivateContent.md)程序的一個環節。如需有關整個程序的詳細資訊，請參閱 [使用已簽署 URL](private-content-signed-urls.md)。
在`Signature.getInstance`通話中，請注意 `SHA1withRSA`可以取代為 `SHA256withRSA`。

**Example Java 政策和簽章加密方法**  <a name="ExampleJavaPolicyAndSignatureEncryptionMethods"></a>

```
package org.example;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import software.amazon.awssdk.services.cloudfront.CloudFrontUtilities;
import software.amazon.awssdk.services.cloudfront.model.CannedSignerRequest;
import software.amazon.awssdk.services.cloudfront.url.SignedUrl;

public class Main {

    public static void main(String[] args) throws Exception {
        CloudFrontUtilities cloudFrontUtilities = CloudFrontUtilities.create();
        Instant expirationDate = Instant.now().plus(7, ChronoUnit.DAYS);
        String resourceUrl = "https://a1b2c3d4e5f6g7.cloudfront.net";
        String keyPairId = "K1UA3WV15I7JSD";
        CannedSignerRequest cannedRequest = CannedSignerRequest.builder()
                .resourceUrl(resourceUrl)
                .privateKey(new java.io.File("/path/to/private_key.pem").toPath())
                .keyPairId(keyPairId)
                .expirationDate(expirationDate)
                .build();
        SignedUrl signedUrl = cloudFrontUtilities.getSignedUrlWithCannedPolicy(cannedRequest);
        String url = signedUrl.url();
        System.out.println(url);

    }
}
```

**Example 在 Java 中使用 SHA256 的固定政策簽署範例**  <a name="ExampleJavaPolicySHA256AndSignatureEncryptionMethods"></a>

```
package org.example;

import java.io.File;
import java.nio.file.Files;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Base64;

public class Main {

    public static void main(String[] args) throws Exception {
        String resourceUrl = "https://a1b2c3d4e5f6g7.cloudfront.net/myfile.html";
        String keyPairId = "K1UA3WV15I7JSD";
        Instant expiration = Instant.now().plus(7, ChronoUnit.DAYS);
        PrivateKey privateKey = loadPrivateKey("/path/to/private_key.der");

        System.out.println(createSignedUrl(resourceUrl, keyPairId, privateKey, expiration, "SHA1"));
        System.out.println(createSignedUrl(resourceUrl, keyPairId, privateKey, expiration, "SHA256"));
    }

    static String createSignedUrl(String resourceUrl, String keyPairId,
                                  PrivateKey privateKey, Instant expiration,
                                  String hashAlgorithm) throws Exception {
        long epochSeconds = expiration.getEpochSecond();

        String policy = "{\"Statement\":[{\"Resource\":\"" + resourceUrl
                + "\",\"Condition\":{\"DateLessThan\":{\"AWS:EpochTime\":" + epochSeconds + "}}}]}";

        String jcaAlgorithm = hashAlgorithm.equals("SHA256") ? "SHA256withRSA" : "SHA1withRSA";

        Signature sig = Signature.getInstance(jcaAlgorithm);
        sig.initSign(privateKey);
        sig.update(policy.getBytes("UTF-8"));
        String signature = base64UrlEncode(sig.sign());

        String url = resourceUrl
                + (resourceUrl.contains("?") ? "&" : "?")
                + "Expires=" + epochSeconds
                + "&Signature=" + signature
                + "&Key-Pair-Id=" + keyPairId;

        if (hashAlgorithm.equals("SHA256")) {
            url += "&Hash-Algorithm=SHA256";
        }

        return url;
    }

    static String base64UrlEncode(byte[] bytes) {
        return Base64.getEncoder().encodeToString(bytes)
                .replace('+', '-')
                .replace('=', '_')
                .replace('/', '~');
    }

    static PrivateKey loadPrivateKey(String path) throws Exception {
        byte[] keyBytes = Files.readAllBytes(new File(path).toPath());
        return KeyFactory.getInstance("RSA")
                .generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
    }
}
```

另請參閱：
+ [使用 Perl 建立 URL 簽章](CreateURLPerl.md)
+ [使用 PHP 建立 URL 簽章](CreateURL_PHP.md)
+ [使用 C\$1 和 .NET 架構建立 URL 簽章](CreateSignatureInCSharp.md)