すべてのプロダクト
Search
ドキュメントセンター

Object Storage Service:直接アップロードのサーバー側署名

最終更新日:Sep 02, 2026

PostObject 操作では、Web クライアントから Object Storage Service (OSS) にファイルを直接アップロードできます。 また、サーバーで生成された署名をセキュリティに使用し、ビジネス要件に基づいてアップロードを制限するポリシーを設定することもできます。

ソリューションの概要

image

サーバー側の署名による直接アップロードを実装するには、次の 3 つの手順に従ってください:

説明

一時的なアクセス認証情報を使用すると、サーバーの長期キーの漏洩を防ぎ、ファイルアップロードのセキュリティを強化できます。

  1. OSS の設定:コンソールでユーザーファイルを格納するバケットを作成します。次に、Web クライアントからのクロスオリジンリクエストを許可するように、バケットのクロスオリジンリソース共有 (CORS) ルールを設定します。

  2. サーバーの設定:Security Token Service (STS) を呼び出して、一時的なアクセス認証情報を取得します。次に、この認証情報とサーバー側のアップロードポリシーを使用して署名を生成します。このポリシーには、バケット名、ディレクトリパス、有効期限などのパラメーターが含まれます。この署名により、ユーザーは指定された期間、ファイルをアップロードできます。

  3. Web クライアントの設定:HTML フォームリクエストを作成し、署名を使用してファイルを OSS にアップロードします。

サンプルプロジェクト

手順

ステップ 1:OSS の設定

バケットの作成

Web ブラウザーから直接アップロードされたファイルを格納する OSS バケットを作成します。

  1. OSS コンソールにログインします。

  2. ナビゲーションウィンドウで、バケットバケットの作成 の順にクリックします。

  3. バケットの作成 パネルで、[クイック作成] を選択し、次のパラメーターを設定します。

    パラメーター

    サンプル値

    [バケット名]

    web-direct-upload

    [リージョン]

    中国 (杭州)

  4. OK をクリックします。

CORS ルールの設定

OSS バケットに CORS ルールを設定します。

  1. バケットページで、対象のバケットをクリックします。

  2. クロスオリジンリソース共有の設定 ページで、ルールの作成 をクリックします。

  3. ルールの作成 パネルで、次のパラメーターを設定します。

    パラメーター

    サンプル値

    [ソース]

    *

    [許可されたメソッド]

    POST、PUT、GET

    [許可されたヘッダー]

    *

  1. OK をクリックします。

ステップ 2:サーバーの設定

説明

本番デプロイでは、すでにサーバーがある場合、準備は省略し、直接 1. ユーザー権限の設定 に進んでください。

ECS インスタンスの作成

ステップ 1:ECS インスタンスの作成

カスタム起動 ページに移動し、Elastic Compute Service (ECS) インスタンスの作成に必要な基本リソースを選択します。

  1. リージョンと課金方法の選択

    1. ビジネス要件に基づいて課金方法を選択します。このチュートリアルでは、柔軟性の高い [従量課金] モードを使用します。

    2. 一般的に、ユーザーに近いリージョンを選択すると、ネットワーク遅延が短縮され、アクセスが高速になります。このチュートリアルでは、[中国 (杭州)] を例として使用します。

      課金方法では、[従量課金] (後払い、オンデマンド) を選択します。従量課金のインスタンスは ICP 申請をサポートしていません。インスタンス作成後、インスタンスのリージョンは変更できません。異なるリージョンのインスタンスは、内部ネットワーク経由で通信できません。

  1. Virtual Private Cloud (VPC) と vSwitch の作成

    VPC を作成する際、ECS インスタンスと同じリージョンを選択し、ビジネス要件に基づいて CIDR ブロックを計画します。このチュートリアルでは、[中国 (杭州)] リージョンでの VPC と vSwitch の作成を例として使用します。VPC と vSwitch を作成した後、ECS 購入ページに戻り、ページを更新して VPC と vSwitch を選択します。

    説明

    VPC を作成する際に vSwitch を作成できます。

    VPC の作成ページで、名前を ProjectA-VPC に設定し、IPv4 CIDR ブロックでは [IPv4 CIDR ブロックを手動で指定] を選択して 192.168.0.0/16 を入力し、IPv6 CIDR ブロックでは [割り当てない] を選択します。

    vSwitch の設定例:名前を ProjectA-vSwitch に設定し、ゾーンでは [杭州ゾーン H] を選択し、IPv4 CIDR ブロックを 192.168.10.0/24 に設定してから [OK] をクリックします。

  1. インスタンスタイプとイメージの選択

    インスタンスタイプとイメージを選択します。イメージによって、インスタンスにインストールされるオペレーティングシステムとバージョンが決まります。このチュートリアルでは、コストパフォーマンスが高く、テスト要件を満たす ecs.e-c1m1.large インスタンスタイプを使用します。イメージは Alibaba Cloud Linux 3.2104 LTS 64 ビット パブリックイメージです。

  1. ストレージの設定

    このチュートリアルのシンプルな Web システムでは、オペレーティングシステム用にシステムディスクがあれば十分なため、データディスクは不要です。

    システムディスクでは、[ESSD] を選択し、パフォーマンスレベルを [PL0]、容量を 40 GiB に設定し、[インスタンスと共にリリース] を選択して、データディスクは追加しません。

  1. パブリック IP アドレスの割り当て

    簡単にするため、このチュートリアルではパブリック IP アドレスをインスタンスに直接割り当てます。または、インスタンスを作成した後に Elastic IP Address (EIP) をインスタンスに関連付けることもできます。詳細については、「クラウドリソースへの EIP の関連付け」をご参照ください。

    説明
    • パブリック IP アドレスが割り当てられていない場合、SSH またはリモートデスクトッププロトコル (RDP) を使用してインターネットからインスタンスに直接アクセスすることはできず、インスタンス上の Web サービスのデプロイを検証することもできません。

    • このチュートリアルでは、帯域幅課金方法として [トラフィック課金] を使用します。この方法では、消費したパブリックトラフィックに対してのみ課金されます。詳細については、「パブリック帯域幅の課金」をご参照ください。

    ピーク帯域幅5 Mbps に設定します。

  1. セキュリティグループの作成

    インスタンスのセキュリティグループを作成します。セキュリティグループは、ECS インスタンスのインバウンドおよびアウトバウンドトラフィックを制御する仮想ファイアウォールです。セキュリティグループを作成する際、後で ECS インスタンスにアクセスできるように、次のポートでの通信を許可します。

    ポート範囲:SSH (22)、HTTP (80)、および HTTPS (443)。

    説明
    • ポート範囲で選択したポートは、ECS インスタンスで実行されているアプリケーションに必要です。

    • デフォルトでは、ここで作成するセキュリティグループには、送信元を 0.0.0.0/0 に設定するルールが含まれています。これにより、任意の IP アドレスから指定されたポートへのアクセスが許可されます。リクエスト元のクライアントの IP アドレスがわかっている場合は、後で送信元を特定の IP 範囲に制限することを推奨します。詳細については、「セキュリティグループルールの変更」をご参照ください。

    セキュリティグループタイプ セクションで、[基本セキュリティグループ] を選択します。

  1. キーペアの作成

    1. キーペアは、安全なログイン認証情報を提供します。キーペアを作成した後、その秘密鍵をダウンロードする必要があります。これは ECS インスタンスへの接続 に必要です。次に、ECS 購入ページに戻り、ページを更新してキーペアを選択します。

    2. root ユーザーはオペレーティングシステムで最高の権限を持っており、ログイン名として root を使用するとセキュリティリスクを引き起こす可能性があります。ログイン名として ecs-user を使用することを推奨します。

      説明

      キーペアを作成すると、秘密鍵が自動的にダウンロードされます。ブラウザのダウンロード履歴から .pem 秘密鍵ファイルを保存してください。

      ログイン認証情報 セクションで、[キーペア] タブを選択し、[キーペアの作成] をクリックします。次に、[キーペア] ドロップダウンリストから、新しく作成したキーペア (例:ecs-test) を選択します。

  1. ECS インスタンスの作成と表示

    ECS インスタンスに必要なリソースを選択した後、[オーダーの作成] をクリックします。成功ダイアログボックスで、[マネジメントコンソール] をクリックして新しいインスタンスを表示します。後で使用するために、次の情報を控えておいてください:

    • インスタンス ID:インスタンスリストでインスタンスを見つけるために使用します。

    • リージョン:インスタンスリストでインスタンスを見つけるために使用します。

    • パブリック IP アドレス:Web サービスのデプロイを検証するために使用します。

