Cloudinaryでアップロードしたメディアファイルのアクセスコントロールを試してみる

2020.07.03

Cloudinaryや他のSaaSを使って社内勉強会のアーカイブを閲覧できるサービスを勝手に作っていたのですが、 Cloudinaryは画像、ビデオ、その他のファイルを保存する場合、デフォルトでは、 オリジナルとその変換されたバージョンの両方がCDNを通じて公開されるという仕様があります。

ですが、全てを公開したくないといったこともあるので、Cloudinaryでメディアファイルへのアクセスを制御する方法を試していきます。

参考

Strict transformations

Cloudinaryは動的にコンテンツを変換(URLにパラメータを設定)することが可能なのが特徴ですが、全てのユーザーに許可したくないこともあるかと思います。

これを可能にするには、Cloudinaryの設定で Strict transformations を有効にします。

この設定をすると、動的な変換を許可しているメディアファイルをのぞいて(※1)、事前に生成された変換済みのメディアファイルへのアクセスのみに制限されます(※2)。

※1 明示的に許可は、Cloudinaryのコンソールから行えます)

※2 アップロード中にeagerオプションを使って生成されたもの、または認証済みAPIを使用したリクエストで生成されたもの

APIを使ってアップロード中に変換

パラメータ: height: 200, width: 300, radius: 20, crop: "fill"

## node.js
cloudinary.uploader.upload(
  "watching-you-5.gif",
  {eager: [{height: 200, width: 300, radius: 20, crop: "fill"}]},,
  function(error, result) {console.log(result, error); }
);

表示

  • パラメータ: height: 200, width: 300, radius: 20, crop: "fill"
## node.js
cloudinary.image("da4r29yqqtlayohx6osv.gif", {height: 200, width: 300, radius: 20, crop: "fill"})

<img src='https://res.cloudinary.com/classmethod-japan/image/upload/c_fill,h_200,r_20,w_300/da4r29yqqtlayohx6osv.gif' height='200' width='300'/>

これは許可された変換のため表示できます。

  • パラメータ: height: 300, width: 400
## node.js
cloudinary.image("da4r29yqqtlayohx6osv.gif", {height: 300, width: 400})

<img src='https://res.cloudinary.com/classmethod-japan/image/upload/h_300,w_400/da4r29yqqtlayohx6osv.gif' height='200' width='300'/>

見えないよ

こちらは許可されていないため表示できません。

Signed delivery URLs

表示できるようにする前に署名が検証される動的URLで、 Strict transformationsが有効になっているときに特定の派生ファイル(変換)にアクセスする、プライベート/認証済みファイルへのアクセスを許可する といったときに使えます。

URLには /s--SIGNATURE--/ の形式で追加されます。

※ 画像のpublic_idのSHA1ダイジェストと、APIシークレットと連結された変換文字列のbase64エンコーディング

URL生成・タグ生成時に sign_urlパラメータをtrueにすることで有効になります。

署名生成にはapi_secretも必要で、これは承認されていないユーザーには決して公開してはいけません。 署名はクライアント側またはネイティブアプリケーション内で生成しないようにしましょう。

Strict transformationsを有効にし、動的な変換を無効にしている時に、 元々アップロードされている画像を変換したいといった場合、署名をつけることによって変換できるようになります。

変換時に署名

  • パラメータ: height: 180, width: 250, crop: "fill", sign_url: true
## node.js
cloudinary.image("ynwipetsrauqaqwkfcsi.gif", {height: 180, width: 250, crop: "fill", sign_url: true})

<img src='https://res.cloudinary.com/classmethod-japan/image/upload/s--7JHxrl9H--/c_fill,h_180,w_250/ynwipetsrauqaqwkfcsi.gif' height='180' width='250'/>

動的な変換を無効にしていましたが、 署名されて変換し、表示でき流ようになりました。

試しにパラメータを変更してアクセスしてみます。

  • パラメータ: height: 90, width: 120, crop: "fill"
## node.js
cloudinary.image("ynwipetsrauqaqwkfcsi.gif", {height: 90, width: 120, crop: "fill"})

<img src='https://res.cloudinary.com/classmethod-japan/image/upload/c_fill,h_90,w_120/da4r29yqqtlayohx6osv.gif' height='90' width='120'/>

見えないよ

署名を作っていないため変換はできず表示できませんね。

Authenticated access to media assets

認証済みタイプで保存したり、アップロードや更新のaccess_modeやaccess_controlで一時的に認証済みのファイルとして設定したりすることができます。

これにより、元のURLとすべての派生(変換)バージョンの両方へのアクセスが制限されます。 これらのファイルとその派生バージョンには、何らかの認証がなければアクセスできません。

認証に使用できる形式には

があります。

トークンベースとCookieベースの認証はプレミアム機能となっています。(今回は試しません)

認証済みのファイルとして画像をアップロードしてみます。

アップロード

