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

Object Storage Service:クライアントからOSSにデータを安全かつ直接アップロードする

最終更新日:Oct 14, 2024

クライアントから直接アップロードすると、クライアントのsecurity token Service (STS) から取得したセキュリティトークンを使用して署名を生成し、その署名を使用して、中間データ転送なしでクライアントからObject Storage Service (OSS) にデータを直接アップロードできます。 これにより、ワークフローが簡素化され、アップロード速度が高速化されます。 このトピックでは、データをOSSに安全かつ直接アップロードする方法について説明します。

セキュリティリスク管理

企業のアプリケーションサーバーの作業負荷を軽減し、効率を向上させるために、webアプリケーションは、アプリケーションサーバーを使用してすべての要求を転送するのではなく、ユーザーのwebブラウザーでOSSと直接対話するように設計されています。

エンタープライズAは、次のソリューションを使用して、OSSにデータを直接アップロードするwebアプリケーションを構築する予定です。

image

ブラウザ環境はユーザー側にあり、エンタープライズAによって制御することはできません。その結果、エンタープライズaは次の課題に直面します。

  • 認証リーク: ブラウザは信頼できない環境と見なされます。 AccessKeyペアをブラウザに保存すると、認証情報が漏洩するリスクが高くなる可能性があります。 攻撃者は、リークされた資格情報を使用して、企業の秘密、顧客データ、知的財産、主要資産などの企業データを盗むことができます。 データ漏えいは、重大な経済的損失や企業の評判への損害を引き起こす可能性があります。

  • 粗いアクセス制御: ほとんどの場合、アプリケーションを使用するRAMユーザーには、他のクラウドサービスを管理およびアクセスするための過度のアクセス許可が付与されます。 漏洩したRAMユーザーのAccessKeyペアは、深刻な結果につながる可能性があります。 この大まかなアクセス制御の実践は、企業リソースの悪用の可能性を高める可能性もあります。 ハッカーは、リークされたAccessKeyペアを使用して、バックドアプログラム、パスワードスティーラー、暗号マイニングソフトウェアなどのマルウェアプログラムを展開する場合があります。 これらのマルウェアプログラムは、通常のビジネス活動、金融セキュリティ、およびビジネスの評判に高いリスクをもたらします。

解決策

リスクを処理するために、エンタープライズAは既存のソリューションに一時的なアクセス許可を追加できます。 このように、エンタープライズAはアップロード効率を維持し、次の利点を得ることができます。

  • 強化された認証と承認: STSは、特定の期間内に有効なセキュリティトークンを発行します。これにより、長期アクセス資格情報の不正使用を防ぎ、資格情報の漏洩のリスクを軽減できます。

  • きめ細かいアクセス制御: STSにより、エンタープライズAは最小権限の原則に基づいて権限を設定できます。 エンタープライズAは、webアプリケーションに必要な権限のみを付与できます。 きめ細かいアクセス制御は、資格情報の漏洩のリスクを軽減します。

最終的に、エンタープライズAは次のソリューションを使用してwebアプリケーションを構築することを決定します。

image

デプロイ方法

次の配置は、OSSとSTSを使用してwebアプリケーションから直接クライアントをアップロードする方法を説明するための例として使用されます。

この例では、関数コードはPythonで記述されています。 サンプルプロジェクト: oss-upload-sts.zip

Resource Orchestration Service (ROS) テンプレート: add-signatures-on-the-client-by-using-JS-and-upload-data.yml

STSから一時的なアクセス資格情報を取得するために使用されるJavaコードの詳細については、「ststoken.zip」をご参照ください。

迅速な展開

