# [ssrf] Server Side Request Forgery Server Side Request Forgery - уязвимость, позволяющая выполнять различного рода запросы от имени веб-приложения (в нашем случае от имени Nginx). Возникает, когда атакующий может контролировать адрес проксируемого сервера (второй аргумент директивы `proxy_pass`). ## Как самостоятельно обнаружить? Наиболее распространенно два класса ошибок конфигурации, которые приводят к этой проблеме: - отсутствие директивы [internal](http://nginx.org/ru/docs/http/ngx_http_core_module.html#internal). Её смысл заключается в указании того, что определенный location может использоваться только для внутренних запросов; - небезопасное внутреннее перенаправление. ### Отсутствие директивы internal Классический пример уязвимости типа SSRF в виду отсутствия директивы `internal` выглядит следующим образом: ```nginx location ~ /proxy/(.*)/(.*)/(.*)$ { proxy_pass $1://$2/$3; } ``` Злоумышленник, полностью контролируя адрес проксируемого сервера, может выполнять произвольные запросы от имени Nginx. ### Небезопасное внутреннее перенаправление Подразумевается, что в вашей конфигурации есть internal location, которые использует какие-либо данные из запроса в качестве адреса проксируемого сервера. Например: ```nginx location ~* ^/internal-proxy/(?https?)/(?.*?)/(?.*)$ { internal; proxy_pass $proxy_proto://$proxy_host/$proxy_path ; proxy_set_header Host $proxy_host; } ``` Согласно документации Nginx внутренними запросами являются: > - запросы, перенаправленные директивами **error_page**, index, random_index и **try_files**; > - запросы, перенаправленные с помощью поля “X-Accel-Redirect” заголовка ответа вышестоящего сервера; > - подзапросы, формируемые командой “include virtual” модуля ngx_http_ssi_module и директивами модуля ngx_http_addition_module; > - запросы, изменённые директивой **rewrite**.]> Соответственно, любой "неосторожный" реврайт позволит злоумышленнику сделать внутренний запрос и контролировать адрес проксируемого сервера. Пример плохой конфигурации: ```nginx rewrite ^/(.*)/some$ /$1/ last; location ~* ^/internal-proxy/(?https?)/(?.*?)/(?.*)$ { internal; proxy_pass $proxy_proto://$proxy_host/$proxy_path ; proxy_set_header Host $proxy_host; } ``` ## Что делать? Есть несколько правил, которых стоит придерживаться в подобного рода конфигурациях: - использовать только internal location для проксирования; - по возможности запретить передачу пользовательских данных; - обезопасить адрес проксируемого сервера: * если количество проксируемых хостов ограниченно (например, у вас S3), то лучше их захардкодить и выбирать при помощи `map` или иным удобным для вас образом; * если по какой-то причине нет возможности перечислить все возможные хосты для проксирования, его стоит подписать.