ステップ 2:ECS インスタンスへの接続

  1. ECS コンソールインスタンス ページで、リージョンと ID を使用してインスタンスを検索し、[操作] 列の 接続 をクリックします。

  2. リモート接続 ダイアログボックスで、ワークベンチ の横にある 今すぐサインイン をクリックします。

  3. インスタンスへのログオン ダイアログボックスで、接続方法では [ターミナル接続] を、認証方法では [SSH キー認証] を選択します。次に、秘密鍵ファイルを入力またはアップロードし、[ログオン] をクリックして ecs-user ユーザーとして接続します。

  4. 説明

    秘密鍵ファイル (.pem) は、キーペアを作成する際にデバイスに自動的にダウンロードされます。ブラウザのダウンロード履歴を確認してファイルを見つけてください。

  5. 次の出力が表示されたら、ECS インスタンスへのログオンに成功しています。

    Welcome to Alibaba Cloud Elastic Compute Service !
    Last login: Sun Sep 29 15:35:22 2024 from xxx
    [ecs-user@iz*** ~]$

ユーザー権限

説明

デプロイメント後に権限不足により OSS へのアップロードが失敗するのを防ぐため、RAM ユーザーを作成し、必要な権限を設定してください。

ステップ 1:RAM ユーザーの作成

RAM ユーザーを作成し、そのアクセスキーペアを取得して、アプリケーションサーバーの長期的な認証情報として使用します。

  1. Alibaba Cloud アカウントまたは RAM 管理者として RAM コンソールにログオンします。

  2. 左側のナビゲーションペインで、[ID] > [ユーザー] を選択します。

  3. [ユーザーの作成] をクリックします。

  4. [ログイン名][表示名] を入力します。

  5. アクセスモード セクションで、[プログラムによるアクセス] を選択し、[OK] をクリックします。

重要

AccessKey シークレットは作成時にのみ表示され、後から取得することはできません。安全に保管してください。

  1. [操作] 列で [コピー] をクリックして、アクセスキーペア (AccessKey ID と AccessKey シークレット) を保存します。

ステップ 2:AssumeRole 権限の付与

RAM ユーザーを作成したら、STS の AssumeRole API を呼び出す権限を付与します。これにより、ユーザーは RAM ロールを引き受けることで一時的な認証情報を取得できます。

  1. 左側のナビゲーションペインで、[ID] > [ユーザー] を選択します。

  2. [ユーザー] ページで、対象の RAM ユーザーを見つけ、[操作] 列の [権限の追加] をクリックします。

  3. [権限の付与] ページで、[AliyunSTSAssumeRoleAccess] システムポリシーを選択します。

    説明

    [AliyunSTSAssumeRoleAccess] ポリシーは AssumeRole API を呼び出す権限を付与します。OSS リクエストなど、一時的な認証情報を使用する後続の操作に対する権限は付与しません。

  4. 権限を付与 をクリックします。

ステップ 3:RAM ロールの作成

現在の Alibaba Cloud アカウント用に RAM ロールを作成し、その Alibaba Cloud リソースネーム (ARN) を取得します。RAM ユーザーはこのロールを引き受けます。

  1. 左側のナビゲーションペインで、[ID] > [ロール] を選択します。

  2. [ロールの作成] をクリックします。[プリンシパルタイプ] には、[Alibaba Cloud アカウント] を選択します。

  3. 現在の Alibaba Cloud アカウントを選択し、[OK] をクリックします。

  4. ロール名を入力し、[OK] をクリックします。

  5. RAM ロールの詳細ページで、[コピー] をクリックしてロールの ARN を保存します。

ステップ 4:ファイルアップロードポリシーの作成

最小権限の原則に従い、特定の OSS バケットへのアップロードを制限するカスタムポリシーを RAM ロール用に作成します。

  1. 左側のナビゲーションペインで、[権限] > [ポリシー] を選択します。

  2. [ポリシーの作成] をクリックします。

  3. [ポリシーの作成] ページで、JSON をクリックし、スクリプト内の <BucketName> を、準備セクションで作成したバケット名(web-direct-upload)に置き換えます。

    {
      "Version": "1",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": "oss:PutObject",
          "Resource": "acs:oss:*:*:<BucketName>/*"
        }
      ]
    }
  4. ポリシーを設定した後、[OK] をクリックします。

  5. [ポリシーの作成] ダイアログボックスで、[ポリシー名] を入力し、[OK] をクリックします。

ステップ 5:RAM ロールへの権限付与

作成したカスタムポリシーを RAM ロールに付与します。これにより、引き受けたロールに必要な権限が与えられます。

  1. 左側のナビゲーションペインで、[ID] > [ロール] を選択します。

  2. [ロール] ページで、対象の RAM ロールを見つけ、[操作] 列の [権限の追加] をクリックします。

  3. [権限の付与] ページで、[カスタムポリシー] を選択してから、作成したポリシーを選択します。

  4. [OK] をクリックします。

サーバー側の署名

説明

AccessKey IDAccessKey SecretRole ARN などの機密情報は、環境変数として設定することをお勧めします。これにより、コードへのハードコーディングを回避し、認証情報漏洩のリスクを低減できます。

次の手順に従って、環境変数を設定します。

Linux

  1. コマンドラインから、次のコマンドを実行して、環境変数の設定を~/.bashrc ファイルに追記します。

    echo "export OSS_ACCESS_KEY_ID='your-access-key-id'" >> ~/.bashrc
    echo "export OSS_ACCESS_KEY_SECRET='your-access-key-secret'" >> ~/.bashrc
    echo "export OSS_STS_ROLE_ARN='your-role-arn'" >> ~/.bashrc
  2. 次のコマンドを実行して、変更を適用します。

    source ~/.bashrc
  3. 次のコマンドを実行して、環境変数が設定されていることを確認します。

    echo $OSS_ACCESS_KEY_ID
    echo $OSS_ACCESS_KEY_SECRET
    echo $OSS_STS_ROLE_ARN