ROSを使用して、Elastic Compute Service (ECS) インスタンスとOSSバケットを設定し、ECSインスタンスにブラウザクライアントをデプロイできます。 ROSを使用してwebアプリケーションをすばやくデプロイし、直接アップロードを実行するには、次の手順を実行します。

  1. 数回クリックするだけでクラウドリソースをデプロイできます。

    1. ROSコンソールでスタック作成ウィザードを使用します。

    2. ROSコンソールの [スタックの作成] ウィザードの [パラメータの設定] ステップで、スタック名と作成するOSSバケットの名前を入力します。 購入するECSインスタンスのゾーン、インスタンスタイプ、システムディスクカテゴリ、およびパスワードを指定し、[次へ] をクリックします。 チェックと確認ステップで、設定を確認し、作成する をクリックします。

      表示されるページの [スタック情報] タブで、スタックのステータスは [作成中] になります。

    3. スタックが [作成済み] 状態になったら、[出力] タブをクリックして、ECSインスタンスやOSSバケットなどのリソースを表示します。

  2. 直接アップロードを実行します。

    1. [出力] タブで、UploadPathの値をコピーしてブラウザで開きます。

    2. [WebクライアントからOSSへのデータ転送] ページで、[ファイルの選択] をクリックし、特定の種類のファイルを選択し、[アップロード] をクリックします。

操作の検証とリソースのクリーンアップ

操作確認

アップロード操作が完了したら、オブジェクトがバケットに存在するかどうかを確認します。

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

  2. 左側のナビゲーションウィンドウで、[バケット] をクリックします。

  3. [バケット] ページで、管理するOSSバケットを見つけ、バケット名をクリックします。

  4. [オブジェクト] ページで、オブジェクトが存在するかどうかを確認します。

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

不要な料金を避けるためにリソースを解放します。

  1. スタックページの右上隅にある 削除 をクリックします。

  2. リソーススタックの削除 ダイアログボックスで、スタックを削除する方法リソースのリリース に設定し、決定 をクリックします。

手動展開

準備

  • ブラウザーからwebアプリケーションによってアップロードされたデータを保存するOSSバケットを作成します。

    パラメーター

    例:

    リージョン

    中国 (杭州)

    バケット名

    web-direct-upload

    詳細は、「バケットの作成」をご参照ください。

  • ECSインスタンスを作成し、STSから一時的なアクセス資格情報を取得します。

    説明

    実際のデプロイシナリオでは、ECSインスタンスを作成することなく、STS API操作をアプリケーションサーバーに統合できます。

    パラメーター

    Billing Method

    従量課金

    リージョン

    中国 (杭州)

    パブリック IP アドレス

    パブリックIPv4アドレスの割り当て

    セキュリティグループ

    HTTP-TCP:80-open

    詳細については、「コンソールでのECSインスタンスの作成と管理 (エクスプレスバージョン) 」をご参照ください。

  • OSSバケットのクロスオリジンリソース共有 (CORS) を設定します。

    パラメーター

    ソース

    http:// ECS-public-IP-address

    許可されたメソッド

    PUT

    許可されたヘッダー

    *

    詳細については、「CORS」をご参照ください。

手順

手順1: RAMコンソールでのRAMユーザーの作成

OpenAPIアクセスが有効になっているRAMユーザーを作成し、RAMユーザーのAccessKeyペアを取得します。 AccessKeyペアは、アプリケーションサーバーへのアクセスと管理に必要な長期アクセス資格情報です。

  1. Alibaba Cloudアカウントを使用するか、アカウント管理者としてRAMコンソールにログインします。

  2. 左側のナビゲーションウィンドウで、[アイデンティティ]> [ユーザー] を選択します。

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

  4. [ログイン名] および [表示名] パラメーターを設定します。

  5. [アクセスモード] セクションで、[OpenAPIアクセス] を選択し、[OK] をクリックします。

  6. [操作] セクションの [コピー] をクリックして、AccessKeyペアをコピーし、安全に保存されたファイルに貼り付けます。

手順2: AssumeRole操作の呼び出しをRAMユーザーに許可する

AssumeRole操作を呼び出す権限をRAMユーザーに付与します。 これにより、RAMユーザーはRAMロールを引き受けることで一時的なアクセス資格情報を取得できます。

  1. 左側のナビゲーションウィンドウで、[アイデンティティ]> [ユーザー] を選択します。

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

  3. [権限付与] パネルの [ポリシー] セクションで、[AliyunSTSAssumeRoleAccess] ポリシーを選択します。

    説明

    AliyunSTSAssumeRoleAccessポリシーを使用すると、RAMユーザーはAssumeRole操作を呼び出すことができます。 ポリシーの権限は、RAMユーザーがSTSから一時的なアクセス資格情報を取得してOSSへのリクエストを開始するために必要な権限とは無関係です。

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

