Cloudinary におけるアクセス制限の設定方法と署名付きURL

2020.08.28

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Guten Morgen!ベルリンから伊藤です。

画像や動画のデジタルメディア管理・変換 SaaS、Cloudinaryを使うと、画像・動画の最適化ウォーターマークの追加が簡単に実現できます。

以前、Cloudinary でウォーターマークを簡単に付与し、URL操作によるウォーターマーク除去がされないようにするアクセス制限について解説しました。

Cloudinary におけるアクセス制限とウォーターマークの除去対策

本稿では、具体的にアクセス制限で Private/Authenticated へ設定する方法と、制限したアセットへアクセスするための署名付きURLの取得について解説します。

アセットを Private/Authenticated で格納

デフォルトでは、Cloudinaryに格納されるアセットはパブリックの状態で、アセットタイプ(画像であれば image/)の後に upload というタイプが使用され、アセットのパスとファイル名(パブリックID)が続きます。

https://res.cloudinary.com/CLOUD-NAME/image/upload/sample.jpg

この状態では誰でもアクセスすることができ、さらにはURL内に変換パラメータを追加・変更するだけで別の変換を適用させることができます。
変換パラメータによる即座の変換は Cloudinary の利点ではありますが、ウォーターマークを付与した画像を配信して、勝手に変換操作でロゴのない画像を取得されては困ります。

ユースケースや使い分けの詳細は前回のブログにありますが、ここでは Private、Authenticated への設定方法を説明します。

コンソール

残念ながら、現時点でコンソールからの操作は限られており、アップロード時に都度アセットタイプを指定したり、既存アセットのタイプを設定変更することはできません。一度アップロードしたアセットのタイプを変更するには、APIで変更するか、コンソールならアセットをアップロードし直す必要があります。

コンソールからアップロードする際にアセットのタイプを指定する場合、アップロードプリセットを使います。アップロードプリセットとは、アップロード設定のテンプレートのようなもので、これを使って コンソールからアップロードするすべてのアセットにタイプを指定することができます。

アップロードプリセットを作成し、Media Library のアップロードに適用させる

◆ 英語ドキュメント: How can I add upload-options when uploading via the Media-Library?

コンソールにログインして設定画面の Upload を開き、プリセットの追加に進みます。

Cloudinary - Add an upload preset

プリセットの設定画面で、Signing Mode に「Signed」(ユーザサインインした状態で使う場合)を選択し、Delivery type で選択したいタイプ「Upload」「Authenticated」「Private」のいずれかを選択します。

なお、Signing Mode「Unsigned」は、アップロードウィジェットを使って非ユーザによるアップロードを行わせる場合に指定するので、今回は使いません。

その他、格納先のフォルダ、アセットのパブリックIDにファイル名を使うかどうか、タグ付け等のオプションも適宜設定します。

Cloudinary - Configure an upload preset

プリセットを作成したら、再び設定の Upload 内、 Media library's upload presets で作成したプリセットを選択します。

Cloudinary - Set the Media Library's upload preset

これで、コンソールの Media Library からアップロードした画像はすべて、このプリセット設定を適用することになり、指定したタイプでアップロードされます。Video、Rawにもそれぞれプリセットを指定することで、同様に動画やそれ以外のアセットについてもそれぞれ指定することが可能です。

API

Upload API を使えば、タイプを指定したアップロードや変更が柔軟に行えます。ここでは、Pythonによる実行例を紹介します。

◆ 参考:PythonからCloudinaryを操作してみた | Developers.IO

アップロード時にタイプを指定する

アップロード時、typeオプションを指定するだけです。この例ではローカル画像を private としてアップロードしています。

cloudinary.uploader.upload("./cafe.png",
   public_id = "ito-test/cafe",
   type = "private")

既存アセットのタイプを変更する

タイプの変更には、Renameメソッドを使い、typeto_typeオプションを指定します。同じ名前を指定することでパブリックIDを維持することはできますが、タイプの変更によりいずれにせよ画像URLのパスが変わることにご注意ください。

この例では、タイプを authenticated から private へ変更しています。

cloudinary.uploader.rename("ito-test/cafe", "ito-test/cafe",
   type = "authenticated",
   to_type = "private")

署名付き URL の取得

