
Лаборатория исследований безопасности: воспроизведение CVE-2025-61584 (GHSA-9g7x-737f-5xpc) — внедрение команд через github.head_ref в рабочем процессе pull_request_target (.github/workflows/pr.yml)
Автоматически созданный исследовательский артефакт — не вышестоящий проект.
Этот репозиторий — одноразовая лаборатория, созданная автоматизированной системой для магистерской диссертации в Университете Лаваля по воспроизведению опубликованных уязвимостей в рабочих процессах GitHub Actions. Это точный снимок
serverless-dns/serverless-dnsна коммитеb0b1a1538aeb1991b5bc13dfe4e18e686913b12e(2025-04-26), распространённый под собственной лицензией этого проекта, файл которой включён без изменений в этот снимок.Вышестоящий проект не участвует, никогда не является целью, а изучаемая здесь уязвимость уже публична. Каждый секрет и переменная в этом репозитории — случайно сгенерированное фиктивное значение — никаких реальных учётных данных здесь нет. Ссылки на действия и образы раннеров закреплены на те значения, которые они имели на 2025-04-26; см.
pinning.mdв выводе системы для каждого изменения, внесённого в снимок.Вопросы или возражения: [email protected]
serverless-dns — это блокировщик контента в духе Pi-Hole, бессерверный резолвер DNS-over-HTTPS (DoH) и DNS-over-TLS (DoT). Работает из коробки на Cloudflare Workers, , и . Бесплатных тарифов всех этих сервисов должно хватить на 10–20 устройств DNS-трафика в месяц.
RethinkDNS запускает serverless-dns в продакшене на следующих конечных точках:
Обработка на стороне сервера занимает от 0 миллисекунд (мс) до 2 мс (медиана), а сквозная задержка (варьируется в зависимости от региона и сети) составляет от 10 мс до 30 мс (медиана).
Резолвер Rethink DNS на Fly.io спонсируется FOSS United.
Cloudflare Workers — самая простая платформа для настройки serverless-dns:
Пошаговые инструкции см. в документации:
| Платформа | Сложность | Среда выполнения | Документация |
|---|---|---|---|
| ⛅ Cloudflare | Лёгкая | v8 Isolates | Хостинг на Cloudflare Workers |
| 🦕 Deno.com | Средняя | Deno Isolates | Хостинг на Deno.com |
| ⏱️ Fastly Compute@Edge | Лёгкая | Fastly JS | Хостинг на Fastly Compute@Edge |
| 🪂 Fly.io | Сложная | Node MicroVM | Хостинг на Fly.io |
Чтобы настроить списки блокировки, откройте https://<my-domain>.tld/configure в браузере (должна загрузиться страница, похожая на страницу configure RethinkDNS).
За помощью или поддержкой обращайтесь: откройте issue или отправьте патч.
Код:
# перейдите в рабочую директорию
cd /my/work/dir
# клонируйте этот репозиторий
git clone https://github.com/serverless-dns/serverless-dns.git
# перейдите в serverless-dns
cd ./serverless-dns
Node:
# установите node v22+ через nvm, если требуется
# https://github.com/nvm-sh/nvm#installing-and-updating
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
nvm install --lts
# загрузите зависимости
npm i
# (необязательно) обновите зависимости
npm update
# запустите serverless-dns на node
./run n
# запустите профилировщик clinicjs.org
./run n [cpu|fn|mem]
Deno:
# установите deno.land v2+
# https://github.com/denoland/deno/#install
curl -fsSL https://deno.land/install.sh | sh
# запустите serverless-dns на deno
./run d
Fastly:
# установите node v22+ через nvm, если требуется
# установите Fastly CLI
# https://developer.fastly.com/learning/tools/cli
# запустите serverless-dns на Fastly Compute@Edge
./run f
Wrangler:
# установите Cloudflare Workers (cli), также известный как Wrangler
# https://developers.cloudflare.com/workers/cli-wrangler/install-update
npm i wrangler --save-dev
# запустите serverless-dns на Cloudflare Workers (cli)
# Убедитесь, что Wrangler настроен:
# https://developers.cloudflare.com/workers/cli-wrangler/authentication
./run w
# профилируйте wrangler с помощью Chrome DevTools
# blog.cloudflare.com/profiling-your-workers-with-wrangler
Коммиты в этом репозитории соблюдают Google JavaScript style guide (см. .eslintrc.cjs).
Git pre-commit хук запускает линтер (eslint) и форматтер (prettier) для .js файлов. Используйте git commit --no-verify,
чтобы обойти этот хук.
Pull request'ы также проверяются на нарушения стиля кода и автоматически исправляются, где это возможно.
Настройте env.js, если нужно изменить значения по умолчанию.
Для Cloudflare Workers настраивайте переменные окружения в wrangler.toml.
Для Fastly Compute@Edge настраивайте переменные окружения в fastly.toml.
serverless-dns поддерживает аутентификацию с буквенно-цифровым bearer-токеном как для DoH, так и для DoT. Для токена msg-key (секрет) добавьте вывод hex(hmac-sha256(msg-key|domain.tld), msg) в переменную окружения ACCESS_KEYS в формате csv. Примечание: msg в настоящее время зафиксирован как sdns-public-auth-info.
msg-key в конец blockstamp, например:
1:1:4AIggAABEGAgAA:<msg-key> (здесь 1 — версия, 1:4AIggAABEGAgAA
— blockstamp, <msg-key> — секрет аутентификации, а : — разделитель).msg-key в конец SNI (доменного имени), содержащего blockstamp:
1-4abcbaaaaeigaiaa-<msg-key> (здесь 1 — версия, 4abcbaaaaeigaiaa
— blockstamp, <msg-key> — секрет аутентификации, а - — разделитель).Если планируется использовать аутентификацию и с DoT, держите msg-key короче (от 8 до 24 символов), поскольку поддомены могут быть не длиннее 63 символов в сумме.
Вы можете сгенерировать ключи доступа для своего форка с max.rethinkdns.com следующим образом:
msgkey="ShortAlphanumericSecret"
domain="my-serverless-dns-domain.tld"
curl 'https://max.rethinkdns.com/genaccesskey?key='"$msgkey"'&dom='"$domain"
# вывод
# {"accesskey":["my-serverless-dns-domain.tld|deadbeefd3adb33fa2bb33fd3eadf084beef3b152beefdead49bbb2b33fdead83d3adbeefdeadb33f"],"context":"sdns-public-auth-info"}
serverless-dns можно настроить на загрузку логов через Cloudflare Logpush.
CF_ACCOUNT_ID=<hex-cloudflare-account-id>
CF_API_KEY=<api-key-with-logs-edit-permission-at-account-level>
R2_BUCKET=<r2-bucket-name>
R2_ACCESS_KEY=<r2-access-key-for-the-bucket>
R2_SECRET_KEY=<r2-secret-key-with-read-write-permissions>
# необязательно: настройте фильтр так, чтобы в push попадали только логи этого worker'а; но если
# фильтр по имени Worker (script-name) не нужен, отредактируйте поле "filter" ниже соответствующим образом.
SCRIPT_NAME=<имя-worker-как-в-wrangler-toml>
# дополнительные параметры см.: developers.cloudflare.com/logs/get-started/api-configuration
# Logpush API с cURL: developers.cloudflare.com/logs/tutorials/examples/example-logpush-curl
# Доступные поля Logpull: developers.cloudflare.com/logs/reference/log-fields/account/workers_trace_events
curl -s -X POST "https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/logpush/jobs" \
-H "Authorization: Bearer ${CF_API_KEY}" \
-H 'Content-Type: application/json' \
-d '{
"name": "dns-logpush",
"logpull_options": "fields=EventTimestampMs,Outcome,Logs,ScriptName×tamps=rfc3339",
"destination_conf": "r2://'"$R2_BUCKET"'/{DATE}?access-key-id='"${R2_ACCESS_KEY}"'&secret-access-key='"${R2_SECRET_KEY}"'&account-id='"{$CF_ACCOUNT_ID}"',
"dataset": "workers_trace_events",
"filter": "{\"where\":{\"and\":[{\"key\":\"ScriptName\",\"operator\":\"contains\",\"value\":\"'"${SCRIPT_NAME}"'\"},{\"key\":\"Outcome\",\"operator\":\"eq\",\"value\":\"ok\"}]}}",
"enabled": true,
"frequency": "low"
}'
logpush = true в wrangler.toml, что включает Logpush.LOG_LEVEL = "logpush" повышает уровень логирования так, что выводятся только запросы и логи ошибок.LOGPUSH_SRC = "csv,of,subdomains", которая заставляет log-pusher.js выводить логи запросов только если hostname Workers содержит один из поддоменов.Логи, публикуемые в R2, можно получить либо через R2 Workers, R2 API или Logpush API.
Workers Analytics, если включено, отправляется с ключом лога lid, который, если не указан, устанавливается в hostname бессерверного развёртывания с заменой точек . на подчёркивания _. Аутентификация обязательна при запросе Analytics через API, который возвращает json; например: https://max.rethinkdns.com/1:<optional-stamp>:<msg-key>/analytics?t=<time-interval-in-mins>&f=<field-name>. Возможные fields: ip (IP клиента), qname (имя DNS-запроса), region (регион резолвера), qtype (тип DNS-запроса), dom (домены верхнего уровня), ansip (IP-адреса DNS-ответов) и cc (коды стран IP-адресов ответов).
Захват логов и аналитика пока не реализованы для Fly и Deno Deploy.
Deno Deploy (облако) и Deno (среда выполнения) не предоставляют одинаковый API (например, Deno Deploy поддерживает только HTTP/S серверные слушатели; тогда как Deno поддерживает сырые TCP/UDP/TLS в дополнение к обычному HTTP и HTTP/S).
За исключением Node, serverless-dns использует вышестоящие DoH-резолверы, определённые переменными окружения CF_DNS_RESOLVER_URL / CF_DNS_RESOLVER_URL_2.
На Node вышестоящий DNS-резолвер по умолчанию — 1.1.1.2 (ссылка) или рекурсивный DNS-резолвер на fdaa::3 при работе на Fly.io.
Точки входа для Node и Deno — src/server-node.js и src/server-deno.ts соответственно,
и обе слушают TCP-over-TLS и HTTP/S соединения; тогда как точка входа для Cloudflare Workers, который слушает только HTTP (cli) или
HTTP/S (prod), — src/server-workers.js; а для Fastly — src/server-fastly.js.
В локальных (не prod) настройках на Node файлы key (приватный) и cert (публичная цепочка) по умолчанию читаются из
путей, определённых переменными окружения TLS_KEY_PATH и TLS_CRT_PATH.
Для prod-настройки на Node (на Fly.io) либо TLS_OFFLOAD должно быть установлено в true, либо key и cert должны быть
base64 закодированы в переменной окружения TLS_CERTKEY (ссылка), например:
# ЛИБО: перенесите TLS на fly.io и установите tls_offload в true
TLS_OFFLOAD="true"
# ИЛИ: base64 представление и key (приватного), и cert (публичной цепочки)
TLS_CERTKEY="KEY=b64_key_content\nCRT=b64_cert_content"
Для Deno файлы key и cert читаются из путей, определённых переменными окружения TLS_KEY_PATH и TLS_CRT_PATH (ссылка).
Запуск процесса отличается для каждой из этих сред выполнения: для Node src/core/node/config.js управляет запуском;
для Deno — src/core/deno/config.ts, а для Workers — src/core/workers/config.js.
src/system.js pub-sub координирует фазу запуска между различными модулями.
На Node и Deno внутрипроцессное кэширование DNS поддерживается @serverless-dns/lfu-cache; Cloudflare Workers поддерживается как Cache Web API, так и
внутрипроцессными lfu-кэшами. Чтобы полностью отключить кэширование на всех трёх платформах, установите переменную окружения PROFILE_DNS_RESOLVES=true.
Cloudflare Workers и Deno Deploy эфемерны, то есть «процесс», обслуживающий клиентские запросы, не является долгоживущим, и на самом деле два последовательных запроса могут обслуживаться двумя разными isolates («процессами»). Fastly Compute@Edge также эфемерен, но не использует isolates; вместо этого Fastly создаёт и уничтожает wasmtime песочницу для каждого запроса. Резолвер на Fly.io, работающий на Node, поддерживается постоянными VM и поэтому более долгоживущий, как традиционные «serverfull» среды.
Для Deno Deploy кодовая база собирается в один javascript-файл с помощью deno bundle, а затем передаётся
на Deno.com.
Конфигурации сборки и выполнения Cloudflare Workers определены в wrangler.toml.
Webpack5 собирает файлы в ESM-модуль, который затем загружается в Cloudflare с помощью Wrangler.
Конфигурации сборки и выполнения Fastly Compute@Edge определены в fastly.toml.
Webpack5 собирает файлы в ESM-модуль, который затем компилируется в WASM с помощью npx js-compute-runtime
и впоследствии упаковывается и публикуется в Fastly Compute@Edge с помощью Fastly CLI.
Для Fly.io, который работает на Node, директивы выполнения определены в fly.toml (используется типами развёртывания dev и live),
а директивы развёртывания — в node.Dockerfile. flyctl соответствующим образом
настраивает serverless-dns на инфраструктуре Fly.io.
# сборка и развёртывание для cloudflare workers.dev
npm run build
# обычно имя env — prod
npx wrangler publish [-e <env-name>]
# сборка и развёртывание для fastly compute@edge
# developer.fastly.com/reference/cli/compute/publish
fastly compute publish
# сборка и развёртывание на fly.io
npm run build:fly
flyctl deploy --dockerfile node.Dockerfile --config <fly.toml> [-a <app-name>] [--image-label <some-uniq-label>]
Для развёртываний с переносом завершения TLS на Fly.io (тип развёртывания B1) директивы выполнения вместо этого определены в
fly.tls.toml, который настраивает HTTP2 Cleartext и HTTP/1.1 на порту 443 и DNS поверх TCP на порту 853.
См.: github/workflows.
190+ списков блокировки сжаты в Succinct Radix Trie (на основе реализации Стива Ханова) с модификациями
для ускорения поиска строк (lookup) в ущерб «сжатости». Списки блокировки версионируются
меткой времени unix (определённой в src/basicconfig.json, загружаемом pre.sh), которая генерируется раз в неделю, но мы хотели бы генерировать их ежедневно / ежечасно,
если возможно см.), и размещаются на Cloudflare R2 (переменная окружения: CF_BLOCKLIST_URL).
serverless-dns загружает 3 файла списков блокировки,
необходимых для настройки radix-trie во время запуска, или загружает их лениво,
при обслуживании DNS-запроса.
serverless-dns компилирует около ~13M записей (по состоянию на январь 2023) из примерно 190+ списков блокировки. Они определены в репозитории serverless-dns/blocklists.