SAML parser consistency: подпись и бизнес-логика должны видеть один assertion
Авторская схема Virusologia: сигналы, контрольные точки, evidence и критерий ретеста.
Коротко: SAML ломается не только из-за слабой криптографии. Опасная граница возникает, когда verifier подтверждает один XML-узел, а приложение извлекает identity из другого представления документа.

Проблема

XML Signature может быть математически корректной, но итоговая authentication decision все равно окажется неверной, если разные части SAML-библиотеки по-разному понимают namespaces, duplicate IDs, transforms или расположение assertion.

Исследование PortSwigger показывает, насколько хрупкой становится архитектура при нескольких parser passes и несогласованной canonicalization. Для production-команды важен не exploit payload, а контроль инварианта: подписан и использован один и тот же объект.

Решение: parse once и consume by reference

Входной документ должен иметь жесткий size limit, запрет DTD и external entities, строгую схему и уникальные ID. После единственного parse verifier возвращает ссылку на проверенный assertion node, а business logic читает claims только из этой ссылки без повторного XPath и повторного parse.

Audience, recipient, issuer, time window, InResponseTo и allowed algorithms должны проверяться как единый policy result. Любая неоднозначность должна завершаться fail closed и оставлять decision record.

Что проверить руками

  • Какая библиотека и какая версия реально обрабатывают SAML в каждом service provider.
  • Есть ли второй XML parser, повторный XPath или ручное извлечение claims после verify.
  • Отклоняются ли duplicate IDs, неожиданные transforms, неизвестные algorithms и лишние assertions.
  • Проверяются ли audience, recipient, ACS URL, issuer, replay cache и clock skew.
  • Есть ли regression corpus из malformed и неоднозначных документов без production credentials.

Безопасный пример: same-node contract

Псевдокод показывает архитектурный контракт. Конкретные API зависят от выбранной поддерживаемой SAML-библиотеки.

def authenticate_saml(raw_response, policy):
    document = strict_parse_once(
        raw_response,
        max_bytes=256_000,
        allow_dtd=False,
        allow_external_entities=False,
        require_unique_ids=True,
    )
    result = verify_response(document, policy)
    if not result.valid or result.assertion_node is None:
        raise AuthenticationDenied(result.reason)

    # Claims are consumed from the exact node returned by verification.
    claims = claims_from_verified_node(result.assertion_node)
    return policy.authorize(claims, result.context)

Типичные ошибки

  • Считать успешную crypto verification полной проверкой SAML response.
  • Патчить один parser edge case без regression corpus и архитектурного инварианта.
  • Разрешать слишком широкий набор algorithms и transforms ради совместимости.
  • Логировать полный assertion с PII и session-sensitive claims.

Evidence и критерий ретеста

  • Inventory содержит SP, IdP, library version, owner и supported algorithm policy.
  • Unit tests доказывают, что verify и claim consumption используют один node identity.
  • Regression corpus стабильно отклоняется после обновления library и parser dependencies.
Первичные материалы

Материал написан Virusologia с нуля как авторская инженерная интерпретация. Факты сверены по первичным публикациям, формулировки и практические выводы не копируют исходные тексты.

Этическая рамка

Материал предназначен для защиты, controlled labs и аудита систем, которыми вы владеете или на проверку которых имеете явное разрешение. Он не содержит эксплуатационных payload-цепочек или инструкций для несанкционированного доступа.