署名付きURLとは s--SIGNATURE-- の形式でランダムな値が含まれるURLで、アクセス制限されたアセットを表示させるための認証として使われます。具体的には、以下のような場合に必要となります。

  • Authenticated タイプのアセットを表示させる場合
  • Private タイプのアセットのオリジナルを表示させる場合
  • Strict Transformation が有効なアカウントで許可されていない変換を適用させたアセットを表示させる場合
  • 外部のメディアからの取り込みを制限している場合

署名は Cloudinary で自動的に生成されます。生成アルゴリズムにはパブリックID、変換パラメータ、API シークレットが使われているため、同じ署名を他の変換に使い回したりすることはできません

◆ 英語ドキュメント: Signed delivery URLs

コンソール

コンソールでは、Private アセットのオリジナルURL、Authenticated アセットのすべてのURL、あるいはアカウントで Strict Transformations が有効な場合の変換URLには、自動的に署名付きURLが発行されます。

次の例は Strict Transformations が無効なアカウントの Private アセットで、オリジナルURLには署名が含まれています。

Cloudinary - Private asset on Console with signed URL

API

変換 API を使ってアセットの変換URLを取得する場合は、sign_url オプションをTrueに指定します。

cloudinary.CloudinaryImage("ito-test/cafe.jpg").image(
   height = 300,
   width = 300,
   crop = "fill",
   sign_url = True, # 署名付きURL
   type = "private", # タイプ
   secure = True # HTTPS
)
# <img height="300" src="https://res.cloudinary.com/CLOUD-NAME/image/private/s--dvvbB4Ws--/c_fill,h_300,w_300/v1/ito-test/cafe.jpg" width="300"/>

ユースケース

一度公開してアクセスされたアセットを非表示にする

既にユーザによるアクセス済みでキャッシュされているアセットについても、これをやっぱり非表示にさせたいという場合には、URL変更とキャッシュ無効化を行えばOKです。

例えば、ウェブサイト内に以下のような画像URLが埋め込まれていたとします。ウェブサイト上でこのコンテンツを取り下げたとしても、このままでは画像URLには引き続きアクセス可能です。

<img src="https://res.cloudinary.com/CLOUD-NAME/image/upload/c_fill,e_improve,f_auto,g_auto,h_600,q_auto:best,w_600/v1/ito-test/cafe.jpg" alt="Photogenic cafe" />

URL変更として、以下の2つの方法があります。

  1. パブリックID(フォルダパスまたはファイル名)を変更する
  2. 配信タイプを Authenticated にする

どちらかだけでも非表示にさせられますが、1のみで Public または Private アセットのままでは、もし名前が予想されるなどして知れてしまった場合にアセットにアクセスされる可能性があります。確実にアクセスを防ぎたい場合には、両方を行う必要があります。

 

■例

以下で、フォルダパスを変更し、パブリックの画像を authenticated に切り替え、さらに invalidate オプションを有効にすることで既存CDNキャッシュを無効化しています。これにより、すぐに元のパブリックの画像URLにアクセスすることができなくなります。

cloudinary.uploader.rename("ito-test/cafe", "hide/cafe",
   type = "upload",
   to_type = "authenticated",
   invalidate = True)

※ 完全にCDN伝播させるため、キャッシュ無効化には、数分(最大1時間)かかります。
※ キャッシュ無効化しない場合、キャッシュの保持期間(アセットやURLの種類により異なり、デフォルトでは30日)は元のURLが引き続きアクセス可能です。

◆ 参考:CDNキャッシュ保持期間 - For how long does Cloudinary cache my delivered content on the CDN?

 

■Authenticatedタイプへの変更後

authenticated へ変更した後も、署名付きURLを発行することでアクセスは可能です。

cloudinary.CloudinaryImage("hide/cafe.jpg").image(transformation=[
  { 'raw_transformation' : "c_fill,e_improve,f_auto,g_auto,h_600,q_auto:best,w_600" }
  ],
  type = "authenticated",
  sign_url = True,
  secure = True)
# '<img src="https://res.cloudinary.com/CLOUD-NAME/image/authenticated/s--Yssbotd7--/c_fill,e_improve,f_auto,g_auto,h_600,q_auto:best,w_600/v1/hide/cafe.jpg"/>'
# # ↑署名URLはアクセス可能
# # ↓正しいパブリックIDを使っても署名URLがないとアクセス不可
# # https://res.cloudinary.com/CLOUD-NAME/image/upload/c_fill,e_improve,f_auto,g_auto,h_600,q_auto:best,w_600/v1/hide/cafe.jpg

 

