mirror of https://github.com/yandex/gixy
61 lines
4.4 KiB
Markdown
61 lines
4.4 KiB
Markdown
# [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/(?<proxy_proto>https?)/(?<proxy_host>.*?)/(?<proxy_path>.*)$ {
|
||
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/(?<proxy_proto>https?)/(?<proxy_host>.*?)/(?<proxy_path>.*)$ {
|
||
internal;
|
||
|
||
proxy_pass $proxy_proto://$proxy_host/$proxy_path ;
|
||
proxy_set_header Host $proxy_host;
|
||
}
|
||
```
|
||
|
||
## Что делать?
|
||
Есть несколько правил, которых стоит придерживаться в подобного рода конфигурациях:
|
||
- использовать только internal location для проксирования;
|
||
- по возможности запретить передачу пользовательских данных;
|
||
- обезопасить адрес проксируемого сервера:
|
||
* если количество проксируемых хостов ограниченно (например, у вас S3), то лучше их захардкодить и выбирать при помощи `map` или иным удобным для вас образом;
|
||
* если по какой-то причине нет возможности перечислить все возможные хосты для проксирования, его стоит подписать.
|