Перейти к содержанию

Глава 10. Условия заголовков

Условия заголовков позволяют проверять значения HTTP-заголовков запроса и ответа. Поддерживаются проверки по точному совпадению, подстроке, регулярному выражению, wildcard-шаблону и наличию заголовка.

CPL различает два типа заголовков:

  • Распознанные заголовки (request.header., response.header.) — стандартные HTTP-заголовки (Host, User-Agent, Content-Type, Cookie и др.). Используйте эти условия для проверки любых заголовков, определённых в RFC 7230-7235 и других HTTP-стандартах.
  • Пользовательские заголовки (request.x_header.) — нестандартные заголовки, обычно начинающиеся с X-. В BlueCoat пользовательские заголовки рекомендуется тестировать через request.x_header., однако Redcoat принимает оба варианта — request.header. и request.x_header. обрабатываются одним парсером и обрабатываются одинаково.

10.1. request.header.header_name=

Проверяет значение указанного заголовка HTTP-запроса по точному совпадению, wildcard-шаблону или регулярному выражению.

Описание (BlueCoat): Tests the specified request header (header_name) against a regular expression or a string. Any recognized HTTP request header can be tested. For custom headers, use request.x_header.header_name= instead. For streaming requests, only the User-Agent header is available.

Синтаксис:

request.header.header_name=pattern

где:

  • header_name — имя HTTP-заголовка (регистронезависимо);
  • pattern — значение для сравнения:
  • строка без кавычек — точное совпадение;
  • строка с * или ? — wildcard-шаблон;
  • regex:выражение — регулярное выражение;
  • строка в кавычках "..." — точное или wildcard-совпадение (зависит от наличия */?);
  • * (отдельно) — любое значение (any);
  • список (val1, val2, val3) — совпадение с любым из значений.

Допустимые слои (BlueCoat): Admin, Cache, Exception, Forward, Proxy.

Транзакции: HTTP proxy, streaming transactions; для streaming-запросов доступен только заголовок User-Agent.

Примеры:

<Proxy>
    ; Блокировка запросов без кэша
    deny url=http://www.example.com request.header.Pragma="no-cache"

<Proxy>
    ; Проверка Content-Type
    request.header.Content-Type=application/json allow

<Proxy>
    ; Wildcard по User-Agent
    request.header.User-Agent=Mozilla* allow

<Proxy>
    ; Список допустимых Accept значений
    request.header.Accept=(text/html, application/json, application/xml) allow

Модификаторы строкового сравнения. В BlueCoat определены модификаторы exact, prefix, regex, substring, suffix через синтаксис request.header.header_name.string_modifier=pattern. В Redcoat из этих модификаторов реализованы .regex (раздел 10.3) и .substring (раздел 10.4) как отдельные условия. Модификаторы .exact, .prefix и .suffix в настоящее время не реализованы как отдельные формы — используйте базовую форму request.header.header_name= (точное совпадение) или .regex= для аналогичного результата.

Числовые/адресные под-условия (все поддерживаются, см. разделы 10.9–10.11):

  • request.header.header_name.address= — проверка значения заголовка как IP-адреса (поддерживает подсети), раздел 10.10a. В отличие от BlueCoat, применим к любому заголовку, а не только client-ip/X-Forwarded-For. См. также главу 23.
  • request.header.header_name.count= — проверка количества значений заголовка (раздел 10.9).
  • request.header.header_name.length= — проверка длины значения заголовка (раздел 10.10).

Действия над заголовками. В BlueCoat CPL заголовки запросов можно не только проверять, но и модифицировать действиями: set(), append(), delete(). В Redcoat реализованы: set(request.header, Name, value), append(request.header, Name, value), delete(request.header.Name) — см. главу 26.

См. также: request.header.header_name.exists= (10.2), request.header.header_name.regex= (10.3), request.header.header_name.substring= (10.4), request.x_header.header_name= (10.5), response.header.header_name= (10.7).

10.2. request.header.header_name.exists=

Проверяет, присутствует ли указанный заголовок в HTTP-запросе.

Описание (BlueCoat): Test whether the specified request header exists.

Синтаксис:

request.header.header_name.exists={yes|no}

где:

  • header_name — имя HTTP-заголовка (регистронезависимо);
  • yes — заголовок должен присутствовать;
  • no — заголовок должен отсутствовать.

Допустимые слои (BlueCoat): Exception, Proxy.

Примеры:

<Proxy>
    ; Требовать наличие Authorization
    request.header.Authorization.exists=no deny

<Proxy>
    ; Блокировка запросов с X-Debug заголовком
    request.header.X-Debug.exists=yes deny

<Exception>
    ; Исключение для запросов с Cookie
    request.header.Cookie.exists=yes exception(allow_with_cookie)