手順3: RAMコンソールでRAMロールを作成する

Alibaba CloudアカウントのRAMロールを作成し、RAMロールのAlibaba Cloudリソース名 (ARN) を取得します。 RAMロールは、後でRAMユーザーによって引き受けられます。

  1. 左側のナビゲーションウィンドウで、[アイデンティティ]> [ロール] を選択します。

  2. [ロールの作成] をクリックします。 [ロールの作成] ウィザードで、[信頼できるエンティティの選択] を [Alibaba Cloudアカウント] に設定し、[次へ] をクリックします。

  3. [ロールの設定] ステップで、[RAMロール名] フィールドに名前を入力し、[信頼できるAlibaba Cloudアカウントの選択] を [現在のAlibaba Cloudアカウント] に設定します。

  4. [OK] をクリックします。 ロールを作成したら、[閉じる] をクリックします。

  5. [ロール] ページで、検索ボックスにロール名を入力します。 例: oss-web-upload ロールの名前をクリックします。

  6. [基本情報] セクションで、ARNフィールドの横にある [コピー] をクリックして、RAMロールのARNを記録します。

手順4: RAMコンソールでカスタムポリシーを作成する

RAMロールがバケットで指定されたAPI操作のみを呼び出すことを許可するカスタムポリシーを作成します。

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

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

  3. [ポリシーの作成] ページで、[JSON] をクリックします。 次のサンプルスクリプトをコピーして、コードエディターに貼り付けます。 <BucketName> を、作成したバケットの名前に置き換えます。

    重要

    次のサンプルスクリプトは、参照用にのみ提供されます。 ユーザーに過度の権限を与えないように、要件に基づいてきめ細かいRAMポリシーを構成する必要があります。 詳細なポリシーを設定する方法の詳細については、「OSSのカスタムポリシー」をご参照ください。

    {
      "Version": "1",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": "oss:PutObject",
          "Resource": "acs:oss:*:*:<BucketName>/uploads/*"
        }
      ]
    }
  4. [次へ] をクリックしてポリシー情報を編集します。

  5. [基本情報] セクションで、ポリシー名を指定し、[OK] をクリックします。

手順5: RAMコンソールでRAMロールにカスタムポリシーをアタッチする

カスタムポリシーをRAMロールにアタッチします。 このようにして、RAMロールは、RAMロールが引き受けられたときに必要な権限を提供できます。

  1. 左側のナビゲーションウィンドウで、[アイデンティティ]> [ロール] を選択します。

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

  3. [権限付与] パネルの [ポリシー] セクションで、ドロップダウンリストから [カスタムポリシー] を選択し、カスタムポリシーを選択します。

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

手順6: アプリケーションサーバーから一時的なアクセス資格情報を取得

STS SDKをアプリケーションサーバーに統合して、/get_sts_token操作を取得し、STSから一時的なアクセス資格情報を取得します。 HTTP GETメソッドを使用して /get_sts_token操作を呼び出すと、一時的なアクセス資格情報が作成され、要求元に返されます。