## node.js
cloudinary.uploader.upload(
  "watching-you-3.gif",
  {type: "authenticated",access_mode: "authenticated"},
  function(error, result) {console.log(result, error); }
);

アップロードした画像をそのまま表示

## node.js
cloudinary.image("pgr4v5dva6oeoqg3smal.gif", {})

<img src='https://res.cloudinary.com/classmethod-japan/image/upload/pgr4v5dva6oeoqg3smal.gif' />

見えないよ

そのままだと表示ができません。

署名付きURL認証で表示

type: "authenticated", sign_url: true を使用して署名付きのURLを発行します。

  • パラメータ: type: "authenticated", sign_url: true
## node.js
cloudinary.image("pgr4v5dva6oeoqg3smal.gif", {type: "authenticated", sign_url: true})

<img src='https://res.cloudinary.com/classmethod-japan/image/upload/pgr4v5dva6oeoqg3smal.gif' />

これは表示可能です。

署名付きURL認証を行うことで変換も可能です。

  • パラメータ: height: 200, width: 300, radius: 20, crop: "fill", type: "authenticated", sign_url: true
## node.js
cloudinary.image("pgr4v5dva6oeoqg3smal.gif", {height: 200, width: 300, radius: 20, crop: "fill", type: "authenticated", sign_url: true})

<img src='https://res.cloudinary.com/classmethod-japan/image/upload/pgr4v5dva6oeoqg3smal.gif' />

Private media assets

非公開としてアップロードすることにより、元のファイルへのアクセスを制限し、派生(変換)バージョンへのアクセスのみを許可することができます。

非公開としてアップロードされたファイルは、署名付きURLなしでは公開アクセスできません。

非公開としてアップロード

## node.js
cloudinary.uploader.upload(
  "watching-you-2.gif",
  {type: "private"},
  function(error, result) {console.log(result, error); }
);

アップロードしたファイルをそのまま表示

## node.js
cloudinary.image("ggcyoh0rjza5tbzssjsi.gif", {type: "private"});

<img src='https://res.cloudinary.com/classmethod-japan/image/private/ggcyoh0rjza5tbzssjsi.gif' />

見えないよ

表示はできません。

Strict transformationsが有効の状態で変換して表示

※ デフォルトでは、画像のすべての派生バージョンにアクセスできます。

  • パラメータ: background: "#000000", effect: "blur:400", height: 200, opacity: 90, width: 200, crop: "limit", sign_url: true, type: "private"
## node.js
cloudinary.image("ggcyoh0rjza5tbzssjsi.gif", {background: "#000000", effect: "blur:400", height: 200, opacity: 90, width: 200, crop: "limit", sign_url: true, type: "private"});

<img src='https://res.cloudinary.com/classmethod-japan/image/private/s--W77OCzs5--/b_rgb:000000,c_limit,e_blur:400,h_200,o_90,w_200/ggcyoh0rjza5tbzssjsi.gif' />

Strict transformationsが有効なので署名を作成することで表示ができるようになります。

署名なしだと、

## node.js
cloudinary.image("ggcyoh0rjza5tbzssjsi.gif", {background: "#000000", effect: "blur:400", height: 100, opacity: 90, width: 150, crop: "limit", type: "private"});

<img src='https://res.cloudinary.com/classmethod-japan/image/private/b_rgb:000000,c_limit,e_blur:400,h_100,o_90,w_150/ggcyoh0rjza5tbzssjsi.gif' />

見えないよ

表示はできません。

時間制限付きでアクセス

期間限定の署名付きURLを生成することにより、非公開のオリジナルに一時的にアクセスできるようにすることができます。

## node.js
cloudinary.utils.private_download_url(
'ggcyoh0rjza5tbzssjsi', 'gif', 
function(error, result) { console.log(result); });

https://api-ap.cloudinary.com/v1_1/classmethod-japan/image/download?timestamp=1593781771&public_id=ggcyoh0rjza5tbzssjsi&format=gif&signature=bfa13e02f29666b780f2cfebcfa13a256090d70e&api_key=~~~~~~~~~~~~~~~~

private_download_urlメソッドで払い出されたURLでアクセスが可能となります。

expires_atはUNIXTIMEで、デフォルトはURLが生成されてから1時間になっています。

※ 画像はCDNにキャッシュされません

まとめ

  • Strict transformations
    • 変換がメディアアセットに動的に適用されないようにする
  • Signed delivery URLs
    • Strict transformationsが有効の時に、特定の派生(変換)ファイルを提供する、プライベート/認証済みアセットへのアクセスを許可する など
  • Authenticated access to media assets
    • 元のURLとすべての派生(変換)バージョンの両方へのアクセスを制限する
  • Private media assets
    • 元のURLへのアクセスを制限し、派生(変換)バージョンへのアクセスのみを許可する

のアクセス制御パターンを試してみました。

意図しないアクセス、変換を考慮し使い分けることが大事かなと。