2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

Webアプリケーション開発において、画像管理は避けては通れない課題です。
最適化された画像の提供はユーザー体験の向上だけでなく、パフォーマンスの最適化にもつながります。

画像のリサイズやフォーマット変換を行うためには、適切なツール・インフラの選定が必要です。
この記事では、imgproxyという画像プロキシサーバーを使った画像処理について紹介します。

imgproxyとは

imgproxyは、高速でセキュアなオープンソースの画像プロキシサーバーで、URLパラメータを利用して、画像のリサイズやフォーマット変換などの処理を行います。
Go言語と画像処理ライブラリlibvipsを使って実装されています。

起動方法

本記事では公式提供されているDockerイメージとdocker compose コマンドを使ってimgproxyを起動します。

下記のymlファイルを用意してください。

compose.yml
services:
  imgproxy:
    image: ghcr.io/imgproxy/imgproxy:latest
    ports:
      - "8080:8080"

ymlファイルの準備ができたら、docker composeでコンテナを起動しましょう。

docker compose up

ブラウザで http://localhost:8080 にアクセスして下記のようなページが表示されれば起動成功です。

image.png

実際に使ってみる

imgproxyを使って画像をリサイズしてみましょう。

  • 使用する画像URLはこちら → URL
    • Nasaが公開している画像(7680x4320)
    • imgproxyの公式ドキュメントでも使用されています

上記の画像を300x300にリサイズします。
imgproxyコンテナを起動させた状態で、下記にアクセスしてください。

http://localhost:8080/insecure/rs:fill:300:300/plain/https://mars.nasa.gov/system/downloadable_items/40368_PIA22228.jpg

ブラウザに表示された画面のスクショです。
300x300にリサイズされた画像が表示されます。

image.png

ここでは、簡単な例を紹介しました。実際は署名を使ってセキュアにしたり、元画像のURLを難読化するなど設定して使うことになります。

詳しくは後述していきます。

URLパラメータ

imgproxyのURLパラメータについて説明していきます。

URLパラメータは、署名、処理オプション、画像ソースURL、拡張子(オプション)で構成されますが、処理対象の画像URL(以降、ソース画像URL)の形式によって若干異なります。

パターン1: ソース画像URLがそのまま

http://localhost:8080/{signature}/{processing_options}/plain/{source_url}@{extension}
  • {source_url}にはソース画像URLがそのまま入る
  • /{source_url}の前に/plainというパスが入る

パターン2: ソース画像URLをbase64でエンコード

http://localhost:8080/{signature}/{processing_options}/{encoded_source_url}.{extension}
  • {encoded_source_url}には、Base64でエンコードされたソース画像URLが入る

パターン3: ソース画像URLを暗号化(PRO版)

http://localhost:8080/{signature}/{processing_options}/enc/{encrypted_source_url}.{extension}
  • {encrypted_source_url}にはAES-CBCで暗号化されたソース画像URLが入る
  • /{encrypted_source_url}の前に/encというパスが入る

URLパラメータまとめ

以上が基本的なURLのパターンになります。
URLパラメータを表にまとめました。

パラメータ 意味 参考リンク
signature 署名 (署名しない場合insecure) Signing a URL
processing_options 処理オプション (リサイズのパラメータなど)  Processing an image
source_url ソース画像URL Source URL
encoded_source_url Base64エンコードしたソース画像URL Base64 encoded
encrypted_source_url 暗号化したソース画像URL(PRO版) Encrypted with AES-CBC
extension 拡張子(オプション) Extension

各パラメータの設定方法についても後述していきます。

Base64エンコードしたソース画像URL

タイトルそのままですが、
URLセーフなBase64形式にエンコードしたソース画像URLのことです。

Base64エンコードしたソース画像URLの生成方法

Pythonで実装してみました。

def generate_base64_source_url(source_url: str) -> str:
    return base64.urlsafe_b64encode(source_url.encode()).decode()

if __name__ == "__main__":
    source_url = source_url = "https://mars.nasa.gov/system/downloadable_items/40368_PIA22228.jpg"
    print(generate_base64_source_url(source_url))
    # aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvNDAzNjhfUElBMjIyMjguanBn

処理オプション

対象の画像に適応する操作(リサイズ、クロップ、回転など)を指定します。

主な処理オプションを表に記載しました。

オプション 説明
resize (rs) リサイズ方法1とサイズを指定 rs:fill:300:300
crop (c) クロップする領域を指定 crop:1000:1000
rotate (rot) 回転する角度を指定(90度単位でサポート) rotate:180
blur (bl) ぼかしを指定 blur:30
background (bg) 塗りつぶす背景色を指定(RGBまたはHEX) bg:255:153:0, bg:ff9900

処理オプションの例

例えば、
500x500の範囲でクロップし、画像アスペクト比を維持せず300x100にリサイズするなら、処理オプションは下記の文字列になります。

insecure/crop:500:500/resize:force:300:100

以下は実際に処理をかけて表示された画像です。
微妙な画像が出来上がりました笑

image.png

これ以外にもさまざまな処理方法が存在します。

署名

画像の処理をセキュアに行うための「署名」について紹介します。

