diff --git a/README.md b/README.md index 2a2a46c..33389bc 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,8 @@ Total issues: Or something else, you can find all other `gixy` arguments with the help command: `gixy --help` # Documentation -Full documentation and recommendations can be found [here](https://github.com/yandex/gixy/wiki/ru/) (sorry, but Russian language only so far) +Full documentation and recommendations can be found [here](https://github.com/yandex/gixy/docs/ru/README.md) (sorry, but Russian language only so far) + # Contributing Contributions to Gixy are always welcome! You can help us in different ways: diff --git a/docs/ru/README.md b/docs/ru/README.md new file mode 100644 index 0000000..f394ace --- /dev/null +++ b/docs/ru/README.md @@ -0,0 +1,108 @@ +Gixy — это утилита для анализа конфигурации Nginx. Большей частью служит для обнаружения проблем безопасности, но может искать и иные ошибки. + +Перечень проблем, которые Gixy способна обнаружить: + * [[ssrf] Server Side Request Forgery](https://github.com/yandex/gixy/docs/ru/plugins/ssrf.md) + * [[http_splitting] HTTP Splitting](https://github.com/yandex/gixy/docs/ru/plugins/httpsplitting.md) + * [[origins] Проблемы валидации referrer/origin](https://github.com/yandex/gixy/docs/ru/plugins/origins.md) + * [[add_header_redefinition] Переопределение "вышестоящих" заголовков ответа директивой "add_header"](https://github.com/yandex/gixy/docs/ru/plugins/addheaderredefinition.md) + * [[host_spoofing] Подделка заголовка запроса Host](https://github.com/yandex/gixy/docs/ru/plugins/hostspoofing.md) + * [[valid_referers] none in valid_referers](https://github.com/yandex/gixy/docs/ru/plugins/validreferers.md) + * [[add_header_multiline] Многострочные заголовоки ответа](https://github.com/yandex/gixy/docs/ru/plugins/addheadermultiline.md) + +Проблемы, которым Gixy только учится можно найти в [Issues с меткой "new plugin"](https://github.com/yandex/gixy/issues?q=is%3Aissue+is%3Aopen+label%3A%22new+plugin%22) + +## Установка +Наиболее простой способ установки Gixy - воспользоваться pip для установки из Pypi: +```bash +pip install gixy +``` +Официально поддерживаются версии Python 2.7, 3.5 и 3.6 + +## Использование +После установки должна стать доступна консольная утилита `gixy`. +По умолчанию Gixy ищет конфигурацию по стандартному пути `/etc/nginx/nginx.conf`, однако вы можете указать специфичное расположение: +``` +$ gixy /etc/nginx/nginx.conf + +==================== Results =================== + +Problem: [http_splitting] Possible HTTP-Splitting vulnerability. +Description: Using variables that can contain "\n" may lead to http injection. +Additional info: https://github.com/yandex/gixy/wiki/ru/httpsplitting +Reason: At least variable "$action" can contain "\n" +Pseudo config: +include /etc/nginx/sites/default.conf; + + server { + + location ~ /v1/((?[^.]*)\.json)?$ { + add_header X-Action $action; + } + } + + +==================== Summary =================== +Total issues: + Unspecified: 0 + Low: 0 + Medium: 0 + High: 1 +``` + +Gixy умеет обрабатывать директиву `include` и попробует максимально корректно обработать все зависимости, если что-то пошло не так можно попробовать запустить `gixy` с флагом `-d` для вывода дополнительной информации. +Все доступные опции: +``` +$ gixy -h +usage: gixy [-h] [-c CONFIG_FILE] [--write-config CONFIG_OUTPUT_PATH] + [-v] [-l] [-f {console,text,json}] [-o OUTPUT_FILE] [-d] + [--tests TESTS] [--skips SKIPS] [--disable-includes] + [--origins-domains domains] + [--origins-https-only https_only] + [--add-header-redefinition-headers headers] + [nginx.conf] + +Gixy - a Nginx configuration [sec]analyzer + +positional arguments: + nginx.conf Path to nginx.conf, e.g. /etc/nginx/nginx.conf + +optional arguments: + -h, --help show this help message and exit + -c CONFIG_FILE, --config CONFIG_FILE + config file path + --write-config CONFIG_OUTPUT_PATH + takes the current command line args and writes them + out to a config file at the given path, then exits + -v, --version show program's version number and exit + -l, --level Report issues of a given severity level or higher (-l + for LOW, -ll for MEDIUM, -lll for HIGH) + -f {console,text,json}, --format {console,text,json} + Specify output format + -o OUTPUT_FILE, --output OUTPUT_FILE + Write report to file + -d, --debug Turn on debug mode + --tests TESTS Comma-separated list of tests to run + --skips SKIPS Comma-separated list of tests to skip + --disable-includes Disable "include" directive processing + +plugins options: + --origins-domains domains + Default: * + --origins-https-only https_only + Default: False + --add-header-redefinition-headers headers + Default: content-security-policy,x-xss- + protection,x-frame-options,x-content-type- + options,strict-transport-security,cache-control + + +available plugins: + host_spoofing + add_header_multiline + http_splitting + valid_referers + origins + add_header_redefinition + ssrf +``` + diff --git a/docs/ru/plugins/addheadermultiline.md b/docs/ru/plugins/addheadermultiline.md new file mode 100644 index 0000000..97e627e --- /dev/null +++ b/docs/ru/plugins/addheadermultiline.md @@ -0,0 +1,25 @@ +# [add_header_multiline] Многострочные заголовоки ответа + +Многострочных заголовков ответа стоит избегать по нескольким причинам: + * они признаны устаревшими (см. [RFC 7230](https://tools.ietf.org/html/rfc7230#section-3.2.4)); + * они никогда не поддерживались многими HTTP-клиентами и браузерами. Например, IE/Edge/Nginx. + +## Как самостоятельно обнаружить? +Пример плохой конфигурации: +```nginx +# http://nginx.org/ru/docs/http/ngx_http_headers_module.html#add_header +add_header Content-Security-Policy " + default-src: 'none'; + script-src data: https://yastatic.net; + style-src data: https://yastatic.net; + img-src data: https://yastatic.net; + font-src data: https://yastatic.net;"; + +# https://www.nginx.com/resources/wiki/modules/headers_more/ +more_set_headers -t 'text/html text/plain' + 'X-Foo: Bar + multiline'; +``` + +## Что делать? +Единственный выход - отказ от многострочных заголовок ответа. \ No newline at end of file diff --git a/docs/ru/plugins/addheaderredefinition.md b/docs/ru/plugins/addheaderredefinition.md new file mode 100644 index 0000000..f52d882 --- /dev/null +++ b/docs/ru/plugins/addheaderredefinition.md @@ -0,0 +1,65 @@ +# [add_header_redefinition] Переопределение "вышестоящих" заголовков ответа директивой "add_header" + +К сожалению, многие считают что с помощью директивы `add_header` можно произвольно доопределять заголовки ответа. +Это не так, о чем сказано в [документации](http://nginx.org/ru/docs/http/ngx_http_headers_module.html#add_header) к Nginx: +> Директив add_header может быть несколько. Директивы наследуются с предыдущего уровня при условии, что на данном уровне не описаны свои директивы add_header. + +Суть крайне проста - если у вас устанавливаются заголовки на одном уровне (например, в серверной секции), а уровнем ниже (например, в локейшене) устанавливаются какие-либо еще, то первый не будет применен. + +В этом довольно легко убедится: + - Конфигурация: +```nginx +server { + listen 80; + add_header X-Frame-Options "DENY" always; + location / { + return 200 "index"; + } + + location /new-headers { + # Add special cache control + add_header Cache-Control "no-cache, no-store, max-age=0, must-revalidate" always; + add_header Pragma "no-cache" always; + + return 200 "new-headers"; + } +} +``` + - Запрос к локейшену `/` (заголовок `X-Frame-Options` есть в ответе сервера): +```http +GET / HTTP/1.0 + +HTTP/1.1 200 OK +Server: nginx/1.10.2 +Date: Mon, 09 Jan 2017 19:28:33 GMT +Content-Type: application/octet-stream +Content-Length: 5 +Connection: close +X-Frame-Options: DENY + +index +``` + - Запрос к локейшену `/new-headers` (есть заголовки `Cache-Control` и `Pragma`, но нет `X-Frame-Options`): +```http +GET /new-headers HTTP/1.0 + + +HTTP/1.1 200 OK +Server: nginx/1.10.2 +Date: Mon, 09 Jan 2017 19:29:46 GMT +Content-Type: application/octet-stream +Content-Length: 11 +Connection: close +Cache-Control: no-cache, no-store, max-age=0, must-revalidate +Pragma: no-cache + +new-headers +``` + +## Что делать? +Существует несколько способов решить эту проблему: + - продублировать важные заголовки; + - устанавливать заголовки на одном уровне, например, в серверной секции; + - использовать модуль [ngx_headers_more](https://www.nginx.com/resources/wiki/modules/headers_more/). + +Каждый из способов имеет свои преимущества и недостатки, какой предпочесть зависит от ваших потребностей. \ No newline at end of file diff --git a/docs/ru/plugins/hostspoofing.md b/docs/ru/plugins/hostspoofing.md new file mode 100644 index 0000000..22a0115 --- /dev/null +++ b/docs/ru/plugins/hostspoofing.md @@ -0,0 +1,32 @@ +# [host_spoofing] Подделка заголовка запроса Host + +Зачастую, приложению, стоящему за Nginx, необходимо передать корректный заголовок `Host` для корректной генерации различных URL-адресов (редиректы, ресурсы, ссылки в письмах и т.д.). +Возможность его подмены злоумышленником может повлечь множестве проблем от фишинговых атак до SSRF, поэтому следует избегать таких ситуаций. + +> Возможно, ваше приложение так же ориентируется на заголовок запроса `X-Forwarded-Host`. +> В этом случае вам необходимо самостоятельно позаботится о его корректной установке при проксировании. + +## Как самостоятельно обнаружить? +Чаще всего эта проблема возникает в результате использования переменной `$http_host` вместо `$host`. + +Несмотря на их схожесть, они сильно отличаются: + * `$http` - хост в порядке приоритета: имя хоста из строки запроса, или имя хоста из заголовка `Host` заголовка запроса, или имя сервера, соответствующего запросу; + * `$http_host` - заголовок запроса "Host". + +Пример такой конфигурации: +```nginx +location @app { + proxy_set_header Host $http_host; + # Other proxy params + proxy_pass http://backend; +} +``` + +## Что делать? +К счастью, все довольно очевидно: + * перечислить корректные имена сервера в директиве `server_name`; + * всегда использовать переменную `$host`, вместо `$http_host`. + +## Дополнительная информация + * [Host of Troubles Vulnerabilities](https://hostoftroubles.com/) + * [Practical HTTP Host header attacks](http://www.skeletonscribe.net/2013/05/practical-http-host-header-attacks.html) \ No newline at end of file diff --git a/docs/ru/plugins/httpsplitting.md b/docs/ru/plugins/httpsplitting.md new file mode 100644 index 0000000..cedca60 --- /dev/null +++ b/docs/ru/plugins/httpsplitting.md @@ -0,0 +1,51 @@ +# [http_splitting] HTTP Splitting + +HTTP Splitting - уязвимость, возникающая из-за неправильной обработки входных данных. +Зачастую может быть для атак на приложение стоящее за Nginx (HTTP Request Splitting) или на клиентов приложения (HTTP Response Splitting). +Уязвимость возникает в случае, когда атакующий может внедрить символ перевода строки `\n` в запрос или ответ формируемый Nginx. + +## Как самостоятельно обнаружить? +При анализе конфигурации всега стоит обращать внимание на: + - какие переменные используются в директивах, отвечающих за формирование запросов (могут ли они содержать CRLF), например: `rewrite`, `return`, `add_header`, `proxy_set_header` или `proxy_pass`; + - используются ли переменные `$uri` и `$document_uri` и если да, то в каких директивах, т.к. они гарантированно содержат урлдекодированное значение; + - переменные, выделенные из групп с исключающим диапазоном: `(?P[^.]+)`. + +Пример плохой конфигурации с переменной, полученной из группы с исключающим диапазоном: +```nginx +server { + listen 80 default; + + location ~ /v1/((?[^.]*)\.json)?$ { + add_header X-Action $action; + return 200 "OK"; + } +} +``` + +Пример эксплуатации данной конфигурации: +```http +GET /v1/see%20below%0d%0ax-crlf-header:injected.json HTTP/1.0 +Host: localhost + +HTTP/1.1 200 OK +Server: nginx/1.11.10 +Date: Mon, 13 Mar 2017 21:21:29 GMT +Content-Type: application/octet-stream +Content-Length: 2 +Connection: close +X-Action: see below +x-crlf-header:injected + +OK +``` + +Из примера видно, что злоумышленник смог добавить заголовок ответа `x-crlf-header: injected`. Это случилось благодаря стечению нескольких обстоятельств: + - `add_header` не кодирует/валидирует переданные ему значения, считая что автор знает о последствиях; + - значение пути нормализуется перед обработкой локейшена; + - переменная `$action` была выделена из группы регулярного выражения с исключающим диапазоном: `[^.]*`; + - таким образом, значение переменной `$action` равно `see below\r\nx-crlf-header:injected` и при её использовании в формировании ответа добавился заголовок. + +## Что делать? + - старайтесь использовать более безопасные переменные, например, `$request_uri` вместо `$uri`; + - запретите перевод строки в исключающем диапазоне, например, `/some/(?[^/\s]+)` вместо `/some/(?[^/]+`; + - возможно, хорошей идеей будет добавить валидацию `$uri` (только если вы знаете, что делаете). diff --git a/docs/ru/plugins/origins.md b/docs/ru/plugins/origins.md new file mode 100644 index 0000000..eeb3ee8 --- /dev/null +++ b/docs/ru/plugins/origins.md @@ -0,0 +1,31 @@ +# [origins] Проблемы валидации referrer/origin + +Нередко валидация заголовка запроса `Referer` или `Origin` делается при помощи регулярного выражения. +Зачастую, это необходимо для условного выставления заголовка `X-Frame-Options` (защита от ClickJacking) или реализации Cross-Origin Resource Sharing. + +Наиболее распространенно два класса ошибок конфигурации, которые приводят к этой проблеме: + - ошибки в составлении регулярного выражения; + - разрешение не доверенных third-party доменов. + +> По умолчанию Gixy не валидирует регулярные выражение на предмет матчинга third-party доменов, т.к. не знает кому можно верить. +Передать список доверенных доменом можно при помощи опции `--origins-domains example.com,foo.bar` + +## Как самостоятельно обнаружить? +Все довольно "просто": + - необходимо найти все директивы `if`, которые делают проверку переменной `$http_origin` или `$http_referer`; + - убедится что в регулярном выражении нет проблем. + +Пример плохой конфигурации: +```nginx +if ($http_origin ~* ((^https://www\.yandex\.ru)|(^https://ya\.ru)/)) { + add_header 'Access-Control-Allow-Origin' "$http_origin"; + add_header 'Access-Control-Allow-Credentials' 'true'; +} +``` + +TODO(buglloc): описать типичные проблемы при составлении регулярных выражений +TODO(buglloc): Regex Ninja? + +## Что делать? +Исправить регулярное выражение или отказаться от него вовсе. +Например, если вы используете валидацию на основе регулярного выражения для проверки заголовка запроса `Referer` то, возможно (имеются противопоказания), лучшим решением было бы воспользоваться модулем [ngx_http_referer_module](http://nginx.org/ru/docs/http/ngx_http_referer_module.html) \ No newline at end of file diff --git a/docs/ru/plugins/ssrf.md b/docs/ru/plugins/ssrf.md new file mode 100644 index 0000000..b3466c6 --- /dev/null +++ b/docs/ru/plugins/ssrf.md @@ -0,0 +1,60 @@ +# [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` или иным удобным для вас образом; + * если по какой-то причине нет возможности перечислить все возможные хосты для проксирования, его стоит подписать. diff --git a/docs/ru/plugins/validreferers.md b/docs/ru/plugins/validreferers.md new file mode 100644 index 0000000..29130af --- /dev/null +++ b/docs/ru/plugins/validreferers.md @@ -0,0 +1,22 @@ +# [valid_referers] none in valid_referers + +Модуль [ngx_http_referer_module](http://nginx.org/ru/docs/http/ngx_http_referer_module.html) позволяет блокировать доступ к сервису для запросов с неверными значениями заголовка запроса `Referer`. +Зачастую используется для условного выставления заголовка `X-Frame-Options` (защита от ClickJacking), но могут быть и иные случаи. + +Типичные проблемы при конфигурировании этого модуля: + * использование `server_names` при не корректном имени сервера (директива `server_name`); + * слишком общие и/или не корректные регулярные выражения; + * использование `none`. + +> На текущий момент, Gixy умеет определять только использование `none` в качестве валидного реферера. + +## Чем плох none? +Согласно [документации](http://nginx.org/ru/docs/http/ngx_http_referer_module.html#valid_referers): +> `none` - поле “Referer” в заголовке запроса отсутствует; + +Однако, важно помнить, что любой ресурс может заставить браузер пользователя выполнить запрос без заголовка запроса `Referer`, к примеру: + - в случае редиректа в HTTPS на HTTP; + - указав соответствующую [Referrer Policy](https://www.w3.org/TR/referrer-policy/); + - обращение с opaque origin, например, используя схему `data:`. + +Таким образом, используя `none` в качестве валидного реферера вы сводиде на нет любые попытки валидации реферера. \ No newline at end of file diff --git a/gixy/plugins/add_header_multiline.py b/gixy/plugins/add_header_multiline.py index 0693a8c..a6ace2d 100644 --- a/gixy/plugins/add_header_multiline.py +++ b/gixy/plugins/add_header_multiline.py @@ -14,7 +14,7 @@ add_header Content-Security-Policy " severity = gixy.severity.LOW description = ('Multi-line headers are deprecated (see RFC 7230). ' 'Some clients never supports them (e.g. IE/Edge).') - help_url = 'https://github.com/yandex/gixy/wiki/ru/addheadermultiline' + help_url = 'https://github.com/yandex/gixy/docs/ru/plugins/addheadermultiline.md' directives = ['add_header', 'more_set_headers'] def audit(self, directive): diff --git a/gixy/plugins/add_header_redefinition.py b/gixy/plugins/add_header_redefinition.py index ac54063..8e31411 100644 --- a/gixy/plugins/add_header_redefinition.py +++ b/gixy/plugins/add_header_redefinition.py @@ -16,7 +16,7 @@ class add_header_redefinition(Plugin): severity = gixy.severity.MEDIUM description = ('"add_header" replaces ALL parent headers. ' 'See documentation: http://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header') - help_url = 'https://github.com/yandex/gixy/wiki/ru/addheaderredefinition' + help_url = 'https://github.com/yandex/gixy/docs/ru/plugins/addheaderredefinition.md' directives = ['server', 'location', 'if'] options = {'headers': {'x-frame-options', 'x-content-type-options', diff --git a/gixy/plugins/host_spoofing.py b/gixy/plugins/host_spoofing.py index 0c9ab71..f14bba5 100644 --- a/gixy/plugins/host_spoofing.py +++ b/gixy/plugins/host_spoofing.py @@ -10,7 +10,7 @@ class host_spoofing(Plugin): summary = 'The proxied Host header may be spoofed.' severity = gixy.severity.MEDIUM description = 'In most cases "$host" variable are more appropriate, just use it.' - help_url = 'https://github.com/yandex/gixy/wiki/ru/hostspoofing' + help_url = 'https://github.com/yandex/gixy/docs/ru/plugins/hostspoofing.md' directives = ['proxy_set_header'] def audit(self, directive): diff --git a/gixy/plugins/http_splitting.py b/gixy/plugins/http_splitting.py index 8206147..203dbb4 100644 --- a/gixy/plugins/http_splitting.py +++ b/gixy/plugins/http_splitting.py @@ -20,7 +20,7 @@ class http_splitting(Plugin): summary = 'Possible HTTP-Splitting vulnerability.' severity = gixy.severity.HIGH description = 'Using variables that can contain "\\n" may lead to http injection.' - help_url = 'https://github.com/yandex/gixy/wiki/ru/httpsplitting' + help_url = 'https://github.com/yandex/gixy/docs/ru/plugins/httpsplitting.md' directives = ['rewrite', 'return', 'add_header', 'proxy_set_header', 'proxy_pass'] def audit(self, directive): diff --git a/gixy/plugins/origins.py b/gixy/plugins/origins.py index 5bb8ff8..f5ff14c 100644 --- a/gixy/plugins/origins.py +++ b/gixy/plugins/origins.py @@ -17,7 +17,7 @@ class origins(Plugin): summary = 'Validation regex for "origin" or "referrer" matches untrusted domain.' severity = gixy.severity.MEDIUM description = 'Improve the regular expression to match only trusted referrers.' - help_url = 'https://github.com/yandex/gixy/wiki/ru/origins' + help_url = 'https://github.com/yandex/gixy/docs/ru/plugins/origins.md' directives = ['if'] options = { 'domains': ['*'], diff --git a/gixy/plugins/ssrf.py b/gixy/plugins/ssrf.py index dd5a88f..0449eb5 100644 --- a/gixy/plugins/ssrf.py +++ b/gixy/plugins/ssrf.py @@ -24,7 +24,7 @@ class ssrf(Plugin): summary = 'Possible SSRF (Server Side Request Forgery) vulnerability.' severity = gixy.severity.HIGH description = 'The configuration may allow attacker to create a arbitrary requests from the vulnerable server.' - help_url = 'https://github.com/yandex/gixy/wiki/ru/ssrf' + help_url = 'https://github.com/yandex/gixy/docs/ru/plugins/ssrf.md' directives = ['proxy_pass'] def __init__(self, config): diff --git a/gixy/plugins/valid_referers.py b/gixy/plugins/valid_referers.py index cfdec36..a3b2438 100644 --- a/gixy/plugins/valid_referers.py +++ b/gixy/plugins/valid_referers.py @@ -10,7 +10,7 @@ class valid_referers(Plugin): summary = 'Used "none" as valid referer.' severity = gixy.severity.HIGH description = 'Never trust undefined referer.' - help_url = 'https://github.com/yandex/gixy/wiki/ru/validreferers' + help_url = 'https://github.com/yandex/gixy/docs/ru/plugins/validreferers.md' directives = ['valid_referers'] def audit(self, directive):