Начиная с версии 0.8.50 в модуле Nginx secure_link появилось значительное улучшение по защите ссылок от подделывания. Как ни странно, новые возможности до сих пор не отражены в официальной документации [1]. Описание на английском можно найти на сайте Nginx Community [2], а также пояснения Сысоева по данным изменениям [3]. Код на PHP для генерации защищённых ссылок можно найти в форуме по nginx [4].
В общем, новшество выглядит так :
nginx.conf:
URL может выглядеть так: /p/HASH,TIMESTAMP/ANYTHING где
PASSWORD секретный пароль
TIMESTAMP это время до которого действительна ссылка в unix epoch
ANYTHING произволный текст
HASH кодированный в base64-URL [5] md5 хэш из шаблона secure_link_md5 ($secured_stuff = ANYTHING в данном примере). Символы '=' после base64 можно опускать
Nginx имеет пару неявных нюансов в подсчете md5 суммы:
1. строка для подсчета из URL ($secured_stuff) декодируется из URL encoding в оригинальный вид
2. md5 хэш должен передаваться в бинарном виде для кодирования в base64
код для PHP может быть такой:
Для передачи хэша и времени можно также использовать аргументы и куки:
для URL вида
где агрумент st это хэш от PASSWORD, URI и аргумента e
location вида
Как не сложно догадаться, при формировании хэша можно использовать IP адрес клиента.
Ссылки:
[1] sysoev.ru/nginx/docs/http/ngx_http_secure_link_module.html
[2] wiki.nginx.org/HttpSecureLinkModule
[3] nginx.org/pipermail/nginx/2010-September/022324.html
[4] forum.nginx.org/read.php?21,126363,128324#msg-128324
[5] en.wikipedia.org/wiki/Base64#URL_applications
В общем, новшество выглядит так :
nginx.conf:
location ~ ^/p/(?<secure>[\w-]+,\d+)/(?<secured_stuff>.+)$ { secure_link $secure; # в данном примере '$secure' = "HASH,TIMESTAMP" secure_link_md5 PASSWORD$secure_link_expires$secured_stuff; # '$secure_link_expires' это переменная nginx содержащая значение после запятой из 'secure_link' = TIMESTAMP if ($secure_link = "") { return 403; } # invalid link if ($secure_link == 0) { return 410; } # expired link # link is ok, do something here }
URL может выглядеть так: /p/HASH,TIMESTAMP/ANYTHING где
PASSWORD секретный пароль
TIMESTAMP это время до которого действительна ссылка в unix epoch
ANYTHING произволный текст
HASH кодированный в base64-URL [5] md5 хэш из шаблона secure_link_md5 ($secured_stuff = ANYTHING в данном примере). Символы '=' после base64 можно опускать
Nginx имеет пару неявных нюансов в подсчете md5 суммы:
1. строка для подсчета из URL ($secured_stuff) декодируется из URL encoding в оригинальный вид
2. md5 хэш должен передаваться в бинарном виде для кодирования в base64
код для PHP может быть такой:
$time = time() + EXPIRE_TTL; # = TIMESTAMP
$hash = md5(PASSWORD.$time.$secured_stuff, true);
$hash = strtr( base64_encode($hash), array( '+' => '-', '/' => '_', '=' => '' ));
$url = 'http://example.tld/p/$hash.','.$time.'/'.$secured_stuff;
Для передачи хэша и времени можно также использовать аргументы и куки:
для URL вида
http://example.com/p/files/top_secret.pdf?st=PIrEk4JX5gJPTGmvqJG41g&e=1324527723
где агрумент st это хэш от PASSWORD, URI и аргумента e
location вида
location /p/ { secure_link $arg_st,$arg_e; # this must match the URI part related secure_link_md5 PASSWORD$uri$arg_e; # PASSWORD is the secret token .... }
Как не сложно догадаться, при формировании хэша можно использовать IP адрес клиента.
Ссылки:
[1] sysoev.ru/nginx/docs/http/ngx_http_secure_link_module.html
[2] wiki.nginx.org/HttpSecureLinkModule
[3] nginx.org/pipermail/nginx/2010-September/022324.html
[4] forum.nginx.org/read.php?21,126363,128324#msg-128324
[5] en.wikipedia.org/wiki/Base64#URL_applications