См. также: request.header.header_name= (10.1), request.x_header.header_name.exists= (10.6), response.header.header_name.exists= (10.8).

10.3. request.header.header_name.regex=

Проверяет значение указанного заголовка запроса регулярным выражением.

Описание: Это реализация модификатора .regex из request.header.header_name.string_modifier= (BlueCoat). В Redcoat реализовано.

Синтаксис:

request.header.header_name.regex="pattern"

где:

  • header_name — имя HTTP-заголовка (регистронезависимо);
  • pattern — регулярное выражение в кавычках.

Допустимые слои (BlueCoat): Admin, Cache, Exception, Forward, Proxy (как модификатор request.header).

Примеры:

<Proxy>
    ; Блокировка ботов по User-Agent
    request.header.User-Agent.regex=".*[Bb]ot.*" deny

<Proxy>
    ; Проверка формата Authorization
    request.header.Authorization.regex="^Bearer [A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+" allow

<Proxy>
    ; Проверка Referer по домену
    request.header.Referer.regex="^https://trusted\.example\.com/" allow

Отличие от базовой формы. Базовая форма request.header.header_name= с префиксом regex: (например request.header.User-Agent=regex:.*Bot.*) также поддерживает regex. Форма .regex= является явным и рекомендуемым способом.

См. также: request.header.header_name= (10.1), request.header.header_name.substring= (10.4).

10.4. request.header.header_name.substring=

Проверяет, содержит ли значение указанного заголовка запроса заданную подстроку.

Описание: Это реализация модификатора .substring из request.header.header_name.string_modifier= (BlueCoat). В Redcoat реализовано.

Синтаксис:

request.header.header_name.substring=value

где:

  • header_name — имя HTTP-заголовка (регистронезависимо);
  • value — подстрока для поиска (в кавычках или без).

Допустимые слои (BlueCoat): Admin, Cache, Exception, Forward, Proxy (как модификатор request.header).

Примеры:

<Proxy>
    ; Блокировка по подстроке в Cookie
    DENY("Too much cookie data") request.header.Cookie.substring=admin_session

<Proxy>
    ; Проверка языка
    request.header.Accept-Language.substring=en-US allow

См. также: request.header.header_name= (10.1), request.header.header_name.regex= (10.3).

10.5. request.x_header.header_name=

Проверяет значение указанного пользовательского заголовка HTTP-запроса.

Описание (BlueCoat): Tests the specified custom request header (header_name) against a regular expression or a string. To test recognized headers, use request.header.header_name= instead.

В BlueCoat CPL request.x_header. предназначен для пользовательских (нестандартных) заголовков, тогда как request.header. — для стандартных HTTP-заголовков. В Redcoat оба варианта обрабатываются одинаково, поэтому поведение идентично. Тем не менее, для совместимости с BlueCoat CPL рекомендуется использовать request.x_header. для заголовков с префиксом X-.

Синтаксис:

request.x_header.header_name=pattern

где:

  • header_name — имя пользовательского заголовка (регистронезависимо);
  • pattern — значение для сравнения (точное совпадение, wildcard, regex:, список — аналогично request.header.header_name=).

Допустимые слои (BlueCoat): Cache, Exception, Forward, Proxy.

Примеры:

<Proxy>
    ; Проверка кастомного заголовка авторизации
    request.x_header.X-Api-Key="secret-key-12345" allow

<Proxy>
    ; Проверка кастомного идентификатора
    request.x_header.X-Request-ID=regex:"^[a-f0-9]{32}$" allow

<Proxy>
    ; Маршрутизация по внутреннему заголовку
    request.x_header.X-Internal-Route=(backend-a, backend-b) \
        forward(internal_pool)

См. также: request.header.header_name= (10.1), request.x_header.header_name.exists= (10.6).

10.6. request.x_header.header_name.exists=

Проверяет, присутствует ли указанный пользовательский заголовок в HTTP-запросе.

Описание (BlueCoat): Test whether the specified custom request header exists.

В Redcoat работает аналогично условию request.header.header_name.exists=. Для .exists=no выполняется логическое отрицание.

Синтаксис:

request.x_header.header_name.exists={yes|no}

где:

  • header_name — имя пользовательского заголовка (регистронезависимо);
  • yes — заголовок должен присутствовать;
  • no — заголовок должен отсутствовать.

Допустимые слои (BlueCoat): Exception, Proxy.

Примеры:

<Proxy>
    ; Требовать наличие API-ключа
    request.x_header.X-Api-Key.exists=no deny

<Proxy>
    ; Блокировка если присутствует отладочный заголовок
    request.x_header.X-Debug-Mode.exists=yes deny

См. также: request.header.header_name.exists= (10.2), request.x_header.header_name= (10.5).

10.7. response.header.header_name=

Проверяет значение указанного заголовка HTTP-ответа.