macOS

  1. ターミナルで、次のコマンドを実行して、デフォルトのシェルを確認します。

    echo $SHELL
  2. デフォルトのシェルに応じて、次の手順に従います。

    Zsh

    1. 次のコマンドを実行して、環境変数の設定を ~/.zshrc ファイルに追記します。

      echo "export OSS_ACCESS_KEY_ID='your-access-key-id'" >> ~/.zshrc
      echo "export OSS_ACCESS_KEY_SECRET='your-access-key-secret'" >> ~/.zshrc
      echo "export OSS_STS_ROLE_ARN='your-role-arn'" >> ~/.zshrc
    2. 次のコマンドを実行して、変更を適用します。

      source ~/.zshrc
    3. 次のコマンドを実行して、環境変数が設定されていることを確認します。

      echo $OSS_ACCESS_KEY_ID
      echo $OSS_ACCESS_KEY_SECRET
      echo $OSS_STS_ROLE_ARN

    Bash

    1. 次のコマンドを実行して、環境変数の設定を ~/.bash_profile ファイルに追記します。

      echo "export OSS_ACCESS_KEY_ID='your-access-key-id'" >> ~/.bash_profile
      echo "export OSS_ACCESS_KEY_SECRET='your-access-key-secret'" >> ~/.bash_profile
      echo "export OSS_STS_ROLE_ARN='your-role-arn'" >> ~/.bash_profile
    2. 次のコマンドを実行して、変更を適用します。

      source ~/.bash_profile
    3. 次のコマンドを実行して、環境変数が設定されていることを確認します。

      echo $OSS_ACCESS_KEY_ID
      echo $OSS_ACCESS_KEY_SECRET
      echo $OSS_STS_ROLE_ARN

Windows

  1. コマンドプロンプト (CMD) で次のコマンドを実行します。

    setx OSS_ACCESS_KEY_ID "your-access-key-id"
    setx OSS_ACCESS_KEY_SECRET "your-access-key-secret"
    setx OSS_STS_ROLE_ARN "your-role-arn"
  2. 新しい CMD ウィンドウを開きます。

  3. 新しい CMD ウィンドウで、次のコマンドを実行して、環境変数が設定されていることを確認します。

    echo %OSS_ACCESS_KEY_ID%
    echo %OSS_ACCESS_KEY_SECRET%
    echo %OSS_STS_ROLE_ARN%

次のサンプルコードを使用して、署名バージョン 4 (推奨) でサーバー上の POST 署名を計算します。policy フォームフィールドの設定の詳細については、policy フォームフィールドをご参照ください。

Java

Maven プロジェクトに次の依存関係を追加します。

<!-- https://mvnrepository.com/artifact/com.aliyun/credentials-java -->
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.17.4</version>
</dependency>
<dependency>
  <groupId>com.aliyun</groupId>
  <artifactId>sts20150401</artifactId>
  <version>1.1.6</version>
</dependency>

次のサンプルコードは、一時的なアクセス認証情報を取得し、サーバー上で POST 署名を計算する方法を示しています。

package com.aliyun.oss.web;
import com.aliyun.sts20150401.models.AssumeRoleResponse;
import com.aliyun.sts20150401.models.AssumeRoleResponseBody;
import com.aliyun.tea.TeaException;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.binary.Base64;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
@Controller
public class WebController {
    // OSS の基本情報:実際のバケット名、リージョン ID、ホストに置き換えてください。
    String bucket = "examplebucket";
    String region = "cn-hangzhou";
    String host = "http://examplebucket.oss-cn-hangzhou.aliyuncs.com";
    // アップロードコールバック URL を設定します。これはコールバックサーバーのアドレスです。これはパブリック URL である必要があります。OSS はこの URL を使用して、オブジェクトのアップロード情報をアプリケーションサーバーに送信します。
    // OSS にアップロードされるオブジェクトのプレフィックス (ディレクトリ)。
    String upload_dir = "dir";
    // 有効期限 (秒単位):
    Long expire_time = 3600L;
    /**
     * 指定された秒数に基づいて有効期限を生成します。
     * @param seconds 秒数。
     * @return ISO 8601 時刻文字列、例: "2014-12-01T12:00:00.000Z"。
     */
    public static String generateExpiration(long seconds) {
        // 現在のタイムスタンプ (秒単位) を取得します。
        long now = Instant.now().getEpochSecond();
        // 有効期限のタイムスタンプを計算します。
        long expirationTime = now + seconds;
        // タイムスタンプを Instant オブジェクトに変換し、ISO 8601 にフォーマットします。
        Instant instant = Instant.ofEpochSecond(expirationTime);
        // タイムゾーンを UTC として定義します。
        ZoneId zone = ZoneOffset.UTC;  
        // Instant を ZonedDateTime に変換します。
        ZonedDateTime zonedDateTime = instant.atZone(zone);
        // 日時フォーマットを定義します。例: 2023-12-03T13:00:00.000Z。
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        // 日時をフォーマットします。
        String formattedDate = zonedDateTime.format(formatter);
        // 結果を返します。
        return formattedDate;
    }
    // STS クライアントを初期化します。
    public static com.aliyun.sts20150401.Client createStsClient() throws Exception {
        // アクセスキーペアのハードコーディングはセキュリティリスクがあり、推奨されません。このコードは参考用です。
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
                // 必須:コードの実行環境で OSS_ACCESS_KEY_ID 環境変数が設定されていることを確認してください。
                .setAccessKeyId(System.getenv("OSS_ACCESS_KEY_ID"))
                // 必須:コードの実行環境で OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
                .setAccessKeySecret(System.getenv("OSS_ACCESS_KEY_SECRET"));
        // エンドポイントの詳細については、https://api.alibabacloud.com/product/Sts をご参照ください。
        config.endpoint = "sts.cn-hangzhou.aliyuncs.com";
        return new com.aliyun.sts20150401.Client(config);
    }
    /**
     * STS 一時的な認証情報を取得します。
     * @return AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials オブジェクト。
     */
    public static AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials getCredential() throws Exception {
        com.aliyun.sts20150401.Client client = WebController.createStsClient();
        com.aliyun.sts20150401.models.AssumeRoleRequest assumeRoleRequest = new com.aliyun.sts20150401.models.AssumeRoleRequest()
                // 必須:コードの実行環境で OSS_STS_ROLE_ARN 環境変数が設定されていることを確認してください。
                .setRoleArn(System.getenv("OSS_STS_ROLE_ARN"))
                .setRoleSessionName("yourRoleSessionName");// カスタムセッション名:
        com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
        try {
            // このコードをコピーして実行する場合は、API の戻り値を出力してください。
            AssumeRoleResponse response = client.assumeRoleWithOptions(assumeRoleRequest, runtime);
            // credentials オブジェクトには、AccessKeyId、AccessKeySecret、および SecurityToken が含まれています。
            return response.body.credentials;
        } catch (TeaException error) {
            // これはデモンストレーション用です。例外は慎重に処理し、プロジェクトでは無視しないでください。
            // エラーメッセージ
            System.out.println(error.getMessage());
            // 診断アドレス
            System.out.println(error.getData().get("Recommend"));
            com.aliyun.teautil.Common.assertAsString(error.message);
        }
        // null を返さないように、デフォルトのエラーレスポンスオブジェクトを返します。
        AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials defaultCredentials = new AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials();
        defaultCredentials.accessKeyId = "ERROR_ACCESS_KEY_ID";
        defaultCredentials.accessKeySecret = "ERROR_ACCESS_KEY_SECRET";
        defaultCredentials.securityToken = "ERROR_SECURITY_TOKEN";
        return defaultCredentials;
    }
    @GetMapping("/get_post_signature_for_oss_upload")
    public ResponseEntity<Map<String, String>> getPostSignatureForOssUpload() throws Exception {
        AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials sts_data = getCredential();
        String accesskeyid =  sts_data.accessKeyId;
        String accesskeysecret =  sts_data.accessKeySecret;
        String securitytoken =  sts_data.securityToken;
       // x-oss-credential の日付を取得します。これは yyyyMMdd 形式の現在の日付です。
        ZonedDateTime today = ZonedDateTime.now().withZoneSameInstant(java.time.ZoneOffset.UTC);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String date = today.format(formatter);
        // x-oss-date を取得します。
        ZonedDateTime now = ZonedDateTime.now().withZoneSameInstant(java.time.ZoneOffset.UTC);
        DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");
        String x_oss_date = now.format(formatter2);
        // ステップ 1:ポリシーを作成します。
        String x_oss_credential = accesskeyid + "/" + date + "/" + region + "/oss/aliyun_v4_request";
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> policy = new HashMap<>();
        policy.put("expiration", generateExpiration(expire_time));
        List<Object> conditions = new ArrayList<>();
        Map<String, String> bucketCondition = new HashMap<>();
        bucketCondition.put("bucket", bucket);
        conditions.add(bucketCondition);
        Map<String, String> securityTokenCondition = new HashMap<>();
        securityTokenCondition.put("x-oss-security-token", securitytoken);
        conditions.add(securityTokenCondition);
        Map<String, String> signatureVersionCondition = new HashMap<>();
        signatureVersionCondition.put("x-oss-signature-version", "OSS4-HMAC-SHA256");
        conditions.add(signatureVersionCondition);
        Map<String, String> credentialCondition = new HashMap<>();
        credentialCondition.put("x-oss-credential", x_oss_credential); // 実際の AccessKey ID に置き換えてください。
        conditions.add(credentialCondition);
        Map<String, String> dateCondition = new HashMap<>();
        dateCondition.put("x-oss-date", x_oss_date);
        conditions.add(dateCondition);
        conditions.add(Arrays.asList("content-length-range", 1, 10240000));
        conditions.add(Arrays.asList("eq", "$success_action_status", "200"));
        conditions.add(Arrays.asList("starts-with", "$key", upload_dir));
        policy.put("conditions", conditions);
        String jsonPolicy = mapper.writeValueAsString(policy);
        // ステップ 2:署名対象の文字列を構築します。
        String stringToSign = new String(Base64.encodeBase64(jsonPolicy.getBytes()));
        // System.out.println("stringToSign: " + stringToSign);
        // ステップ 3:署名キーを計算します。
        byte[] dateKey = hmacsha256(("aliyun_v4" + accesskeysecret).getBytes(), date);
        byte[] dateRegionKey = hmacsha256(dateKey, region);
        byte[] dateRegionServiceKey = hmacsha256(dateRegionKey, "oss");
        byte[] signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request");
        // System.out.println("signingKey: " + BinaryUtil.toBase64String(signingKey));
        // ステップ 4:署名を計算します。
        byte[] result = hmacsha256(signingKey, stringToSign);
        String signature = BinaryUtil.toHex(result);
        // System.out.println("signature:" + signature);
        Map<String, String> response = new HashMap<>();
        // データをマップに追加します。
        response.put("version", "OSS4-HMAC-SHA256");
        response.put("policy", stringToSign);
        response.put("x_oss_credential", x_oss_credential);
        response.put("x_oss_date", x_oss_date);
        response.put("signature", signature);
        response.put("security_token", securitytoken);
        response.put("dir", upload_dir);
        response.put("host", host);
        // PostObject API 用の Web クライアントに、ステータスコード 200 (OK) の ResponseEntity を返します。
        return ResponseEntity.ok(response);
    }
    public static byte[] hmacsha256(byte[] key, String data) {
        try {
            // HmacSHA256 キー仕様を初期化します。
            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacSHA256");
            // HmacSHA256 Mac インスタンスを取得します。
            Mac mac = Mac.getInstance("HmacSHA256");
            // キーを使用して Mac オブジェクトを初期化します。
            mac.init(secretKeySpec);
            // データの HMAC 署名を計算します。
            byte[] hmacBytes = mac.doFinal(data.getBytes());
            return hmacBytes;
        } catch (Exception e) {
            throw new RuntimeException("Failed to calculate HMAC-SHA256", e);
        }
    }
}

