# Контракт с imgproxy `imgproxy` всегда внешний сервис для `image-platform`. ## Env ```env IMGPROXY_UPSTREAM=http://external-imgproxy.internal:8080 IMGPROXY_SIGNING_ENABLED=false IMGPROXY_KEY= IMGPROXY_SALT= ``` ## Dev режим В dev можно использовать unsigned `/unsafe` URL, если внешний `imgproxy` запущен без key/salt. Пример path: ```text /unsafe/resize:fit:800:0:0/q:80/plain/https://example.com/photo.jpg ``` ## Prod режим В prod нужно перейти на signed URLs и закрыть `/unsafe`. Path для подписи строится без `/unsafe`: ```text /resize:fit:800:0:0/q:80/plain/https://example.com/photo.jpg ``` Signature: ```text HMAC-SHA256(binary_key, binary_salt + path_bytes) base64url without padding ``` Node implementation reference: ```ts import crypto from "node:crypto" export function signImgproxyPath(keyHex: string, saltHex: string, path: string) { const key = Buffer.from(keyHex, "hex") const salt = Buffer.from(saltHex, "hex") const hmac = crypto.createHmac("sha256", key) hmac.update(Buffer.concat([salt, Buffer.from(path)])) return hmac.digest("base64url") } ``` Final signed URL: ```text {IMGPROXY_UPSTREAM}/{signature}{path} ``` ## Security rules - Не отдавать `IMGPROXY_KEY` и `IMGPROXY_SALT` в браузер. - Source URL валидировать в Backend/worker. - Разрешать только `http` и `https`. - Запрещать localhost, private IP, loopback, link-local. - Source host должен быть enabled в `allowed_image_hosts`. - Не давать клиенту произвольные imgproxy options. - Использовать presets и deterministic `variantHash`.