Описание (BlueCoat): Tests the specified response header (header_name) against a regular expression or a string.

Синтаксис:

response.header.header_name=pattern

где:

  • header_name — имя HTTP-заголовка ответа (регистронезависимо);
  • pattern — значение для сравнения (точное совпадение, wildcard, regex:, список — аналогично request.header.header_name=).

В BlueCoat CPL Reference поддерживаются те же модификаторы строкового сравнения (exact, prefix, regex, substring, suffix), что и для request.header. В Redcoat для response.header реализована только базовая форма (без модификаторов .regex, .substring). Для regex-проверки используйте префикс regex: в значении.

Допустимые слои (BlueCoat): Cache, Exception, Proxy.

Примеры:

<Cache>
    ; Не кэшировать ответы с определённым Content-Type
    response.header.Content-Type="image/jpeg" cache(no)

<Exception>
    ; Кастомная страница при ошибке сервера
    response.header.X-Error-Code=500 exception(server_error_page)

<Proxy>
    ; Проверка Server заголовка через regex
    response.header.Server=regex:".*Apache.*" allow

Действия над заголовками ответа. Помимо условий, заголовки ответа можно модифицировать действиями: set(response.header, Name, value), append(response.header, Name, value), delete(response.header.Name) — см. главу 26.

См. также: response.header.header_name.exists= (10.8), request.header.header_name= (10.1).

10.8. response.header.header_name.exists=

Проверяет, присутствует ли указанный заголовок в HTTP-ответе.

Описание (BlueCoat): Test whether the specified response header exists.

Синтаксис:

response.header.header_name.exists={yes|no}

где:

  • header_name — имя HTTP-заголовка ответа (регистронезависимо);
  • yes — заголовок должен присутствовать;
  • no — заголовок должен отсутствовать.

Допустимые слои (BlueCoat): Exception, Proxy.

Примеры:

<Exception>
    ; Действие при наличии заголовка кэша
    response.header.X-Cache.exists=yes exception(cache_hit_page)

<Proxy>
    ; Блокировка ответов без Content-Length
    response.header.Content-Length.exists=no deny

См. также: response.header.header_name= (10.7), request.header.header_name.exists= (10.2).


10.9. request.header.header_name.count=

Имя как в BlueCoat.

Проверяет количество значений заголовка с указанным именем. Поддерживает диапазоны.

Отличие от BlueCoat

Redcoat хранит заголовки слитыми по имени, поэтому count считает значения, разделённые запятыми, внутри слитого заголовка, а не число отдельных вхождений строки заголовка в запросе. Для большинства заголовков (RFC 9110 list-syntax) результат совпадает.

Синтаксис:

request.header.<имя>.count={N|N..M|N..|..M}

Допустимые слои: <Proxy>.

Примеры:

<Proxy>
    ; Подозрительно много значений X-Forwarded-For (спуфинг цепочки)
    request.header.X-Forwarded-For.count=3.. deny

10.10. request.header.header_name.length=

Имя как в BlueCoat.

Проверяет длину значения заголовка (в байтах). Поддерживает диапазоны.

Синтаксис:

request.header.<имя>.length={N|N..M|N..|..M}

Допустимые слои: <Proxy>.

Примеры:

<Proxy>
    ; Аномально длинный User-Agent
    request.header.User-Agent.length=1024.. deny

10.10a. request.header.header_name.address=

Имя как в BlueCoat.

Извлекает значение указанного заголовка как IP-адрес и сравнивает его с заданным адресом, диапазоном или подсетью. Типичное применение — проверка адреса в заголовках, переносящих IP клиента (X-Forwarded-For, Client-IP, X-Real-IP).

Отличие от BlueCoat: в Redcoat условие применимо к любому заголовку, а не только к client-ip/X-Forwarded-For. См. также главу 23 (условия X-Forwarded-For).

Синтаксис:

request.header.<имя>.address={ip_address|ip_address_range|subnet|subnet_label}

где:

  • <имя> — имя HTTP-заголовка запроса (регистронезависимо);
  • ip_address — IP-адрес, например 203.0.113.5;
  • ip_address_range — диапазон, например 10.0.0.1..10.0.0.255;
  • subnet — подсеть, например 10.0.0.0/8;
  • subnet_label — метка блока define subnet.

Допустимые слои: <Proxy>.

Примеры:

<Proxy>
    ; Доверять только внутренним прокси в цепочке X-Forwarded-For
    request.header.X-Forwarded-For.address=10.0.0.0/8 allow

    ; Заблокировать запросы с конкретным исходным адресом
    request.header.X-Real-IP.address=203.0.113.5 deny

См. также: request.header.header_name= (10.1), условия X-Forwarded-For (глава 23), client.address= (глава 7).


10.11. request.header.content-length.as_number=

Имя как в BlueCoat.