Python

次のコマンドを実行して、依存関係をインストールします。

pip install flask
pip install alibabacloud_tea_openapi alibabacloud_sts20150401 alibabacloud_credentials

次のサンプルコードは、一時的なアクセス認証情報 (STS トークン) を取得し、アップロードポリシーを構築し、サーバー上で POST 署名を計算する方法を示しています。

from flask import Flask, render_template, jsonify
from alibabacloud_tea_openapi.models import Config
from alibabacloud_sts20150401.client import Client as Sts20150401Client
from alibabacloud_sts20150401 import models as sts_20150401_models
from alibabacloud_credentials.client import Client as CredentialClient
import os
import json
import base64
import hmac
import datetime
import time
import hashlib
app = Flask(__name__)
# OSS_ACCESS_KEY_ID、OSS_ACCESS_KEY_SECRET、および OSS_STS_ROLE_ARN 環境変数を設定してください。
access_key_id = os.environ.get('OSS_ACCESS_KEY_ID')
access_key_secret = os.environ.get('OSS_ACCESS_KEY_SECRET')
role_arn_for_oss_upload = os.environ.get('OSS_STS_ROLE_ARN')
# カスタムセッション名:
role_session_name = 'yourRoleSessionName'  
# 実際のバケット名、リージョン ID、ホストに置き換えてください。
bucket = 'examplebucket'
region_id = 'cn-hangzhou'
host = 'http://examplebucket.oss-cn-hangzhou.aliyuncs.com'
# 有効期限 (秒単位):
expire_time = 3600  
# OSS にアップロードされるオブジェクトのプレフィックス (ディレクトリ)。
upload_dir = 'dir'
def hmacsha256(key, data):
    """
    HMAC-SHA256 ハッシュ値を計算します。
    :param key: ハッシュを計算するためのキー (バイト単位)。
    :param data: ハッシュ化されるデータ (文字列)。
    :return: 計算された HMAC-SHA256 ハッシュ値 (バイト単位)。
    """
    try:
        mac = hmac.new(key, data.encode(), hashlib.sha256)
        hmacBytes = mac.digest()
        return hmacBytes
    except Exception as e:
        raise RuntimeError(f"Failed to calculate HMAC-SHA256 due to {e}")
@app.route("/")
def hello_world():
    return render_template('index.html')