ECSインスタンスで、Flaskフレームワークを使用してwebアプリケーションを構築し、STSから一時的なアクセス資格情報を取得する操作を実装します。

  1. ECS インスタンスに接続します。

    詳細については、「ECSコンソール (エクスプレスバージョン) を使用したECSインスタンスの作成と管理」をご参照ください。

  2. Python 3をインストールします。

  3. プロジェクトディレクトリを作成し、プロジェクトディレクトリに切り替えます。 サンプルコマンド:

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

    pip3 install Flask
    pip3 install attr
    pip3 install yarl
    pip3 install async_timeout
    pip3 install idna_ssl
    pip3 install attrs
    pip3 install aiosignal
    pip3 install charset_normalizer
    pip3 install alibabacloud_tea_openapi
    pip3 install alibabacloud_sts20150401
    pip3 install alibabacloud_credentials
  5. アプリケーションのバックエンドコードを作成します。

    1. main.pyファイルを作成します。

    2. 次のPythonコードをファイルに書き込みます。

      import json
      from flask import Flask, render_template
      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
      
      app = Flask(__name__)
      
      # Replace <YOUR_ROLE_ARN> with the ARN of the RAM role. 
      role_arn_for_oss_upload = '<YOUR_ROLE_ARN>'
      # Specify the region of STS. Example: cn-hangzhou 
      region_id = 'cn-hangzhou'
      
      @app.route("/")
      def hello_world():
          return render_template('index.html')
      
      @app.route('/get_sts_token', methods=['GET'])
      def get_sts_token():
          # If you do not specify parameters when you initialize CredentialClient, the default credential chain is used. 
          # If you run the program on your local computer, you can obtain the AccessKey pair from the ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables.
          # If you run the program on ECS, Elastic Container Instance, or Container Service for Kubernetes (ACK), you can specify the role of the bound instance by configuring the ALIBABA_CLOUD_ECS_METADATA environment variable. The SDK automatically obtains the temporary access credentials from STS. 
          config = Config(region_id=region_id, credential=CredentialClient())
          sts_client = Sts20150401Client(config=config)
          assume_role_request = sts_20150401_models.AssumeRoleRequest(
              role_arn=role_arn_for_oss_upload,
              # Replace <YOUR_ROLE_SESSION_NAME> with the name of the custom session. 
              role_session_name='<YOUR_ROLE_SESSION_NAME>'
          )
          response = sts_client.assume_role(assume_role_request)
          token = json.dumps(response.body.credentials.to_map())
          return token
      
      app.run(host="0.0.0.0", port=80)
    3. サンプルコードの <YOUR_ROLE_ARN> を、手順3で作成したRAMロールのARNに置き換えます。

    4. <YOUR_ROLE_SESSION_NAME> をセッションのカスタム名に置き換えます。 例: role_session_test

  6. 手順1で取得したAccessKeyペアを使用してアプリケーションを起動します。

    ALIBABA_CLOUD_ACCESS_KEY_ID=<YOUR_AK_ID> ALIBABA_CLOUD_ACCESS_KEY_SECRET=<YOUR_AK_SECRET> python3 main.py
  7. ブラウザのアドレスバーに、http://<ECS-public-IP-address>/get_sts_token と入力します。

    サンプル成功応答:

    sts token.png

  8. Ctrl + Cを押してアプリケーションを停止します。

ステップ7: ブラウザで一時的なアクセス資格情報を使用してファイルをOSSにアップロードする

アプリケーションサーバーで /get_sts_token操作を設定した後、Alibaba Cloud CDNを使用してwebアプリケーションのフロントエンドページにOSS SDK for JavaScriptをインポートします。 バケットにデータをアップロードするときは、/get_sts_token操作を呼び出して、STSから一時的なアクセス資格情報を取得し、一時的なアクセス資格情報を使用してデータをアップロードします。