Проверяет размер тела запроса как число. Поддерживает диапазоны.

Отличие от BlueCoat

Redcoat сравнивает фактический размер тела запроса (как http.request.body.size=), а не текстовое значение заголовка Content-Length. Для корректных запросов результат совпадает; для запросов с ложным Content-Length проверяется реальный размер.

Синтаксис:

request.header.content-length.as_number={N|N..M|N..|..M}

Допустимые слои: <Proxy>.

Примеры:

<Proxy>
    request.header.content-length.as_number=10485760.. deny   ; >10 МБ

10.11a. response.header.content-length.as_number=

Имя как в BlueCoat.

Проверяет значение заголовка Content-Length ответа как число. Поддерживает диапазоны. Аналог request.header.content-length.as_number= (10.11), но для стороны ответа (response).

Нюанс реализации. Для ответа (response) Redcoat сравнивает значение заголовка Content-Length (парсится как число; при отсутствии/невалидности → 0). Это отличается от request-стороны (10.11), где сравнивается фактический размер тела запроса. Для корректных ответов значение заголовка совпадает с реальным размером.

Синтаксис:

response.header.content-length.as_number={N|N..M|N..|..M}

Допустимые слои: <Exception>, <Proxy>.

Примеры:

<Proxy>
    response.header.content-length.as_number=10485760.. deny   ; ответ >10 МБ

См. также: request.header.content-length.as_number= (10.11), response.header.header_name= (10.7).


10.12. request.raw_headers.count=

Имя как в BlueCoat.

Проверяет общее количество заголовков запроса. Поддерживает диапазоны.

Синтаксис:

request.raw_headers.count={N|N..M|N..|..M}

Допустимые слои: <Proxy>.

Примеры:

<Proxy>
    ; Слишком много заголовков — возможная атака
    request.raw_headers.count=50.. deny

10.12a. response.raw_headers.count=

Имя как в BlueCoat.

Проверяет общее количество заголовков ответа. Поддерживает диапазоны. Аналог request.raw_headers.count= (10.12), но для стороны ответа.

Синтаксис:

response.raw_headers.count={N|N..M|N..|..M}

Допустимые слои: <Exception>, <Proxy>.

Транзакции: HTTP proxy.

Примеры:

<Proxy>
    ; Слишком много заголовков в ответе — возможная атака
    DENY("Too many response headers") response.raw_headers.count=40..

См. также: request.raw_headers.count= (10.12), response.raw_headers.length= (10.12b).


10.12b. response.raw_headers.length=

Имя как в BlueCoat.

Проверяет суммарный объём (в байтах) текста всех заголовков ответа. Поддерживает диапазоны. Аналог request.raw_headers.count=/.length=, но измеряет размер сырых заголовков ответа.

Синтаксис:

response.raw_headers.length={N|N..M|N..|..M}

Допустимые слои: <Exception>, <Proxy>.

Транзакции: HTTP proxy.

Примеры:

<Proxy>
    ; Слишком большой объём заголовков ответа
    DENY("Too much response header data") response.raw_headers.length=4096..

См. также: response.raw_headers.count= (10.12a), request.raw_headers.regex= (10.13).


10.13. request.raw_headers.regex=

Имя как в BlueCoat.

Проверяет конкатенированный текст всех заголовков запроса регулярным выражением. Полезно для паттернов, охватывающих несколько заголовков.

Синтаксис:

request.raw_headers.regex="pattern"

Допустимые слои: <Proxy>.

Примеры:

<Proxy>
    request.raw_headers.regex="(?i)x-debug-token" deny

10.14. request.header.Referer.url=

Имя как в BlueCoat.

Проверяет значение заголовка Referer как URL (строковое сравнение, поддерживаются wildcards строкового матчера).

Синтаксис:

request.header.Referer.url="url"

Допустимые слои: <Proxy>.

Примеры:

<Proxy>
    request.header.Referer.url="http://evil.example/landing" deny

10.15. request.header.Referer.url.host.is_private=

Имя как в BlueCoat.

Истинно, если хост в Referer — приватный IP-адрес (RFC 1918, loopback). Полезно для выявления утечек внутренних URL во внешние запросы.

Синтаксис:

request.header.Referer.url.host.is_private={yes|no}

Допустимые слои: <Proxy>.

Примеры:

<Proxy>
    request.header.Referer.url.host.is_private=yes access_log[leak_audit](yes)

Прочие компоненты Referer/Origin URL. Условия request.header.Referer.url.category=, request.header.Origin.url.category=, request.header.Origin.url.threat_risk.level= пока не поддерживаются: они принимаются парсером, но требуют движка категоризации, поэтому правило с ними не сработает. Компонентные проверки Referer.url.domain/host/path/scheme/port/extension не поддерживаются — используйте request.header.Referer.regex= как обходной путь.