@app.route('/get_post_signature_for_oss_upload', methods=['GET'])
def generate_upload_params():
    # 設定を初期化し、認証情報を直接渡します。
    config = Config(
        region_id=region_id,
        access_key_id=access_key_id,
        access_key_secret=access_key_secret
    )
    # STS クライアントを作成し、一時的な認証情報を取得します。
    sts_client = Sts20150401Client(config=config)
    assume_role_request = sts_20150401_models.AssumeRoleRequest(
        role_arn=role_arn_for_oss_upload,
        role_session_name=role_session_name
    )
    response = sts_client.assume_role(assume_role_request)
    token_data = response.body.credentials.to_map()
    # STS によって返された一時的な認証情報を使用します。
    temp_access_key_id = token_data['AccessKeyId']
    temp_access_key_secret = token_data['AccessKeySecret']
    security_token = token_data['SecurityToken']
    now = int(time.time())
    # タイムスタンプを datetime オブジェクトに変換します。
    dt_obj = datetime.datetime.utcfromtimestamp(now)
    # 現在の時刻に expire_time (秒) を追加して、リクエストの有効期限を設定します。
    expiration_dt_obj = dt_obj + datetime.timedelta(seconds=expire_time)
    # リクエスト時刻。
    dt_obj_1 = dt_obj.strftime('%Y%m%dT%H%M%S') + 'Z'
    # リクエスト日付。
    dt_obj_2 = dt_obj.strftime('%Y%m%d')
    # リクエストの有効期限。
    expiration_time = expiration_dt_obj.strftime('%Y-%m-%dT%H:%M:%S.000Z')
    # ポリシーを構築し、署名を生成します。
    policy = {
        "expiration": expiration_time,
        "conditions": [
            {"bucket": bucket},
            ["starts-with", "$key", upload_dir],
            ["content-length-range", 0, 10240000],
            ["eq", "$success_action_status", "200"],
            {"x-oss-signature-version": "OSS4-HMAC-SHA256"},
            {"x-oss-credential": f"{temp_access_key_id}/{dt_obj_2}/{region_id}/oss/aliyun_v4_request"},
            {"x-oss-security-token": security_token},
            {"x-oss-date": dt_obj_1},
        ]
    }
    print(dt_obj_1)
    policy_str = json.dumps(policy).strip()
    # ステップ 2:署名対象の文字列を構築します。
    stringToSign = base64.b64encode(policy_str.encode()).decode()
    # ステップ 3:署名キーを計算します。
    dateKey = hmacsha256(("aliyun_v4" + temp_access_key_secret).encode(), dt_obj_2)
    dateRegionKey = hmacsha256(dateKey, region_id)
    dateRegionServiceKey = hmacsha256(dateRegionKey, "oss")
    signingKey = hmacsha256(dateRegionServiceKey, "aliyun_v4_request")
    # ステップ 4:署名を計算します。
    result = hmacsha256(signingKey, stringToSign)
    signature = result.hex()
    # レスポンスデータを構築します。
    response_data = {
        'policy': stringToSign,  # policy フォームフィールド。
        'x_oss_signature_version': "OSS4-HMAC-SHA256",  # 署名バージョンとアルゴリズム。これは OSS4-HMAC-SHA256 に固定されています。
        'x_oss_credential': f"{temp_access_key_id}/{dt_obj_2}/{region_id}/oss/aliyun_v4_request",  # 認証情報のスコープを指定します。
        'x_oss_date': dt_obj_1,  # リクエスト時刻。
        'signature': signature,  # 計算された署名。
        'host': host,
        'dir': upload_dir,
        'security_token': security_token  # セキュリティトークン。
    }
    return jsonify(response_data)
if __name__ == "__main__":
    app.run(host="127.0.0.1", port=8000)  # 0.0.0.0 などの他のアドレスでリッスンする必要がある場合は、サーバー側の認証メカニズムを追加する必要があります。

Node.js

次のコマンドを実行して、依存関係をインストールします。

npm install ali-oss
npm install @alicloud/credentials
npm install express

次のサンプルコードは、一時的なアクセス認証情報 (STS トークン) を取得し、アップロードポリシーを構築し、サーバー上で POST 署名を計算する方法を示しています。

const express = require('express');
const OSS = require('ali-oss');
const { STS } = require('ali-oss');
const { getCredential } = require('ali-oss/lib/common/signUtils');
const { getStandardRegion } = require('ali-oss/lib/common/utils/getStandardRegion');
const { policy2Str } = require('ali-oss/lib/common/utils/policy2Str');
const app = express();
const PORT = process.env.PORT || 8000; // サービスリクエストのポート番号。
// 静的ファイルディレクトリを設定します。
app.use(express.static('templates'));
const GenerateSignature = async () => {
    // STS クライアントを初期化します。
    let sts = new STS({
        accessKeyId: process.env.OSS_ACCESS_KEY_ID,  // 環境変数から RAM ユーザーの AccessKey ID を取得します。
        accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET // 環境変数から RAM ユーザーの AccessKey Secret を取得します。
    });
    // assumeRole API を呼び出して、一時的な STS アクセス認証情報を取得します。
    const result = await sts.assumeRole(process.env.OSS_STS_ROLE_ARN, '', '3600', 'yourRoleSessionName'); // 環境変数から RAM ロール ARN を取得します。一時的なアクセス認証情報は 3,600 秒間有効で、ロールセッション名は yourRoleSessionName などのカスタム値です。
    // 一時的なアクセス認証情報から AccessKeyId、AccessKeySecret、および SecurityToken を抽出します。
    const accessKeyId = result.credentials.AccessKeyId;
    const accessKeySecret = result.credentials.AccessKeySecret;
    const securityToken = result.credentials.SecurityToken;
    // OSS クライアントを初期化します。
    const client = new OSS({
        bucket: 'examplebucket', // 宛先バケットの名前に置き換えてください。
        region: 'cn-hangzhou', // 宛先バケットのリージョンに置き換えてください。
        accessKeyId,
        accessKeySecret,
        stsToken: securityToken,
        refreshSTSTokenInterval: 0,
        refreshSTSToken: async () => {
            const { accessKeyId, accessKeySecret, securityToken } = await client.getCredential();
            return { accessKeyId, accessKeySecret, stsToken: securityToken };
        },
    });
    // フォームデータマップを作成します。
    const formData = new Map();
    // 署名の有効期限を現在の時刻から1時間後に設定します。
    const date = new Date();
    const expirationDate = new Date(date);
    expirationDate.setHours(date.getHours() + 1);
    // 日付を ISO 8601 に準拠した UTC 時刻文字列にフォーマットします。
    function padTo2Digits(num) {
        return num.toString().padStart(2, '0');
    }
    function formatDateToUTC(date) {
        return (
            date.getUTCFullYear() +
            padTo2Digits(date.getUTCMonth() + 1) +
            padTo2Digits(date.getUTCDate()) +
            'T' +
            padTo2Digits(date.getUTCHours()) +
            padTo2Digits(date.getUTCMinutes()) +
            padTo2Digits(date.getUTCSeconds()) +
            'Z'
        );
    }
    const formattedDate = formatDateToUTC(expirationDate);
    // x-oss-credential を生成し、フォームデータを設定します。
    const credential = getCredential(formattedDate.split('T')[0], getStandardRegion(client.options.region), client.options.accessKeyId);
    formData.set('x_oss_date', formattedDate);
    formData.set('x_oss_credential', credential);
    formData.set('x_oss_signature_version', 'OSS4-HMAC-SHA256');
    // ポリシーを作成します。
    const uploadDir = 'user-dir';
    const policy = {
        expiration: expirationDate.toISOString(),
        conditions: [
            { 'bucket': client.options.bucket },
            ['starts-with', '$key', uploadDir],
            ['content-length-range', 0, 10240000],
            { 'success_action_status': '200' },
            { 'x-oss-credential': credential },
            { 'x-oss-signature-version': 'OSS4-HMAC-SHA256' },
            { 'x-oss-date': formattedDate },
        ],
    };
    // STS トークンが存在する場合は、ポリシーとフォームデータに追加します。
    if (client.options.stsToken) {
        policy.conditions.push({ 'x-oss-security-token': client.options.stsToken });
        formData.set('security_token', client.options.stsToken);
    }
    // 署名を生成し、フォームデータを設定します。
    const signature = client.signPostObjectPolicyV4(policy, date);
    formData.set('policy', Buffer.from(policy2Str(policy), 'utf8').toString('base64'));
    formData.set('signature', signature);
    // フォームデータを返します。
    return {
        host: `http://${client.options.bucket}.oss-${client.options.region}.aliyuncs.com`, 
        policy: Buffer.from(policy2Str(policy), 'utf8').toString('base64'),
        x_oss_signature_version: 'OSS4-HMAC-SHA256',
        x_oss_credential: credential,
        x_oss_date: formattedDate,
        signature: signature,
        dir: uploadDir, // OSS にアップロードされるオブジェクトのプレフィックス (ディレクトリ)。
        security_token: client.options.stsToken
    };
};
app.get('/get_post_signature_for_oss_upload', async (req, res) => {
    try {
        const result = await GenerateSignature();
        res.json(result); // 生成された署名データを返します。
    } catch (error) {
        console.error('Error generating signature:', error);
        res.status(500).send('Error generating signature');
    }
});
app.listen(PORT, () => {
    console.log(`Server is running on http://127.0.0.1:${PORT}`); // 0.0.0.0 などの他のアドレスでリッスンする必要がある場合は、サーバー側の認証メカニズムを追加する必要があります。
});