次の手順では、OSS SDK for JavaScriptをECSインスタンス上のwebアプリケーションのフロントエンドコードに統合する方法について説明します。

  1. Ctrl + Cを押してアプリケーションを停止します。

  2. フロントエンドプロジェクトファイルを作成します。 サンプルコマンド:

    mkdir templates
  3. HTMLファイルを作成します。

    1. templatesディレクトリにindex.htmlファイルを作成します。

      vim templates/index.html
    2. 次のHTMLコードをHTMLファイルに書き込みます。

      <!DOCTYPE html>
      <html lang="zh-CN">
        <head>
          <meta charset="UTF-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <title>Upload an object to OSS</title>
          <script src="https://gosspublic.alicdn.com/aliyun-oss-sdk-6.17.0.min.js"></script>
        </head>
        <body>
          <div class="container">
            <form>
              <div class="mb-3">
                <label for="file" class="form-label">Select File</label>
                <input
                  type="file"
                  class="form-control"
                  id="file"
                  name="file"
                  required
                />
              </div>
              <button type="submit" class="btn btn-primary">Upload</button>
            </form>
          </div>
          <script type="text/javascript">
            let credentials = null;
            const form = document.querySelector("form");
            form.addEventListener("submit", async (event) => {
              event.preventDefault();
              // Re-obtain the temporary access credentials when they expire. This reduces the number of STS calls.
              if (isCredentialsExpired(credentials)) {
                const response = await fetch("/get_sts_token", {
                  method: "GET",
                });
                if (!response.ok) {
                  // Handle the errors based on the HTTP status codes.
                  throw new Error(
                    `Failed to obtain STS token: ${response. Status} ${response.statusText}`
                  );
                }
                credentials = await response.json();
              }
              const client = new OSS({
                // Replace <YOUR_BUCKET> with the name of the OSS bucket. 
                bucket: "<YOUR_BUCKET>",
                // Replace <YOUR_REGION> with the ID of the region in which the OSS bucket is located. Example: oss-cn-hangzhou. 
                region: "<YOUR_REGION>",
                // If you are using a locally-obtained ststoken parameter, manually replace credentials.xxx with the specific value of the obtained parameter.
                accessKeyId: credentials.AccessKeyId,
                accessKeySecret: credentials.AccessKeySecret,
                stsToken: credentials.SecurityToken,
              });
      
              const fileInput = document.querySelector("#file");
              const file = fileInput.files[0];
              const result = await client.put('uploads/'+file.name, file);
              console.log(result);
            });
      
            /**
             * Check whether the temporary access credentials expire. 
             **/
            function isCredentialsExpired(credentials) {
              if (!credentials) {
                return true;
              }
              // If you are using a locally-obtained ststoken parameter, manually replace credentials.xxx with the specific value of the obtained parameter.
              const expireDate = new Date(credentials.Expiration);
              const now = new Date();
              // If the remaining validity period of the temporary access credentials is less than 1 minute, the temporary access credentials are considered expired. 
              return expireDate.getTime() - now.getTime() <= 60000;
            }
          </script>
        </body>
      </html>
    3. コード内の <YOUR_BUCKET<YOUR_REGION> を、作成したバケットの名前とバケットが配置されているリージョンのIDに置き換えます。 リージョンIDの詳細については、「リージョン、エンドポイント、オープンポート」をご参照ください。

  4. 手順1で取得したAccessKeyペアを使用してアプリケーションを起動します。

    ALIBABA_CLOUD_ACCESS_KEY_ID=<YOUR_AK_ID> ALIBABA_CLOUD_ACCESS_KEY_SECRET=<YOUR_AK_SECRET> python3 main.py
  5. ブラウザのアドレスバーで http://<ECS-public-IP-address> を開きます。 webページで、ファイルをアップロードします。

操作の検証とリソースのクリーンアップ

操作確認

アップロード操作が完了したら、オブジェクトがバケットに存在するかどうかを確認します。

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

  2. 左側のナビゲーションウィンドウで、[バケット] をクリックします。

  3. [バケット] ページで、管理するOSSバケットを見つけ、バケット名をクリックします。

  4. [オブジェクト] ページで、オブジェクトが存在するかどうかを確認します。

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

webアプリケーションを構築するために、ECSインスタンス、OSSバケット、RAMユーザー、およびRAMロールを作成しました。 検証が完了したら、これらのリソースをリリースして、不要な料金を回避し、関連するセキュリティリスクを排除できます。

次に何をすべきか

オブジェクトをバケットにアップロードした後、次の操作を実行できます。

  • 署名付きURLを使用して、他のユーザーがオブジェクトをダウンロードまたはプレビューできるようにします。 詳細については、「オブジェクトとオブジェクトURLの共有」をご参照ください。

  • 画像オブジェクトを処理します。 たとえば、画像に透かしを追加したり、画像形式を変換したりできます。 詳細については、「概要」をご参照ください。

よくある質問

アップロードされたオブジェクトのURLを取得するにはどうすればよいですか?

アップロードされたオブジェクトのURLは、オブジェクトを格納するバケットのドメイン名とオブジェクトパスに基づいて取得できます。 詳細については、「署名付きURLでのオブジェクトの共有」をご参照ください。