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

Аутентификация в сканируемых приложениях

Механизм проверки аутентификации

Выполняет периодическую проверку действительности сессии, используя описанную в формате 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[].type указано как "TYPE_LOCAL_STORAGE".
    Если данный параметр пуст, для этого типа будет создан механизм аутентификации, использующий всё обновлённое локальное хранилище (с точностью до outputExtractors[].selectors и outputExtractors[].extractSelectorsOnly) с целью передать содержимое браузерным модулям.
  • Если поле outputExtractors[].type указано как "TYPE_COOKIE", то извлечённые Cookie автоматически создают новый механизм аутентификации, добавляющий их в аутентификационные данные с учётом свойств Domain и Path.
  • Во всех остальных случаях поле допускает ключи cookie, header, httpAuth и jsonReplacer
outputExtractors[].proxyParams.[cookie,header].name *
строка не задано Название заголовка или имя Cookie, значения которых будут заменены извлечёнными данными
outputExtractors[].proxyParams.httpAuth.username *
строка не задано Имя пользователя для базовой HTTP‑аутентификации, для которого извлечённые данные будут заменены паролем
outputExtractors[].proxyParams.jsonReplacer.path *
строка не задано Указывает путь для замены значений в JSON‑телах исходящих запросов сканера. Применяется только при одновременном соблюдении следующих условий:
  • тело запроса полностью представлено в формате JSON,
  • указанный JSON‑путь существует в структуре.
Если условия выполнены, то значение по указанному пути заменяется на данные из извлечённого источника
responseExtractors[].valueTransformationTemplate
строка не задано Поддерживается только при одновременном соблюдении следующих условий: В поле указывается шаблон, в контексте которого с помощью go text/template будут обрабатываться извлёченные значения. Результатом является строка, подставляемая в поле outputExtractors[].proxyParams.
В качестве плейсхолдеров выступают ключи извлечённых из локального хранилища пар.
Например, извлеченный по ключу токен "authToken" необходимо подставить в заголовок следующим образом: Authorization: Bearer <token>. Тогда данное поле примет значение Bearer: {{ .authToken }}, а outputExtractors[].proxyParams будет содержать объект {"header": {"name": "Authorization"}}.
Можно использовать более одного плейсхолдера.
Настоятельно рекомендуется использовать форму {{ index . "some-name" }} для передачи в шаблонную строку, потому что для шаблонизатора, например, «-» является служебным символом, поэтому в форме Bearer: {{ .some-name }} шаблон не будет успешно обработан

* Поля, помеченные звёздочкой, являются обязательными для заполнения.

Примеры конфигурации

  • Извлечение всех Cookie при наличии среди них хотя бы одного с именем «token» (если нет ни одного с именем «token» — неудача):

    {
      "outputExtractors": [
        {
          "type": "TYPE_COOKIE",
          "selectors": ["token"]
        }
      ]
    }
    
  • Извлечение Cookie с именем «token», если он присутствует (если отсутствует — неудача):

    {
      "outputExtractors": [
        {
          "type": "TYPE_COOKIE",
          "selectors": ["token"],
          "extractSelectorsOnly": true
        }
      ]
    }
    
  • Извлечение всех 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/.

  1. Откройте браузер Google Chrome в режиме инкогнито. Вкладка инкогнито
  2. Нажмите «F12» для открытия Chrome Developer Tools → нажмите «⋮» в правом верхнем углу → выберите «More Tools» → нажмите «Recorder». Как открыть рекордер
  3. Нажмите «Create a new recording». Начать создание сценария
  4. Введите имя для будущего сценария и нажмите «Start recording». Начать запись сценария
  5. Перейдите на страницу аутентификации, введите необходимые учетные данные, войдите в систему и нажимите «End recording». Запись сценария
  6. Экспортируйте полученную запись в формате JSON. Экспорт сценария

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