

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

# 使用憑證和 Oracle 錢包設定 UTL\$1HTTP 存取
<a name="Oracle.Concepts.ONA"></a>

Amazon RDS 在您的 RDS for Oracle 資料庫執行個體上支援對外網路存取。若要將資料庫執行個體連線至網路，您可以使用下列 PL/SQL 套件：

`UTL_HTTP`  
此套件會從 SQL 和 PL/SQL 進行 HTTP 呼叫。您可以用其透過 HTTP 存取網際網路上的資料。如需詳細資訊，請參閱 Oracle 文件中的 [UTL\$1HTTP](https://docs.oracle.com/en/database/oracle/oracle-database/19/arpls/UTL_HTTP.html#GUID-A85D2D1F-90FC-45F1-967F-34368A23C9BB)。

`UTL_TCP`  
此套件會在 PL/SQL 中提供 TCP/IP 用戶端存取功能。此套件對於使用網際網路通訊協定和電子郵件的 PL/SQL 應用程式非常有用。如需詳細資訊，請參閱 Oracle 文件中的 [UTL\$1TCP](https://docs.oracle.com/en/database/oracle/oracle-database/19/arpls/UTL_TCP.html#GUID-348AFFE8-78B2-4217-AE73-384F46A1D292)。

`UTL_SMTP`  
此套件會提供 SMTP 命令的介面，讓用戶端能將電子郵件傳送至 SMTP 伺服器。如需詳細資訊，請參閱 Oracle 文件中的 [UTL\$1SMTP](https://docs.oracle.com/en/database/oracle/oracle-database/19/arpls/UTL_SMTP.html#GUID-F0065C52-D618-4F8A-A361-7B742D44C520)。

完成下列任務，就可以設定 `UTL_HTTP.REQUEST`，搭配執行 SSL 交握期間需要用戶端身分驗證憑證的網站使用。您也可以修改 Oracle 錢包產生命令和 `DBMS_NETWORK_ACL_ADMIN.APPEND_WALLET_ACE` 程序，為網站 `UTL_HTTP` 存取設定密碼身分驗證。如需詳細資訊，請參閱 Oracle 資料庫說明文件中的 [ DBMS\$1NETWORK\$1ACL\$1ADMIN](https://docs.oracle.com/en/database/oracle/oracle-database/21/arpls/DBMS_NETWORK_ACL_ADMIN.html)。

**注意**  
您可以針對 `UTL_SMTP` 調整下列任務，允許透過 SSL/TLS (包括 [Amazon Simple Email Service](https://aws.amazon.com/ses/)) 傳送電子郵件。

**Topics**
+ [設定 UTL\$1HTTP 存取時的考量](#utl_http-considerations)
+ [步驟 1：取得網站的根憑證](#website-root-certificate)
+ [步驟 2：建立 Oracle 錢包](#create-oracle-wallet)
+ [步驟 3：將 Oracle 錢包下載到 RDS for Oracle 執行個體](#upload-wallet-to-instance)
+ [步驟 4：授予使用者使用 Oracle 錢包的許可](#config-oracle-wallet-user)
+ [步驟 5：設定從資料庫執行個體存取網站的權限](#config-website-access)
+ [步驟 6：測試從資料庫執行個體連至網站的連線](#test_utl_http)

## 設定 UTL\$1HTTP 存取時的考量
<a name="utl_http-considerations"></a>

設定存取之前，請先考量下列事項：
+ 您可以使用 SMTP 搭配 UTL\$1MAIL 選項。如需詳細資訊，請參閱[Oracle UTL\$1MAIL](Oracle.Options.UTLMAIL.md)。
+ 遠端主機的網域名稱伺服器 (DNS) 名稱可以是以下任何項目：
  + 可公開解析。
  + Amazon RDS 資料庫執行個體的端點。
  + 可透過自訂 DNS 伺服器解析。如需更多詳細資訊，請參閱 [設定自訂 DNS 伺服器](Appendix.Oracle.CommonDBATasks.System.md#Appendix.Oracle.CommonDBATasks.CustomDNS)。
  + 相同 VPC 或對等 VPC 中 Amazon EC2 執行個體的私有 DNS 的名稱。在此情況下，請確定名稱可透過自訂 DNS 伺服器解析。或者，若要使用 Amazon 提供的 DNS，您可以在 VPC 設定中啟用 `enableDnsSupport` 屬性，並為 VPC 對等連接啟用 DNS 解析支援。如需詳細資訊，請參閱 [VPC 中的 DNS 支援](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html#vpc-dns-support)和[修改 VPC 對等連接](https://docs.aws.amazon.com/vpc/latest/peering/working-with-vpc-peering.html#modify-peering-connections)。
  + 如要安全連線到遠端 SSL/TLS 資來源，建議您建立並上傳自訂的 Oracle 錢包。通過使用 Amazon S3 與 Amazon RDS for Oracle 的功能整合，您可以將 Amazon S3 中的錢包下載到 Oracle 資料庫執行個體中。有關 Oracle Amazon S3 整合的詳細資訊，請參閱 [Amazon S3 整合](oracle-s3-integration.md)。
+ 若 Oracle SSL 選項已為個別執行個體進行設定，則您可以透過 SSL/TLS 端點來建立 Oracle 資料庫執行個體之間的資料庫連結。無需進一步設定。如需詳細資訊，請參閱[Oracle Secure Sockets Layer](Appendix.Oracle.Options.SSL.md)。

## 步驟 1：取得網站的根憑證
<a name="website-root-certificate"></a>

若要讓 RDS for Oracle 資料庫執行個體建立與網站的安全連線，請新增根 CA 憑證。Amazon RDS 使用根憑證將網站憑證簽入 Oracle 錢包。

您可以透過多種方式取得根憑證。例如，您可以執行下列動作：

1. 使用 Web 伺服器造訪受憑證保護的網站。

1. 下載用於簽署的根憑證。

對於 AWS 服務，根憑證通常位於 [Amazon 信任服務儲存庫](https://www.amazontrust.com/repository/)中。

## 步驟 2：建立 Oracle 錢包
<a name="create-oracle-wallet"></a>

建立同時包含 Web 伺服器憑證和用戶端身分驗證憑證的 Oracle 錢包。RDS Oracle 執行個體使用 Web 伺服器憑證與網站建立安全連線。網站需要用戶端憑證用於驗證 Oracle 資料庫使用者。

您可能希望設定安全連線，而不透過用戶端憑證進行身分驗證。在此情況下，可以略過以下程序中的 Java 金鑰存放區步驟。

**建立 Oracle 錢包**

1. 將根憑證和用戶端憑證放在單一目錄中，然後變更為此目錄中。

1. 將 .p12 用戶端憑證轉換為 Java 金鑰存放區。
**注意**  
如果您不透過用戶端憑證進行身分驗證，可略過此步驟。

   下列範例將名為 *client\$1certificate.p12* 的用戶端憑證轉換為 *client\$1keystore.jks* Java 金鑰存放區。這樣金鑰存放區就包含在 Oracle 錢包中。金鑰存放區密碼為 *P12PASSWORD*。

   ```
   orapki wallet pkcs12_to_jks -wallet ./client_certificate.p12 -jksKeyStoreLoc ./client_keystore.jks -jksKeyStorepwd P12PASSWORD
   ```

1. 為 Oracle 錢包建立與憑證目錄不同的目錄。

   下列範例會建立 `/tmp/wallet` 目錄。

   ```
   mkdir -p /tmp/wallet
   ```

1. 在錢包目錄中建立 Oracle 錢包。

   下列範例會將 Oracle 錢包密碼設定為 *P12PASSWORD*，此密碼與上一步中 Java 金鑰存放區使用的密碼相同。使用相同的密碼很方便，但沒有必要。`-auto_login` 參數會開啟自動登入功能，因此不需要每次存取時都指定一次密碼。
**注意**  
指定此處所顯示提示以外的密碼，作為安全最佳實務。

   ```
   orapki wallet create -wallet /tmp/wallet -pwd P12PASSWORD -auto_login
   ```

1. 將 Java 金鑰存放區新增到您的 Oracle 錢包。
**注意**  
如果您不透過用戶端憑證進行身分驗證，可略過此步驟。

   下列範例會將金鑰存放區 *client\$1keystore.jks* 新增到名為 */tmp/wallet* 的 Oracle 錢包。在此範例中，為 Java 金鑰存放區和 Oracle 錢包指定了相同的密碼。

   ```
   orapki wallet jks_to_pkcs12 -wallet /tmp/wallet -pwd P12PASSWORD -keystore ./client_keystore.jks -jkspwd P12PASSWORD
   ```

1. 將目標網站的根憑證新增至 Oracle 錢包。

   下列範例會新增名為 *Root\$1CA.cer* 的憑證。

   ```
   orapki wallet add -wallet /tmp/wallet -trusted_cert -cert ./Root_CA.cer -pwd P12PASSWORD
   ```

1. 新增任何中繼憑證。

   下列範例會新增名為 *Intermediate.cer* 的憑證。若要載入所有中繼憑證，請視需要重複此步驟。

   ```
   orapki wallet add -wallet /tmp/wallet -trusted_cert -cert ./Intermediate.cer -pwd P12PASSWORD
   ```

1. 確認新建立的 Oracle 錢包含有所需的憑證。

   ```
   orapki wallet display -wallet /tmp/wallet -pwd P12PASSWORD
   ```

## 步驟 3：將 Oracle 錢包下載到 RDS for Oracle 執行個體
<a name="upload-wallet-to-instance"></a>

在此步驟中，將 Oracle 錢包上傳到 Amazon S3，然後將錢包從 Amazon S3 下載到 RDS for Oracle 執行個體。

**將 Oracle 錢包下載到 RDS for Oracle 資料庫執行個體**

1. 完成 Amazon S3 與 Oracle 整合的必要條件，然後新增 `S3_INTEGRATION` 選項至您的 Oracle 資料庫執行個體。確保選項的 IAM 角色可存取您使用的 Amazon S3 儲存貯體。

   如需詳細資訊，請參閱[Amazon S3 整合](oracle-s3-integration.md)。

1. 以主要使用者身分登入資料庫執行個體，然後建立一個 Oracle 目錄來保存 Oracle 錢包。

   下列範例會建立名為 *WALLET\$1DIR* 的 Oracle 目錄。

   ```
   EXEC rdsadmin.rdsadmin_util.create_directory('WALLET_DIR');
   ```

   如需詳細資訊，請參閱[在主要資料儲存空間中建立和捨棄目錄](Appendix.Oracle.CommonDBATasks.Misc.md#Appendix.Oracle.CommonDBATasks.NewDirectories)。

1. 將 Oracle 錢包上傳至您的 Amazon S3 儲存貯體。

   您可以使用任何支援的上傳技術。

1. 如要重新上傳 Oracle 錢包，請刪除現有錢包。否則，跳至下一步。

   下列範例會移除名為 *cwallet.sso* 的現有錢包。

   ```
   EXEC UTL_FILE.FREMOVE ('WALLET_DIR','cwallet.sso');
   ```

1. 將 Oracle 錢包從您的 Amazon S3 儲存貯體下載至 Oracle 資料庫執行個體。

   下列範例會將名為 *cwallet.sso* 的錢包，從 Amazon S3 儲存貯體 *my\$1s3\$1bucket* 下載到資料庫執行個體目錄 *WALLET\$1DIR*。

   ```
   SELECT rdsadmin.rdsadmin_s3_tasks.download_from_s3(
         p_bucket_name    =>  'my_s3_bucket', 
         p_s3_prefix      =>  'cwallet.sso', 
         p_directory_name =>  'WALLET_DIR') 
      AS TASK_ID FROM DUAL;
   ```

1. (選用) 下載受密碼保護的 Oracle 錢包。

   只有在您想要求每次使用錢包都輸入密碼時，才需下載此錢包。下列範例會下載受密碼保護的錢包 *ewallet.p12*。

   ```
   SELECT rdsadmin.rdsadmin_s3_tasks.download_from_s3(
         p_bucket_name    =>  'my_s3_bucket', 
         p_s3_prefix      =>  'ewallet.p12', 
         p_directory_name =>  'WALLET_DIR') 
      AS TASK_ID FROM DUAL;
   ```

1. 檢查您的資料庫任務。

   下列範例中，將上述步驟傳回的任務 ID 替換為 *dbtask-1234567890123-4567.log*。

   ```
   SELECT TEXT FROM TABLE(rdsadmin.rds_file_util.read_text_file('BDUMP','dbtask-1234567890123-4567.log'));
   ```

1. 檢查用於存放 Oracle 錢包的目錄內容。

   ```
   SELECT * FROM TABLE(rdsadmin.rds_file_util.listdir(p_directory => 'WALLET_DIR'));
   ```

   如需詳細資訊，請參閱[列出資料庫執行個體目錄中的檔案](Appendix.Oracle.CommonDBATasks.Misc.md#Appendix.Oracle.CommonDBATasks.ListDirectories)。

## 步驟 4：授予使用者使用 Oracle 錢包的許可
<a name="config-oracle-wallet-user"></a>

您可以建立新的資料庫使用者或設定現有使用者。無論哪種情況，都必須為使用者設定 Oracle 錢包的存取權，以建立安全連線和使用憑證進行用戶端身分驗證。

**授予使用者使用 Oracle 錢包的許可**

1. 以主要使用者身分登入 RDS for Oracle 資料庫執行個體。

1. 如果不想設定現有的資料庫使用者，請建立一個新使用者。否則，跳至下一步。

   下列範例會建立名為 *my-user* 的資料庫使用者。

   ```
   CREATE USER my-user IDENTIFIED BY my-user-pwd;
   GRANT CONNECT TO my-user;
   ```

1. 向您的資料庫使用者授予許可，允許存取包含 Oracle 錢包的目錄。

   下列範例會為 *my-user* 使用者授予目錄 *WALLET\$1DIR* 的讀取存取權。

   ```
   GRANT READ ON DIRECTORY WALLET_DIR TO my-user;
   ```

1. 使用 `UTL_HTTP` 套件授予資料庫使用者許可。

   下列 PL/SQL 程式授予 `UTL_HTTP` 存取權給使用者 *my-user*。

   ```
   BEGIN 
     rdsadmin.rdsadmin_util.grant_sys_object('UTL_HTTP', UPPER('my-user')); 
     END;
   /
   ```

1. 使用 `UTL_FILE` 套件授予資料庫使用者許可。

   下列 PL/SQL 程式授予 `UTL_FILE` 存取權給使用者 *my-user*。

   ```
   BEGIN 
     rdsadmin.rdsadmin_util.grant_sys_object('UTL_FILE', UPPER('my-user')); 
     END;
   /
   ```

## 步驟 5：設定從資料庫執行個體存取網站的權限
<a name="config-website-access"></a>

在此步驟中，會對 Oracle 資料庫使用者進行設定，允許該使用者使用 `UTL_HTTP`、您上傳的 Oracle 錢包和用戶端憑證連線至您的目標網站。如需詳細資訊，請參閱 Oracle 資料庫說明文件中的[設定 Oracle 錢包的存取控制](https://docs.oracle.com/en/database/oracle/oracle-database/19/dbseg/managing-fine-grained-access-in-pl-sql-packages-and-types.html#GUID-0BCB5925-A40F-4507-95F9-5DA4A1919EBD)。

**設定從 RDS for Oracle 資料庫執行個體存取網站的權限**

1. 以主要使用者身分登入 RDS for Oracle 資料庫執行個體。

1. 在安全連接埠上為使用者和目標網站建立主機存取控制項目 (ACE)。

   下列範例會為 *my-user* 設定安全連接埠 443 上 *secret.encrypted-website.com* 的存取權。

   ```
   BEGIN
     DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE(
       host       => 'secret.encrypted-website.com', 
       lower_port => 443,
       upper_port => 443,
       ace        => xs$ace_type(privilege_list => xs$name_list('http'),
                                 principal_name => 'my-user',
                                 principal_type => xs_acl.ptype_db)); 
                              -- If the program unit results in PLS-00201, set
                              -- the principal_type parameter to 2 as follows:
                              -- principal_type => 2));
   END;
   /
   ```
**重要**  
上述程式單元可能會導致下列錯誤：`PLS-00201: identifier 'XS_ACL' must be declared`。如果傳回此錯誤，請將指派值給 `principal_type` 的一行取代為以下這一行，然後重新執行程式單元：  

   ```
   principal_type => 2));
   ```
若要進一步了解 PL/SQL 套件 `XS_ACL` 中的常數，請參閱 Oracle Database 文件中的 [Real Application Security 的管理員和開發人員指南](https://docs.oracle.com/en/database/oracle/oracle-database/19/dbfsg/XS_ACL-package.html#GUID-A157FB28-FE23-4D30-AAEB-8224230517E7)**。

   如需詳細資訊，請參閱 Oracle 資料庫說明文件中的[設定外部網路服務的存取控制](https://docs.oracle.com/en/database/oracle/oracle-database/19/dbseg/managing-fine-grained-access-in-pl-sql-packages-and-types.html#GUID-3D5B66BC-0277-4887-9CD1-97DB44EB5213)。

1. (選用) 為標準連接埠上的使用者和目標網站建立 ACE。

   如果某些網頁是從標準 Web 伺服器連接埠 (80) 而不是安全連接埠 (443) 提供的，可能需要使用標準連接埠。

   ```
   BEGIN
     DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE(
       host       => 'secret.encrypted-website.com', 
       lower_port => 80,
       upper_port => 80,
       ace        => xs$ace_type(privilege_list => xs$name_list('http'),
                                 principal_name => 'my-user',
                                 principal_type => xs_acl.ptype_db)); 
                              -- If the program unit results in PLS-00201, set
                              -- the principal_type parameter to 2 as follows:
                              -- principal_type => 2));
   END;
   /
   ```

1. 確認存取控制項目存在。

   ```
   SET LINESIZE 150
   COLUMN HOST FORMAT A40
   COLUMN ACL FORMAT A50
   
   SELECT HOST, LOWER_PORT, UPPER_PORT, ACL
     FROM DBA_NETWORK_ACLS
   ORDER BY HOST;
   ```

1. 使用 `UTL_HTTP` 套件授予資料庫使用者許可。

   下列 PL/SQL 程式授予 `UTL_HTTP` 存取權給使用者 *my-user*。

   ```
   BEGIN 
     rdsadmin.rdsadmin_util.grant_sys_object('UTL_HTTP', UPPER('my-user')); 
     END;
   /
   ```

1. 確認相關的存取控制清單存在。

   ```
   SET LINESIZE 150
   COLUMN ACL FORMAT A50
   COLUMN PRINCIPAL FORMAT A20
   COLUMN PRIVILEGE FORMAT A10
   
   SELECT ACL, PRINCIPAL, PRIVILEGE, IS_GRANT,
          TO_CHAR(START_DATE, 'DD-MON-YYYY') AS START_DATE,
          TO_CHAR(END_DATE, 'DD-MON-YYYY') AS END_DATE
     FROM DBA_NETWORK_ACL_PRIVILEGES
   ORDER BY ACL, PRINCIPAL, PRIVILEGE;
   ```

1. 授予資料庫使用者許可，允許使用憑證進行用戶端身分驗證，並授予 Oracle 錢包進行連線的許可。
**注意**  
如果您不透過用戶端憑證進行身分驗證，可略過此步驟。

   ```
   DECLARE
     l_wallet_path all_directories.directory_path%type;
   BEGIN
     SELECT DIRECTORY_PATH 
       INTO l_wallet_path 
       FROM ALL_DIRECTORIES
      WHERE UPPER(DIRECTORY_NAME)='WALLET_DIR';
     DBMS_NETWORK_ACL_ADMIN.APPEND_WALLET_ACE(
       wallet_path => 'file:/' || l_wallet_path,
       ace         =>  xs$ace_type(privilege_list => xs$name_list('use_client_certificates'),
                                   principal_name => 'my-user',
                                   principal_type => xs_acl.ptype_db));
   END;
   /
   ```

## 步驟 6：測試從資料庫執行個體連至網站的連線
<a name="test_utl_http"></a>

在此步驟中，會對資料庫使用者進行設定，允許該使用者使用 `UTL_HTTP`、您上傳的 Oracle 錢包和用戶端憑證連線至您的網站。

**設定從 RDS for Oracle 資料庫執行個體存取網站的權限**

1. 以具有 `UTL_HTTP` 許可的資料庫使用者身分登入 RDS on Oracle 資料庫執行個體。

1. 確認連至目標網站的連線可以解析主機地址。

   下列範例會從 *secret.encrypted-website.com* 取得主機地址。

   ```
   SELECT UTL_INADDR.GET_HOST_ADDRESS(host => 'secret.encrypted-website.com')
     FROM DUAL;
   ```

1. 測試失敗的連線。

   以下查詢失敗，因為 `UTL_HTTP` 需要含有憑證的 Oracle 錢包的所在位置。

   ```
   SELECT UTL_HTTP.REQUEST('secret.encrypted-website.com') FROM DUAL;
   ```

1. 使用 `UTL_HTTP.SET_WALLET` 並從 `DUAL` 中選取來測試網站存取情況。

   ```
   DECLARE
     l_wallet_path all_directories.directory_path%type;
   BEGIN
     SELECT DIRECTORY_PATH
       INTO l_wallet_path 
       FROM ALL_DIRECTORIES
      WHERE UPPER(DIRECTORY_NAME)='WALLET_DIR';
     UTL_HTTP.SET_WALLET('file:/' || l_wallet_path);
   END;
   /
   
   SELECT UTL_HTTP.REQUEST('secret.encrypted-website.com') FROM DUAL;
   ```

1. (選用) 將查詢儲存在變數中並使用 `EXECUTE IMMEDIATE` 來測試網站存取情況。

   ```
   DECLARE
     l_wallet_path all_directories.directory_path%type;
     v_webpage_sql VARCHAR2(1000);
     v_results     VARCHAR2(32767);
   BEGIN
     SELECT DIRECTORY_PATH
       INTO l_wallet_path 
       FROM ALL_DIRECTORIES
      WHERE UPPER(DIRECTORY_NAME)='WALLET_DIR';
     v_webpage_sql := 'SELECT UTL_HTTP.REQUEST(''secret.encrypted-website.com'', '''', ''file:/' ||l_wallet_path||''') FROM DUAL';
     DBMS_OUTPUT.PUT_LINE(v_webpage_sql);
     EXECUTE IMMEDIATE v_webpage_sql INTO v_results;
     DBMS_OUTPUT.PUT_LINE(v_results);
   END;
   /
   ```

1. (選用) 尋找 Oracle 錢包目錄的檔案系統位置。

   ```
   SELECT * FROM TABLE(rdsadmin.rds_file_util.listdir(p_directory => 'WALLET_DIR'));
   ```

   使用上一個命令的輸出執行 HTTP 請求。例如，如果目錄為 *rdsdbdata/userdirs/01*，請執行下列查詢。

   ```
   SELECT UTL_HTTP.REQUEST('https://secret.encrypted-website.com/', '', 'file://rdsdbdata/userdirs/01') 
   FROM   DUAL;
   ```