署名付きURLを無効化する

前述の説明の通り、署名はパブリックIDと変換パラメータの組み合わせに基づいて生成されており、署名付きURLの署名だけを更新・無効化するといったことは残念ながらできません。

ですので、一度配信された署名付きURLを非表示にするには、前項と同様にやはりパブリックIDを変更することでURL変更し、キャッシュを無効化する必要があります。

なお、デフォルトでは署名付きで配信されたURLはキャッシュ無効化させることができませんので、有効にするにはサポートヘ問い合わせます。

◆ 参考:正しく無効化されない原因 - Why wasn't my URL properly invalidated?

また、初めからアセットを一時的に配信するつもりの場合には、Privateの時間制限付きURLを発行するか、トークンベース/クッキーベース認証を発行して時間制限を設けることができます。こちらのブログでも最後に紹介されています。

◆ 英語ドキュメント: Providing time-limited access to private media assets

その他

Access mode 機能との違い

本稿で紹介した private、authenticated は配信タイプと称されていますが、よく似た機能でアクセスモードというものがあります。現時点でドキュメントでも同じページに掲載されており、public か authenticated から指定することができ、非常に似ています。

配信タイプでは upload、private、authenticated でそれぞれURLにも影響があるのに対し、アクセスモードではURLは upload のまま、authenticatedの機能を使うことができます。しかし、サポートに確認したところ、アクセスモードは廃止予定の機能とのことでした。

実際に、API でアップロード時の指定(以下)や更新(cloudinary.api.update_resources_access_mode, cloudinary.api.update_resources_access_mode_by_ids)を試しましたが、Python・Node.js とも、アトリビュートが存在しないといったエラーが出力されました。念のため Github からも含まれていないことを確認しました。

>>> cloudinary.uploader.upload("Pictures/stairs.png", { access_mode: "authenticated" });
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'access_mode' is not defined

なお、プリセットの設定で access mode に「Authenticated」を指定することでアップロードは可能ですが、配信タイプと同様にコンソールからは変更できず、APIもこの通り使えないので、実質その後の設定変更ができません。当然、配信タイプとは独立した設定のため、Renameメソッドなど使ってもアクセスモードの変更はできず、配信タイプと重複して設定を持つことになるようでした。

◆ 英語ドキュメント: Access mode

Private/Authenticated アセットのオーバーレイ

authenticated の画像変換を取得するには、当然署名付きURLが必要ですが、パブリック画像の変換でオーバーレイとして authenticated 画像を入れた場合どうなるのか?

  • authenticated アセットの変換:署名URLが必要
  • パブリックアセットの変換:署名URLが不要
  • パブリックアセットの変換(authenticatedアセットのオーバーレイ):???

ベース画像がパブリックなので、抜け穴的に署名なしでもオーバーレイなら authenticated アセットを取得できるのではないか? と思ったんですが...

# OK (パブリックアセットのみ)
https://res.cloudinary.com/CLOUD-NAME/image/upload/c_scale,w_400/v1592053931/ito-test/gallery.jpg
# NG(署名なし:authenticated アセットのオーバーレイ)
https://res.cloudinary.com/CLOUD-NAME/image/upload/c_scale,w_400/l_cm_logo/v1592053931/ito-test/gallery.jpg
# NG(署名あり:authenticated アセットのオーバーレイ)
https://res.cloudinary.com/mai-ito-test/image/upload/s--igtuFhvH--/c_scale,w_400/l_cm_logo/v1/ito-test/gallery.jpg

実際、署名ありでも authenticated アセットをオーバーレイさせた画像を取得することはできませんでした。(Privateも同様)

ということで、オーバーレイ・アンダーレイをする予定がある場合には、Cloudinary 内のアセットをやみくもにすべて private や authenticated で格納してはいけないなということが分かりました。

参考


クラスメソッドはCloudinaryのパートナーとして導入のお手伝いをさせていただいています。お気軽にこちらからお問い合わせください。こちらから無料でもサインアップいただけます。