Аутентификация в сканируемых приложениях¶
Механизм проверки аутентификации¶
Выполняет периодическую проверку действительности сессии, используя описанную в формате JSON конфигурацию.
Конфигурация содержит массив критериев проверки действительности сессии.
Обязательными полями являются request, responseConditions с вложенными обязательными полями url и statusCode соответственно.
Независимо от типа критерия, он считается выполненным тогда и только тогда, когда выполнены все указанные условия. Количество раундов проверки влияет на решение об аутентификации следующим образом:
- критерий имеет вид
PASSED⇔ аутентификация считается неудачной, если критерий не выполняется N раз подряд; - критерий имеет вид
FAILED⇔ аутентификация считается неудачной, если критерий выполняется N раз подряд.
Конфигурация¶
| Тип | Значение по умолчанию | Допустимые значения | Описание |
kind * |
|||
| строка | не задано | "FAILED", "PASSED" |
Показывает, чему соответствует выполнение критерия — пройдена аутентификация или нет |
request.url * |
|||
| строка | не задано | Абсолютный URL‑адрес проверочного запроса | |
request.method |
|||
| строка | GET |
"GET", "HEAD", "OPTIONS", "TRACE", "PUT", "DELETE", "POST", "PATCH", "CONNECT" |
Метод проверочного запроса |
request.headers |
|||
| объект | не задано | Заголовки проверочного запроса в формате ключ-значение, например {"Content-Type": "application/json"} |
|
request.body |
|||
| строка | не задано | Тело проверочного запроса | |
responseConditions.statusCode * |
|||
| целое число | не задано | HTTP‑статус проверочного ответа. Не равно ⇒ критерий не выполнен | |
responseConditions.body |
|||
| строка | не задано | Регулярное выражение для проверки соответствия тела проверочного ответа. Несоответствующее регулярное выражение ⇒ критерий не выполнен | |
responseConditions.headers |
|||
| объект | не задано | Содержит пары (name, regexp) для сопоставления заголовков проверочных ответов. Любое несоответствие ⇒ критерий не выполнен |
|
interval |
|||
| строка | "10s" |
Любое число с указанием единицы измерения времени s |
Временной интервал в секундах между проверками критерия, например: "0.5s", "1s", "10s" |
rounds |
|||
| целое число | 5 |
Количество проверок критериев, гарантирующих, что аутентификация не выполнена | |
* Поля, помеченные звёздочкой, являются обязательными для заполнения.
Пример конфигурации¶
[
{
"kind": "PASSED",
"request": {
"url": "http://api.e-shop.com/profile"
},
"responseConditions": {
"statusCode": 200,
"headers": {
"Content-Type": "application/json"
}
},
"interval": "7s",
"rounds": 3
},
{
"kind": "FAILED",
"request": {
"url": "http://api.e-shop.com/"
},
"responseConditions": {
"statusCode": 200,
"body": ".*Unauthorized.*"
},
"interval": "1s",
"rounds": 7
},
{
"kind": "FAILED",
"request": {
"url": "http://api.e-shop.com/"
},
"responseConditions": {
"statusCode": 403
},
"interval": "1s",
"rounds": 7
},
{
"kind": "PASSED",
"request": {
"method": "POST",
"url": "http://api.e-shop.com/endpoint/",
"headers": {
"Content-Type": "application/json"
},
"body": "{\"data\": \"here\"}"
},
"responseConditions": {
"statusCode": 200
}
}
]
Обновление аутентификационных данных с помощью HTTP-запроса¶
Выполняет периодическое обновление сеанса, используя описанную в формате JSON конфигурацию. Работает только в сочетании с механизмом проверки аутентификации.
Конфигурация описывает способ выполнения HTTP-запроса на обновление сеанса в любом из его проявлений, а также способ настройки новых параметров аутентификации с обновленными данными.
Конфигурация¶
| Тип | Значение по умолчанию | Допустимые значения | Описание |
request.url * |
|||
| строка | не задано | Абсолютный URL‑адрес конечной точки обновления сеанса | |
request.method |
|||
| строка | "GET" |
"GET", "HEAD", "OPTIONS", "TRACE", "PUT", "DELETE", "POST", "PATCH", "CONNECT" |
HTTP‑метод конечной точки обновления сеанса |
request.headers |
|||
| объект | не задано | Содержит пары "key": "value", в которых указаны дополнительные заголовки для добавления в запрос на обновление сеанса |
|
request.body |
|||
| строка | не задано | Строковое представление тела HTTP‑запроса для обновления сеанса | |
request.timeout |
|||
| строка | "10s" |
Любое число с указанием единицы измерения времени s |
Тайм-аут HTTP‑запроса для обновления сеанса в секундах, например: "0.5s", "1s", "10s" |
responseExtractors * |
|||
| массив | не задано | Способ обработки ответа конечной точки для обновления сеанса. Каждый элемент массива описывает одну и только одну стратегию извлечения | |
responseExtractors[].extractor * |
|||
| строка | не задано | Регулярное выражение в формате RE2, результатом обработки которого будут извлечённые данные для текущего элемента массива responseExtractors. Для каждого заголовка регулярное выражение ищет соответствия в теле ответа и в заголовках ответа, представленных в строковом формате Header-Key: Header-Value. Поиск идёт до первого совпадения, после чего останавливается |
|
responseExtractors[].proxyParams |
|||
| объект | не задано | Описание механизма аутентификации, который будет добавлен после успешного извлечения данных. Возможные ключи для аутентификации: cookie, header, httpAuth, jsonReplacer. Это поле является взаимоисключающим с responseExtractors[].placeholderVariableName |
|
responseExtractors[].proxyParams.cookie |
|||
| объект | не задано | Допустимые ключи: schema, hostname, port, path, name |
|
responseExtractors[].proxyParams.header |
|||
| объект | не задано | Допустимые ключи: schema, hostname, port, path, name |
|
responseExtractors[].proxyParams.httpAuth |
|||
| объект | не задано | Допустимые ключи: schema, hostname, port, path, username |
|
responseExtractors[].proxyParams.jsonReplacer |
|||
| объект | не задано | Допустимые ключи: schema, hostname, port, path |
|
responseExtractors[].proxyParams.[cookie,header,httpAuth,jsonReplacer].schema |
|||
| строка | из базового URL‑адреса | Схема (сетевой протокол), используемая для аутентификации в сканируемом приложении | |
responseExtractors[].proxyParams.[cookie,header,httpAuth,jsonReplacer].hostname |
|||
| строка | из базового URL‑адреса | Имя хоста в любом допустимом варианте: домен (в т.ч. с поддоменами), IPv4 или IPv6 | |
responseExtractors[].proxyParams.[cookie,header,httpAuth].path |
|||
| строка | из базового URL‑адреса | Путь для аутентификации в сканируемом приложении | |
responseExtractors[].proxyParams.[cookie,header,httpAuth,jsonReplacer].port |
|||
| строка | из базового URL‑адреса | "0"–"65535" |
Номер порта для аутентификации в сканируемом приложении |
responseExtractors[].proxyParams.[cookie,header].name * |
|||
| строка | не задано | Название заголовка или имя Cookie, значения которых будут заменены извлечёнными данными | |
responseExtractors[].proxyParams.httpAuth.username * |
|||
| строка | не задано | Имя пользователя для базовой HTTP‑аутентификации, пароль которого будет заменен извлечёнными данными | |
responseExtractors[].proxyParams.jsonReplacer.path * |
|||
| строка | из базового URL‑адреса | Путь к ключам в формате JSON для изменения значения с помощью извлечённых данных | |
responseExtractors[].placeholderVariableName |
|||
| строка | не задано | Имя ключа, по которому будут храниться извлечённые данные. Эти данные будут использоваться во время следующего запроса на обновление сеанса в шаблонной части HTTP‑запроса, соответствующей упомянутому ранее ключу. Пример использования: изменение токена обновления после каждого обновления сеанса. Это поле является взаимоисключающим с responseExtractors[].proxyParams |
|
responseExtractors[].valueTransformationTemplate |
|||
| строка | не задано | Описывает контекст, в соответствующую плейсхолдеру {{ .Matched }} шаблонную часть которого подставляются извлечённые данные. Этот контекст отображается в HTTP‑запросе на обновление сессии в плейсхолдере, соответствующем значению responseExtractors[].placeholderVariableName. Пример использования: извлечённые данные должны использоваться в заголовке Authorization, но значение возвращается без префикса Bearer. Контекст будет выглядеть как Bearer {{ .Matched }} |
|
placeholdersInitValues |
|||
| объект | не задано | Содержит пары "key": "value", которые будут использоваться при заполнении вариативных частей HTTP‑запроса в полях объекта request. Все пары должны быть заполнены начальными значениями, которые будут использоваться при первом запросе обновления сеанса. Для остальных запросов на обновление сеанса значения будут переписаны с помощью извлечённых данных с соответствующим ключом responseExtractors[].placeholderVariableName |
|
dropHooksBeforeRefreshRequest |
|||
| логический | false |
true, false |
Указывает, следует ли удалять данные аутентификации (механизм аутентификации, добавленный после успешного извлечения данных) перед выполнением следующего HTTP‑запроса на обновление |
* Поля, помеченные звёздочкой, являются обязательными для заполнения.
Примеры конфигурации¶
{
"request": {
"url": "http://example.com/login",
"method": "POST",
"body": "login=admin&password=secretpass"
},
"responseExtractors": [
{
"extractor": "Set-Cookie:.*session_token=(.*);",
"proxyParams": {
"cookie": {
"name": "session_token"
}
}
}
]
}
{
"request": {
"url": "http://api.example.com/refresh-with-token",
"method": "POST",
"body": "{\"authData\": {\"refreshToken\": \"{{ .RefreshToken }}\"}}"
},
"responseExtractors": [
{
"extractor": "{\"token\": \"(.*)\",}",
"proxyParams": {
"header": {
"name": "X-Auth",
"hostname": "api.example.com"
}
}
},
{
"extractor": "\"authData\": {\"refreshToken\": \"(.*)\"}",
"placeholderVariableName": "RefreshToken"
}
],
"placeholdersInitValues": {
"RefreshToken": "c2712990-ec19-414b-8be0-8a66e9271253"
}
}
{
"request": {
"url": "http://example.com/refresh-with-token",
"method": "POST",
"body": "{\"authData\": {\"refreshToken\": \"{{ .RefreshToken }}\"}}"
},
"responseExtractors": [
{
"extractor": "{\"token\": \"(.*)\"}",
"proxyParams": {
"header": {
"name": "Authorization"
}
},
"valueTransformationTemplate": "Bearer {{ .Matched }}"
},
{
"extractor": "\"authData\": {\"refreshToken\": \"(.*)\"}",
"placeholderVariableName": "RefreshToken"
}
],
"placeholdersInitValues": {
"RefreshToken": "c2712990-ec19-414b-8be0-8a66e9271253"
}
}
Обновление аутентификационных данных с помощью браузерного сценария¶
Выполняет периодическое обновление сеанса, используя описанную в формате JSON конфигурацию и браузерный сценарий, записанный с помощью Chrome DevTools Recorder. Сущность, называемая браузерным аутентификатором, исполняет браузерный сценарий, а затем передает сканеру состояние Cookie и локального хранилища браузера на момент завершения сценария. В конфигурационном файле необходимо описать, каким образом полученные Cookie и локальное хранилище будут использоваться в обновлённых аутентификационных данных. Работает только в сочетании с механизмом проверки аутентификации. Является взаимоисключающим с механизмом обновления аутентификационных данных с помощью HTTP-запроса.
Конфигурация¶
Конфигурация регулирует исполнение браузерного сценария и описывает способ настройки новых параметров аутентификации с обновлёнными данными.
| Тип | Значение по умолчанию | Допустимые значения | Описание |
browserAuthenticatorName |
|||
| строка | "fuchsia-browser-authenticator" |
Базовое имя исполняемого файла браузерного аутентификатора. Рекомендуется не заполнять это поле и использовать значение по умолчанию | |
loginScript |
|||
| объект | не задано | Содержит объект, описывающий браузерный сценарий. При запуске сканирования через fuchsiactl рекомендуется не заполнять это поле и использовать флаг --file=@browserAuthenticator:loginScript@/path/to/script.jsonЗапуск сканирования через HTTP API возможен только с ключом, указывающим на расположение файла. При запуске через интерфейс SolidPoint это поле заполняется путём загрузки файла скрипта в параметрах сканируемой цели |
|
outputExtractors * |
|||
| массив объектов | не задано | Способ обработки новых Cookie и локального хранилища для обновления сеанса. Каждый элемент массива описывает одну и только одну стратегию извлечения данных | |
outputExtractors[].type * |
|||
| строка | не задано | "TYPE_COOKIE""TYPE_LOCAL_STORAGE" |
Тип источника данных |
outputExtractors[].selectors |
|||
| массив строк | не задано | Массив имен Cookie или ключей локального хранилища, которые должны присутствовать у браузерного аутентификатора после исполнения браузерного сценария. Если массив непустой, то при отсутствии хотя бы одного из его элементов в выводе браузерного аутентификатора обновление аутентификационных данных будет считаться неуспешным. Является обязательным полем, если задано поле outputExtractors[].extractSelectorsOnly |
|
outputExtractors[].extractSelectorsOnly |
|||
| логический | false |
true, false |
Флаг, сигнализирующий о том, стоит ли брать из вывода браузерного аутентификатора все данные или же только те, что соответствовали селекторам. Значение true является допустимым, только если заполнен массив outputExtractors[].selectors |
outputExtractors[].proxyParams |
|||
| объект | зависит от типа источника данных | Описание механизма аутентификации, который будет добавлен после успешного извлечения данных.
|
|
outputExtractors[].proxyParams.[cookie,header].name * |
|||
| строка | не задано | Название заголовка или имя Cookie, значения которых будут заменены извлечёнными данными | |
outputExtractors[].proxyParams.httpAuth.username * |
|||
| строка | не задано | Имя пользователя для базовой HTTP‑аутентификации, для которого извлечённые данные будут заменены паролем | |
outputExtractors[].proxyParams.jsonReplacer.path * |
|||
| строка | не задано | Указывает путь для замены значений в JSON‑телах исходящих запросов сканера. Применяется только при одновременном соблюдении следующих условий:
|
|
responseExtractors[].valueTransformationTemplate |
|||
| строка | не задано | Поддерживается только при одновременном соблюдении следующих условий:
go text/templateoutputExtractors[].proxyParamsВ качестве плейсхолдеров выступают ключи извлечённых из локального хранилища пар. Например, извлеченный по ключу токен "authToken" необходимо подставить в заголовок следующим образом: Authorization: Bearer <token>Bearer: {{ .authToken }}outputExtractors[].proxyParams{"header": {"name": "Authorization"}}Можно использовать более одного плейсхолдера. Настоятельно рекомендуется использовать форму {{ index . "some-name" }}-» является служебным символом, поэтому в форме Bearer: {{ .some-name }} |
|
* Поля, помеченные звёздочкой, являются обязательными для заполнения.
Примеры конфигурации¶
-
Извлечение всех Cookie при наличии среди них хотя бы одного с именем «
token» (если нет ни одного с именем «token» — неудача):
-
Извлечение Cookie с именем «
token», если он присутствует (если отсутствует — неудача):
-
Извлечение всех Cookie.
Извлечение локального хранилища и его передача браузерным модулям.
Извлечение из локального хранилища значений по ключамtoken_secret_nameиtokenи передача их в заголовокAuthorizationв соответствии с шаблоном.
Неудача для всего обновления, если хотя бы одно значение не нашлось:{ "outputExtractors": [ { "type": "TYPE_COOKIE" }, { "type": "TYPE_LOCAL_STORAGE" }, { "type": "TYPE_LOCAL_STORAGE", "selectors": ["token_secret_name", "token"], "extractSelectorsOnly": true, "proxyParams": { "hostname": "example.com", "scheme": "https", "port": "443", "header": { "name": "Authorization" } }, "valueTransformationTemplate": "Bearer {{ .token_secret_name }}||{{ .token }}" } ] }
Запись браузерного сценария¶
Для записи браузерного сценария потребуется браузер Google Chrome. Последовательность действий описана в документации Chrome для разработчиков. В данном разделе она конкретизируется с целью получения наиболее качественной записи сценария.
В качестве демонстрационного примера используется: http://juiceshop.stands.appsecuritytesting.fun/.
- Откройте браузер Google Chrome в режиме инкогнито.

- Нажмите «F12» для открытия Chrome Developer Tools → нажмите «⋮» в правом верхнем углу → выберите «More Tools» → нажмите «Recorder».

- Нажмите «Create a new recording».

- Введите имя для будущего сценария и нажмите «Start recording».

- Перейдите на страницу аутентификации, введите необходимые учетные данные, войдите в систему и нажимите «End recording».

- Экспортируйте полученную запись в формате JSON.

Полученный файл — это браузерный сценарий, необходимый для обновления аутентификационных данных сканирования.