Go

次のコマンドを実行して、依存関係をインストールします。

go get -u github.com/aliyun/credentials-go
go mod tidy

次のサンプルコードは、一時的なアクセス認証情報 (STS トークン) を取得し、アップロードポリシーを構築し、サーバー上で POST 署名を計算する方法を示しています。

package main
import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io"
    "hash"
    "log"
    "net/http"
    "os"
    "time"
    "github.com/aliyun/credentials-go/credentials"
)
// グローバル変数を定義します。
var (
    region     string
    bucketName string
    product    = "oss"
)
// PolicyToken 構造体は、生成されたフォームデータを格納します。
type PolicyToken struct {
    Policy           string `json:"policy"`
    SecurityToken    string `json:"security_token"`
    SignatureVersion string `json:"x_oss_signature_version"`
    Credential       string `json:"x_oss_credential"`
    Date             string `json:"x_oss_date"`
    Signature        string `json:"signature"`
    Host             string `json:"host"` 
    Dir              string `json:"dir"` 
}
func main() {
    // デフォルトの IP アドレスとポート文字列を定義します。
    strIPPort := ":8000"
    if len(os.Args) == 3 {
    strIPPort = fmt.Sprintf("%s:%s", os.Args[1], os.Args[2])
    } else if len(os.Args) != 1 {
    fmt.Println("Usage   : go run test1.go                ")
    fmt.Println("Usage   : go run test1.go ip port        ")
    fmt.Println("")
    os.Exit(0)
    }
    // サーバーが実行されているアドレスとポートを出力します。
    fmt.Printf("server is running on %s \n", strIPPort)
    // ルートパスリクエストを処理する関数を登録します。
    http.HandleFunc("/", handlerRequest)
    // 署名生成リクエストを処理する関数を登録します。
    http.HandleFunc("/get_post_signature_for_oss_upload", handleGetPostSignature)
    // HTTP サーバーを起動します。
    err := http.ListenAndServe(strIPPort, nil)
    if err != nil {
    strError := fmt.Sprintf("http.ListenAndServe failed : %s \n", err.Error())
    panic(strError)
    }
}
// handlerRequest 関数は、ルートパスリクエストを処理します。
func handlerRequest(w http.ResponseWriter, r *http.Request) {
    if r.Method == "GET" {
    http.ServeFile(w, r, "templates/index.html")
    return
    }
    http.NotFound(w, r)
}
// handleGetPostSignature 関数は、署名生成リクエストを処理します。
func handleGetPostSignature(w http.ResponseWriter, r *http.Request) {
    if r.Method == "GET" {
    response := getPolicyToken()
    w.Header().Set("Content-Type", "application/json")
    w.Header().Set("Access-Control-Allow-Origin", "*") // クロスオリジンリクエストを許可します。
    w.Write([]byte(response))
    return
    }
    http.NotFound(w, r)
}
// getPolicyToken 関数は、OSS アップロードに必要な署名と認証情報を生成します。
func getPolicyToken() string {
    // バケットのリージョンを設定します。
    region = "cn-hangzhou"
    // バケット名に置き換えてください。
    bucketName = "examplebucket"
    // OSS アップロードアドレスを設定します。
    host := fmt.Sprintf("https://%s.oss-%s.aliyuncs.com", bucketName, region)
    // アップロードディレクトリを設定します。
    dir := "user-dir"
    config := new(credentials.Config).
    SetType("ram_role_arn").
    SetAccessKeyId(os.Getenv("OSS_ACCESS_KEY_ID")).
    SetAccessKeySecret(os.Getenv("OSS_ACCESS_KEY_SECRET")).
    SetRoleArn(os.Getenv("OSS_STS_ROLE_ARN")).
    SetRoleSessionName("Role_Session_Name").
    SetPolicy("").
    SetRoleSessionExpiration(3600)
    // 設定に基づいて認証情報プロバイダーを作成します。
    provider, err := credentials.NewCredential(config)
    if err != nil {
    log.Fatalf("NewCredential fail, err:%v", err)
    }
    // 認証情報プロバイダーから認証情報を取得します。
    cred, err := provider.GetCredential()
    if err != nil {
    log.Fatalf("GetCredential fail, err:%v", err)
    }
    // ポリシーを構築します。
    utcTime := time.Now().UTC()
    date := utcTime.Format("20060102")
    expiration := utcTime.Add(1 * time.Hour)
    policyMap := map[string]any{
        "expiration": expiration.Format("2006-01-02T15:04:05.000Z"),
        "conditions": []any{
            map[string]string{"bucket": bucketName},
            []string{"starts-with", "$key", dir},
            []string{"content-length-range", "0", "10240000"},
            []string{"eq", "$success_action_status", "200"},
            map[string]string{"x-oss-signature-version": "OSS4-HMAC-SHA256"},
            map[string]string{"x-oss-credential": fmt.Sprintf("%v/%v/%v/%v/aliyun_v4_request", *cred.AccessKeyId, date, region, product)},
            map[string]string{"x-oss-date": utcTime.Format("20060102T150405Z")},
            map[string]string{"x-oss-security-token": *cred.SecurityToken},
        },
    }
    // ポリシーを JSON 形式に変換します。
    policy, err := json.Marshal(policyMap)
    if err != nil {
    log.Fatalf("json.Marshal fail, err:%v", err)
    }
    // 署名対象の文字列を構築します。
    stringToSign := base64.StdEncoding.EncodeToString([]byte(policy))
    hmacHash := func() hash.Hash { return sha256.New() }
        // 署名キーを構築します。
    signingKey := "aliyun_v4" + *cred.AccessKeySecret
    h1 := hmac.New(hmacHash, []byte(signingKey))
    io.WriteString(h1, date)
    h1Key := h1.Sum(nil)
    h2 := hmac.New(hmacHash, h1Key)
    io.WriteString(h2, region)
    h2Key := h2.Sum(nil)
    h3 := hmac.New(hmacHash, h2Key)
    io.WriteString(h3, product)
    h3Key := h3.Sum(nil)
    h4 := hmac.New(hmacHash, h3Key)
    io.WriteString(h4, "aliyun_v4_request")
    h4Key := h4.Sum(nil)
    // 署名を生成します。
    h := hmac.New(hmacHash, h4Key)
    io.WriteString(h, stringToSign)
    signature := hex.EncodeToString(h.Sum(nil))
    // クライアントに返されるフォームを構築します。
    policyToken := PolicyToken{
    Policy:           stringToSign,
    SecurityToken:    *cred.SecurityToken,
    SignatureVersion: "OSS4-HMAC-SHA256",
    Credential:       fmt.Sprintf("%v/%v/%v/%v/aliyun_v4_request", *cred.AccessKeyId, date, region, product),
    Date:             utcTime.UTC().Format("20060102T150405Z"),
    Signature:        signature,
    Host:             host, // OSS アップロードアドレス。
    Dir:              dir,  // アップロードディレクトリ。
    }
    response, err := json.Marshal(policyToken)
    if err != nil {
    fmt.Println("json err:", err)
    }
    return string(response)
}

PHP

次のコマンドを実行して、依存関係をインストールします。

composer install

次のサンプルコードは、一時的なアクセス認証情報 (STS トークン) を取得し、アップロードポリシーを構築し、サーバー上で POST 署名を計算する方法を示しています。