署名は画像URLが改竄されていないか確認するための暗号化されたトークンです。画像処理を外部からの不正なリクエストを防ぐことができるためセキュリティを強化できます。

署名の有効化

環境変数IMGPROXY_KEYIMGPROXY_SALTを設定することで署名を有効化できます。

IMGPROXY_KEYIMGPROXY_SALTは、

  • IMGPROXY_KEY: 16進数でエンコードされたキー
  • IMGPROXY_SALT: 16進数でエンコードされたソルト

である必要があります。

下記コマンドを使用してキーとソルトを簡単に生成することができます。

echo $(xxd -g 2 -l 64 -p /dev/random | tr -d '\n')

上記で生成したキーとソルトをIMGPROXY_KEYIMGPROXY_SALTに設定し、コンテナを再起動してください。

services:
  imgproxy:
    image: ghcr.io/imgproxy/imgproxy:latest
    ports:
      - "8080:8080"
    environment:
      - IMGPROXY_KEY=16進数でエンコードされたキー
      - IMGPROXY_SALT=16進数でエンコードされたソルト

IMGPROXY_KEYIMGPROXY_SALTは外部に公開されると署名の意味がなくなるので管理には注意が必要です。

署名URLの生成方法

署名付きURLの生成手順は下記の通りです。

  1. 署名より後のURLパスを定義しエンコード(エンコードURLパス)
  2. キーとソルト+エンコードURLパスを組み合わせてSHA256で暗号化されたHMAC署名を生成
  3. 生成されたHMAC署名をBase64エンコードしてURLセーフな形式に変換
  4. 上記の署名をURLパスのsigunatureに入れて署名付きURLが完成

といってもわかりづらいと思うので、公式のExampleを参考にPythonで署名付きURL生成関数を作成しました。

import base64
import hashlib
import hmac


def generate_base64_source_url(source_url: str) -> str:
    return base64.urlsafe_b64encode(source_url.encode()).decode()


def generate_signature_url_path(key: str, salt: str, path: str) -> str:
    key = bytes.fromhex(key)
    salt = bytes.fromhex(salt)
    path = path.encode()
    digest = hmac.new(key, msg=salt+path, digestmod=hashlib.sha256).digest()
    signature = base64.urlsafe_b64encode(digest).rstrip(b"=")
    signature_url_path = b'/%s%s' % (signature, path)
    return signature_url_path.decode()


if __name__ == "__main__":
    key = "017fd0c61f868beb9b66d74b6a9f1275"
    salt = "ab6d92e9e65e4cd804c502412acb9617"

    process_option = "/rs:fit:300:300"
    source_url = "https://mars.nasa.gov/system/downloadable_items/40368_PIA22228.jpg"
    b64_source_url = generate_base64_source_url(source_url)
    
    path = f"{process_option}/{b64_source_url}"

    signature_url_path = generate_signature_url_path(key, salt, path)
    print(signature_url_path)
    # => /YVu2QQCmvaQFTGkZ_l_NF0bT1ri6JfpEYsaX8mzJq1E/rs:fit:300:300/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvNDAzNjhfUElBMjIyMjguanBn

生成されたURLパスにアクセスしてみるとリサイズされた画像が表示されます。

http://localhost:8080/YVu2QQCmvaQFTGkZ_l_NF0bT1ri6JfpEYsaX8mzJq1E/rs:fit:300:300/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvNDAzNjhfUElBMjIyMjguanBn

下記はブラウザに表示された画面のスクショです。
無事、リサイズされていることがわかります。

image.png

不正なリクエストを検証してみる

上記で生成されたURLパスのrs:fit:300:300rs:fit:100:100に変更して画像処理部分を変更してリクエストしてみましょう。

http://localhost:8080/YVu2QQCmvaQFTGkZ_l_NF0bT1ri6JfpEYsaX8mzJq1E/rs:fit:100:100/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvNDAzNjhfUElBMjIyMjguanBn

すると403エラーForbiddenが返ってきます。
URLパラメータを改ざんできないことが確認できました。

image.png

おまけ

クラウドストレージ上の画像をimgproxyで処理する方法について紹介します。
弊社でよく使っているGoogle Cloud Storage(GCS) を対象とします。

まとめ

本記事では、imgproxyを使った画像処理について紹介しました。
imgproxyは高速で安全な画像プロキシサーバーです。豊富な画像処理オプションが存在し、署名によって不正なアクセスを防ぐ機能があります。
導入することで画像処理のロジックをWebアプリケーションから切り離すことができ、サービスの最適化にもつながってきます。

基本的な操作のみの説明になりましたが、imgproxyにはソース画像URLの制限やクラウドストレージとの連携、キャッシュの設定などWebアプリケーションで使用するために必要なさまざまな設定があります。
弊社では、特定GCSバケット内の画像に限定する設定を加え、CloudRun上に起動しています。

記事をみてimgproxyが気になった方はぜひ探ってみてください。

おわりに

ここまで読んでいただきありがとうございます!
引き続きアドベントカレンダー続きますのでよければ明日以降の記事もご覧ください!

弊社インティメート・マージャーに少しでも興味を持った方は下記もご覧ください!!

  1. リサイズの方法についてはこちらを参照してください

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?