- PVSM.RU - https://www.pvsm.ru -
Изображение защиты
В этой статье хочу изложить нелёгкий путь, который я прошёл «защищая» изображения в вебе. Перед тем, как мы начнём это увлекательное путешествие, хочу обозначить два подхода в деле защиты изображений:
Вначале моего пути традиционно был велосипед. Много лет тому назад я разрабатывал один замечательный проект. Там было очень много чудесных фотографий животных и природы. Именно эти фотографии (а точнее их полноразмерный вариант) надо было защищать со всей силой. Клиент хотел не просто запретить прямые ссылки на файлы изображений, а лишить пользователя возможнсти скачать эти самые изображения. При этом накладывать водяные знаки не желал.
Мы уже читали о том, что программисты всё время врут [1]. Поэтому пришлось делать то, чего хотел клиент. Решение оказалось вполне даже симпотичным. При запросе страницы с фотографией, мы генерируем некий $secretKey
и сохраняем в сессию под этим ключём путь к полноразмерной копии изоражения:
public function actionView()
{
// ...
$_SESSION['protected-photos'][$secretKey]['file'] = $photoPath;
// ...
}
Во вьюшке же указываем путь к фотографии в следующем виде:
<img src="/photo/source/{secretKey}" />
Теперь в actionSource
мы получаем из сессии путь к полноразмерной копии фото, отправляем её с правильными заголовками и очищаем путь к полноразмерному файлу:
public function actionSource()
{
$secretKey= $_GET('key');
$session &= $_SESSION['protected-photos'];
$file = $session[$secretKey]['file'];
if (is_file($file)) {
header('Content-type: image/jpeg');
echo file_get_contents($file);
}
$session[$secretKey]['file'] = '';
}
В итоге если пользователь попытается скачать / открыть в новой вкладке / расшарить картинку, ему вернётся её маленькая копия.
Важно: Слабое место такого подхода довольно очевидно: если страницу с фотографией запросить не из браузера, а скажем через wget. В этом случае тег img
не сделает запрос /photo/source/{secretKey}
. Таким образом он будет содержать полноразмерную копию фотографии.
Позже я узнал, что самый простой и распространённый способ защиты изображений — это настроить соответствующим образом .htaccess. Можно не только запретить прямые ссылки на изображения, но и указать заглушку, которая будет отображаться на сторонних ресурсах вместо оригинальных изображений с вашего сайта. Вот пример такой конфигурации:
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^http://(.+.)?mysite.com/ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteRule .*.(jpe?g|gif|png)$ http://i.imgur.com/qX4w7.gif [L]
Первая строка содержит директиву, которая включает работу механизма преобразований. Здесь всё просто. Второй строкой мы блокируем любые сайты, кроме нашего собственного mysite.com. Код [NC] означает «без вариантов», иными словами регистронезависимое соответствие URL. Третьей строкой мы разрешаем пустые рефералы. И, наконец, последняя строка мачит все файлы с расширением JPEG, JPG, GIF или PNG и заменяет их изображением qX4w7.gif с сервера imgur.com.
При необходимости можно поступть иначе: запретить прямые ссылки на изображения для конкретных доменов.
RewriteEngine On
RewriteCond %{HTTP_REFERER} ^http://(.+.)?myspace.com/ [NC,OR]
RewriteCond %{HTTP_REFERER} ^http://(.+.)?blogspot.com/ [NC,OR]
RewriteCond %{HTTP_REFERER} ^http://(.+.)?livejournal.com/ [NC]
RewriteRule .*.(jpe?g|gif|png)$ http://i.imgur.com/qX4w7.gif [L]
Каждый RewriteCond, кроме последнего, должен содержать код [NC, OR]. OR означает «или следующий», т.е. совпадение с текущим доменом или следующим.
Также вместо изображения-заглушки можно вернуть HTTP ошибку с кодом 403:
RewriteRule .*.(jpe?g|gif|png)$ - [F]
Важно: не пытайтесь вернуть вместо изображений HTML страницу. Вы можете вернуть либо другое изображение, либоHTTP-ошибку.
Для nginx всё аналогично:
location ~* .(jpe?g|gif|png)$ {
set $bad_ref "N";
if ($http_referer !~ ^(http://(.+.)?myspace.com|http://(.+.)?blogspot.com|http://(.+.)?livejournal.com)) {
set $bad_ref "Y";
}
if ($bad_ref = "Y") {
return 444;
}
}
Amazon CloudFront является одним из лучших вариантов доставки контента пользователям. Помимо своих прямых обязанностей рядового CDN'а, он также даёт возможность генерировать подписанные ссылки. Такие ссылки дают возможность ограничить доступ к файлу по временному диапазону, а также по IP. Таким образом, например, можно указать, что изображение будет доступно в течении 10 минут. Или 7 дней начиная с завтрашнего.
Всреднем, ссылка на файл имеет следующий вид:
1http://d111111abcdef8.cloudfront.net/image.jpg?
2color=red&size=medium
3&Policy=eyANCiAgICEXAMPLEW1lbnQiOiBbeyANCiAgICAgICJSZXNvdXJjZSI6Imh0dHA 6Ly9kemJlc3FtN3VuMW0wLmNsb3VkZnJvbnQubmV0L2RlbW8ucGhwIiwgDQogICAgICAiQ 29uZGl0aW9uIjp7IA0KICAgICAgICAgIklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiI yMDcuMTcxLjE4MC4xMDEvMzIifSwNCiAgICAgICAgICJEYXRlR3JlYXRlclRoYW4iOnsiQ VdTOkVwb2NoVGltZSI6MTI5Njg2MDE3Nn0sDQogICAgICAgICAiRGF0ZUxlc3NUaGFuIjp 7IkFXUzpFcG9jaFRpbWUiOjEyOTY4NjAyMjZ9DQogICAgICB9IA0KICAgfV0gDQp9DQo
4&Signature=nitfHRCrtziwO2HwPfWw~yYDhUF5EwRunQA-j19DzZrvDh6hQ73lDx~ -ar3UocvvRQVw6EkC~GdpGQyyOSKQim-TxAnW7d8F5Kkai9HVx0FIu-5jcQb0UEmat EXAMPLE3ReXySpLSMj0yCd3ZAB4UcBCAqEijkytL6f3fVYNGQI6
5&Key-Pair-Id=APKA9ONS7QCOWEXAMPLE
А теперь по пунктам:
Важно: CloudFront не поддерживает CNAMEs с HTTPS [7]. Т.е. вы не сможете заменить https://d111111abcdef8.cloudfront.net
на https://images.example.com
. Есть два варианта решений проблемы:
https://*.cloudfront.com
для изображений.images.example.com
, но использовать его через протокол HTTP.Выбор одного из двух вариантов по сути это дело вкуса. Принципиально они между собой не отличаются.
Надеюсь описанные выше подходы помогут вам быстрее сориентироваться в нелёгком деле защиты изображений в вебе. И немного полезных ссылок по теме:
Автор: uaoleg
Источник [13]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/amazon-web-services/36032
Ссылки в тексте:
[1] всё время врут: http://habrahabr.ru/post/177591/
[2] передавать, кэшировать и логировать: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/QueryStringParameters.html
[3] хранятся на Amazon S3: http://docs.aws.amazon.com/AmazonS3/latest/dev/LogFormat.html
[4] детали: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html#private-content-custom-policy-statement
[5] детали: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html
[6] детали: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-trusted-signers.html
[7] не поддерживает CNAMEs с HTTPS: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/CNAMEs.html
[8] Hotlinking: Генератор .htaccess: http://www.htaccesstools.com/hotlink-protection/
[9] Hotlinking: Конфигурация .htaccess: http://altlab.com/htaccess_tutorial.html
[10] Hotlinking: Пример настройки nginx: http://www.webhostingtalk.com/showpost.php?s=4f4dd97cc9fc015c5ae8e773893b5a97&p=7682925&postcount=4
[11] Hotlinking: Проверка: http://altlab.com/hotlinkchecker.php
[12] Amazon CloudFront Signed URLs: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/PrivateContent.html
[13] Источник: http://habrahabr.ru/post/176299/
Нажмите здесь для печати.