<?php
// Alibaba Cloud SDK をインポートします。
require_once __DIR__ . '/vendor/autoload.php';
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
use AlibabaCloud\Sts\Sts;
// エラー表示を無効にします。
ini_set('display_errors', '0');
$bucket = 'examplebucket'; // バケット名に置き換えてください。
$region_id = 'cn-hangzhou'; // バケットのリージョンに置き換えてください。
$host = 'http://examplebucket.oss-cn-hangzhou.aliyuncs.com'; // バケットのドメイン名に置き換えてください。
$expire_time = 3600; // 有効期限 (秒単位)。
$upload_dir = 'user-dir'; // アップロードされるオブジェクトのプレフィックス (ディレクトリ)。
// HMAC-SHA256 を計算します。
function hmacsha256($key, $data) {
    return hash_hmac('sha256', $data, $key, true);
}
// POST 署名を取得するリクエストを処理します。
if ($_SERVER['REQUEST_METHOD'] === 'GET' && $_SERVER['REQUEST_URI'] === '/get_post_signature_for_oss_upload') {
    AlibabaCloud::accessKeyClient(getenv('OSS_ACCESS_KEY_ID'), getenv('OSS_ACCESS_KEY_SECRET'))
        ->regionId('cn-hangzhou')
        ->asDefaultClient();
    // STS リクエストを作成します。
    $request = Sts::v20150401()->assumeRole();
    // STS リクエストを開始し、結果を取得します。
    // <YOUR_ROLE_SESSION_NAME> を、oss-role-session などのカスタムセッション名に設定します。
    // <YOUR_ROLE_ARN> を、指定された OSS バケットにファイルをアップロードする権限を持つ RAM ロールの ARN に置き換えてください。
    $result = $request
        ->withRoleSessionName('oss-role-session')
        ->withDurationSeconds(3600)
        ->withRoleArn(getenv('OSS_STS_ROLE_ARN'))
        ->request();
    // STS リクエスト結果から認証情報を取得します。
    $tokenData = $result->get('Credentials');
    // 返される JSON データを構築します。
    $tempAccessKeyId = $tokenData['AccessKeyId'];
    $tempAccessKeySecret = $tokenData['AccessKeySecret'];
    $securityToken = $tokenData['SecurityToken'];
    $now = time();
    $dtObj = gmdate('Ymd\THis\Z', $now);
    $dtObj1 = gmdate('Ymd', $now);
    $expiration_time_str = gmdate('Y-m-d\TH:i:s.u\Z', $now + $expire_time);
    // ポリシーを構築します。
    $policy = [
        "expiration" => $expiration_time_str,
        "conditions" => [
            ["bucket" => $bucket],
            ['starts-with', '$key', $upload_dir],
            ['content-length-range', 0, 10240000],
            ['eq', '$success_action_status', '200'],
            ["x-oss-signature-version" => "OSS4-HMAC-SHA256"],
            ["x-oss-credential" => "{$tempAccessKeyId}/{$dtObj1}/{$region_id}/oss/aliyun_v4_request"],
            ["x-oss-security-token" => $securityToken],
            ["x-oss-date" => $dtObj],
        ]
    ];
    $policyStr = json_encode($policy);
    // 署名対象の文字列を構築します。
    $stringToSign = base64_encode($policyStr);
    // 署名キーを計算します。
    $dateKey = hmacsha256(('aliyun_v4' . $tempAccessKeySecret), $dtObj1);
    $dateRegionKey = hmacsha256($dateKey, $region_id);
    $dateRegionServiceKey = hmacsha256($dateRegionKey, 'oss');
    $signingKey = hmacsha256($dateRegionServiceKey, 'aliyun_v4_request');
    // 署名を計算します。
    $result = hmacsha256($signingKey, $stringToSign);
    $signature = bin2hex($result);
    // 署名データを返します。
    $responseData = [
        'policy' => $stringToSign,
        'x_oss_signature_version' => "OSS4-HMAC-SHA256",
        'x_oss_credential' => "{$tempAccessKeyId}/{$dtObj1}/{$region_id}/oss/aliyun_v4_request",
        'x_oss_date' => $dtObj,
        'signature' => $signature,
        'host' => $host,
        'dir' => $upload_dir,
        'security_token' => $securityToken
    ];
    header('Content-Type: application/json');
    echo json_encode($responseData);
    exit;
}
// ホームページルート。
if ($_SERVER['REQUEST_METHOD'] === 'GET' && $_SERVER['REQUEST_URI'] === '/') {
    echo file_get_contents(__DIR__ . '/public/index.html');
    exit;
}
// その他のルート。
http_response_code(404);
echo json_encode(['message' => 'Not Found']);
exit;
?>

ステップ 3: Web クライアントの設定

クライアント側のフォームアップロード

Web クライアントがアプリケーションサーバーから必要な情報を受信した後、HTML フォームリクエストを構築します。このリクエストは OSS と直接通信してファイルをアップロードします。

Web クライアント: サンプルレスポンス

アプリケーションサーバーは、STS トークンとアップロードポリシーを Web クライアントに返します。

{
    "dir": "user-dirs",
    "host": "http://examplebucket.oss-cn-hangzhou.aliyuncs.com",
    "policy": "eyJl****",
    "security_token": "CAIS****",
    "signature": "9103****",
    "x_oss_credential": "STS.NSpW****/20241127/cn-hangzhou/oss/aliyun_v4_request",
    "x_oss_date": "20241127T060941Z",
    "x_oss_signature_version": "OSS4-HMAC-SHA256"
}

レスポンスボディの各フィールドについては、次の表で説明します。

パラメーター

説明

dir

アップロードに必要なオブジェクト名のプレフィックスを指定します。

host

送信先バケットのドメイン名です。

policy

ブラウザベースのフォームアップロードに使用されるポリシーです。詳細については、「Post Policy」をご参照ください。

security_token

STS によって提供される、認証に使用される一時的な認証情報です。

signature

ポリシーから生成された署名です。詳細については、「Post Signature」をご参照ください。

x_oss_credential

署名キーを導出するために使用されるパラメーターセットを指定します。

x_oss_date

ISO 8601 形式のリクエスト時刻です (例: 20231203T121212Z)。

x_oss_signature_version

署名バージョンとアルゴリズムです。値は OSS4-HMAC-SHA256 に固定されています。

  • フォームリクエストには、ファイルの内容とアプリケーションサーバーから返されたパラメーターが含まれます。

  • Web クライアントは、このリクエストを使用して OSS と直接通信し、ファイルをアップロードします。

説明
  • file フォームフィールドを除き、key を含む他のすべてのフォームフィールドは 8 KB を超えてはなりません。

  • デフォルトでは、Web ベースのアップロードは同じ名前のオブジェクトを上書きします。オブジェクトが上書きされないようにするには、リクエストに x-oss-forbid-overwrite フォームフィールドを追加し、その値を true に設定します。OSS に同じ名前のオブジェクトが既に存在する場合、アップロードは失敗し、OSS は FileAlreadyExists エラーを返します。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>サーバーで署名を生成して OSS にファイルをアップロードする</title>
</head>
<body>
<div class="container">
    <form>
        <div class="mb-3">
            <label for="file" class="form-label">ファイルを選択:</label>
            <input type="file" class="form-control" id="file" name="file" required />
        </div>
        <button type="submit" class="btn btn-primary">アップロード</button>
    </form>
</div>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function () {
    const form = document.querySelector("form");
    const fileInput = document.querySelector("#file");
    form.addEventListener("submit", (event) => {
        event.preventDefault();
        const file = fileInput.files[0];
        if (!file) {
            alert('アップロードするファイルを選択してください。');
            return;
        }
        const filename = file.name;
        fetch("/get_post_signature_for_oss_upload", { method: "GET" })
            .then((response) => {
                if (!response.ok) {
                    throw new Error("署名の取得に失敗しました");
                }
                return response.json();
            })
            .then((data) => {
                let formData = new FormData();
                formData.append("success_action_status", "200");
                formData.append("policy", data.policy);
                formData.append("x-oss-signature", data.signature);
                formData.append("x-oss-signature-version", "OSS4-HMAC-SHA256");
                formData.append("x-oss-credential", data.x_oss_credential);
                formData.append("x-oss-date", data.x_oss_date);
                formData.append("key", data.dir + file.name); // オブジェクト名
                formData.append("x-oss-security-token", data.security_token);
                formData.append("file", file); // file は最後のフォームフィールドにする必要があります
                return fetch(data.host, { 
                    method: "POST",
                    body: formData
                });
            })
            .then((response) => {
                if (response.ok) {
                    console.log("アップロードが成功しました。");
                    alert("ファイルが正常にアップロードされました。");
                } else {
                    console.log("アップロードが失敗しました", response);
                    alert("アップロードに失敗しました。後でもう一度お試しください。");
                }
            })
            .catch((error) => {
                console.error("エラーが発生しました:", error);
            });
    });
});
</script>
</body>
</html>
  • HTML フォームには、ファイル入力と送信ボタンが含まれています。

  • フォームが送信されると、JavaScript コードはデフォルトの送信を防ぎ、必要な署名情報を取得するためにアプリケーションサーバーに AJAX リクエストを送信します。

  • 署名情報を受信した後、コードは必要なフォームフィールドを使用してFormData オブジェクトを作成します。

  • 次に、fetch メソッドを使用して OSS URL に POST リクエストを送信し、ファイルをアップロードします。

アップロードが成功すると、「ファイルが正常にアップロードされました。」というメッセージが表示されます。アップロードが失敗すると、エラーメッセージが表示されます。

検証

デプロイメント後、アプリケーションサーバーにアクセスして、署名付き URL による直接アップロード機能をテストします。

  1. ブラウザでアプリケーションサーバーにアクセスします。[ファイルを選択] をクリックし、ファイルを選択してアップロードします。

  2. バケットページ で、作成したバケットを開き、アップロードされたオブジェクトが存在することを確認します。

推奨設定

ファイルのアップロードポリシー

コード内の ポリシー を変更して、HTML フォームから OSS へのファイルアップロードに対する権限と制約を設定できます。JSON 形式のポリシーでは、許可されるバケット名、オブジェクトプレフィックス、有効期限、許可される HTTP メソッド、コンテンツサイズの制限、コンテンツタイプなどのパラメーターを設定することで、アップロードを制限できます。

{
  "expiration": "2023-12-03T13:00:00.000Z",
  "conditions": [
    {"bucket": "examplebucket"},
    {"x-oss-signature-version": "OSS4-HMAC-SHA256"},
    {"x-oss-credential": "AKIDEXAMPLE/20231203/cn-hangzhou/oss/aliyun_v4_request"},
    {"x-oss-security-token": "CAIS******"},
    {"x-oss-date": "20231203T121212Z"},
    ["content-length-range", 1, 10],
    ["eq", "$success_action_status", "201"],
    ["starts-with", "$key", "user/eric/"],
    ["in", "$content-type", ["image/jpeg", "image/png"]],
    ["not-in", "$cache-control", ["no-cache"]]
  ]
}

ポリシーパラメーターの詳細については、「POST ポリシー」をご参照ください。

サーバー側署名とアップロードコールバック

アップロードされたファイルのファイル名やサイズなどのメタデータを受信するには、アップロードコールバックを設定します。ファイルがアップロードされると、OSS はファイル情報をアプリケーションサーバーに送信します。詳細については、「サーバー側署名とアップロードコールバックによる直接アップロード」をご参照ください。

CORS オリジンの制限

これまでは便宜上、許可されたオリジンにワイルドカード文字 * が設定されていました。セキュリティのベストプラクティスとして、ワイルドカードをアプリケーションサーバーの特定の URL に置き換える必要があります。これにより、サーバーからのクロスオリジンリクエストのみが許可されるようになります。

パラメーター

サンプル値

[ソース]

http://<your_application_server_address>

[許可されたメソッド]

POST, PUT, GET

[許可されたヘッダー]

*

リソースのクリーンアップ

このソリューションでは、1 つの ECS インスタンス、1 つの OSS バケット、1 つの RAM ユーザー、および 1 つの RAM ロールを作成しました。テストの完了後、継続的な課金やセキュリティリスクを回避するために、これらのリソースをクリーンアップします。

ECS インスタンスのリリース

インスタンスが不要になった場合は、リリースしてください。インスタンスをリリースすると、課金が停止し、そのデータは回復できなくなります。

  1. ECS コンソールインスタンスページに移動します。リージョンとインスタンス ID で対象の ECS インスタンスを見つけ、[操作] 列の image をクリックします。

  2. [リリース] を選択します。表示されるメニューで、[リリース] をクリックします。

  3. インスタンスの詳細を確認し、[今すぐリリース] を選択してから、[次へ] をクリックします。

  4. リリースされる関連リソースを確認し、関連するデータリスクに同意してから、[確認] をクリックします。

説明
  • システムディスクと割り当てられたパブリック IP アドレスは、インスタンスと共にリリースされます。

  • セキュリティグループ、VSwitch、および VPC は、インスタンスと共にリリースされません。これらのリソースは無料ですが、不要になった場合は削除できます。

  • EIP はインスタンスと共にリリースされず、引き続き課金されます。不要になった場合は、別途削除してください。

OSS バケットの削除

  1. OSS コンソールにログオンします。

  2. バケット をクリックし、ターゲット OSS バケットの名前をクリックします。

  3. バケット内のすべてのオブジェクトを削除します。

  4. 左側のナビゲーションペインで バケットの削除 をクリックし、画面の指示に従います。

RAM ユーザーの削除

  1. 管理者権限を持つ RAM ユーザーとして RAM コンソールにログオンします。

  2. 左側メニューで、 を選択します。

  3. [ユーザー] ページで、対象の RAM ユーザーを見つけ、[操作] 列の [削除] をクリックします。

    または、複数の RAM ユーザーを選択し、すべてをごみ箱に移動するために、リストの下にある [ユーザーの削除] をクリックします。

  4. [ユーザーの削除] ダイアログボックスで、削除による影響を慎重に確認し、対象の RAM ユーザーの名前を入力してから、ごみ箱に移動する をクリックします。

RAM ロールの削除

  1. 管理者権限を持つ RAM ユーザーとして RAM コンソールにログオンします。

  2. 左側メニューで、 を選択します。

  3. [ロール] ページで、対象の RAM ロールを見つけ、[操作] 列の [ロールの削除] をクリックします。

  4. [ロールの削除] ダイアログボックスで、RAM ロール名を入力し、[ロールの削除] をクリックします。

    説明

    RAM ロールにポリシーがアタッチされている場合、ロールを削除するとそれらもデタッチされます。

よくある質問

マルチパートアップロードと再開可能なアップロード

このソリューションはフォームアップロードを使用するため、マルチパートアップロードおよび再開可能なアップロードはサポートしていません。これらの方法を使用する場合は、「再開可能なアップロード」および「マルチパートアップロード」をご参照ください。

ファイルの上書き防止

アップロードフォームのフィールドで、x-oss-forbid-overwrite パラメーターを true に設定します。例:

formData.append('x-oss-forbid-overwrite', 'true');