Skip to content

Security: foosber-byte/dnstool

SECURITY.md

Безопасность: удалённое подключение и обработка учётных данных

Этот документ - для тех, кто проверяет код перед тем, как разрешить установку (служба ИБ, аудит, самопроверка). Версия: v2.2.1. Ссылки на строки даются в формате файл:строка и относятся к состоянию кода на момент этой версии - при последующих правках номера строк могут сместиться, ориентируйтесь по названиям методов/переменных, если файл успел измениться.

1. Кратко

  • Приложение не реализует собственный сетевой протокол. Вся связь с удалённым DNS-сервером идёт через штатный WinRM (Windows Remote Management) - тот же самый транспорт, что использует Enter-PSSession, Invoke-Command и удалённое управление через dnsmgmt.msc. Ничего поверх стандартных возможностей Windows не добавляется.
  • Аутентификация - Kerberos (если клиент и сервер в одном домене) либо NTLM через TrustedHosts (если клиент вне домена). Оба механизма - встроенные в Windows, приложение их не реализует само, а просто вызывает штатный командлет New-CimSession.
  • HTTPS-транспорт и пропуск проверки TLS-сертификата, которые были в v2.1.0, полностью убраны в v2.2.1 (см. раздел 5) - сейчас в кодовой базе нет пути, который бы принимал недоверенный сертификат сервера.
  • Пароль никогда не пишется на диск - ни в файл лога, ни в файл настроек, ни во временные файлы. Хранится в памяти только как SecureString.

2. Как физически устроено подключение

2.1. Обычный режим (без явных учётных данных)

По умолчанию поле DnsHelper.ComputerName пустое, и все командлеты выполняются локально, на том же компьютере, где запущено приложение (DnsHelper.cs:22).

Если пользователь указывает целевой сервер (поле "Целевой DNS-сервер" в главном окне), это значение просто передаётся как параметр -ComputerName каждому вызову командлета (DnsHelper.cs:211) - стандартный параметр модуля DnsServer, ничего специфичного для этого приложения. Аутентификация в этом случае - текущая Windows-сессия пользователя (Kerberos с делегированием текущего токена), без ввода пароля.

2.2. Режим с явными учётными данными (другой логин/пароль)

Если требуется подключиться под другой учёткой, чем текущая Windows-сессия - открывается ServerAuthDialog (ServerAuthDialog.cs). Логика:

  1. Пароль, введённый в текстовое поле, сразу же посимвольно копируется в SecureString (ServerAuthDialog.cs:127), сразу помечается неизменяемым (.MakeReadOnly(), ServerAuthDialog.cs:129), и текстовое поле пароля немедленно очищается (ServerAuthDialog.cs:130) - обычная string-копия пароля нигде не хранится дольше, чем нужно для этого одного присваивания.
  2. SecureString передаётся в DnsHelper.TryAuthenticate (DnsHelper.cs:53), который строит из него PSCredential (DnsHelper.cs:62) и вызывает штатный командлет New-CimSession -ComputerName <сервер> -Credential <PSCredential>.
  3. New-CimSession - это командлет из модуля CimCmdlets, входящего в поставку Windows (не сторонняя библиотека). Он сам решает, как аутентифицироваться - Kerberos или NTLM - по тем же правилам, что и любой другой инструмент Windows, использующий WinRM/WSMan. Приложение не влияет на выбор протокола и не реализует его само.
  4. Созданная CimSession кешируется по серверу (DnsHelper.cs:62, словарь _cimSessions, не единственное значение на всё приложение) и используется для всех дальнейших запросов именно к этому серверу (ps.AddParameter("CimSession", ...), DnsHelper.cs:220) - то есть повторно логиниться не нужно, пока не закроется приложение. Несколько разных серверов, авторизованных с явными кредами, могут оставаться подключёнными одновременно - переключение между ними в интерфейсе не разрывает подключение к остальным (DnsHelper.cs:120).

2.3. TrustedHosts - зачем это, и это не наша настройка

Если клиентская машина не входит в домен, Kerberos физически не может работать (нет доверия к KDC), и WinRM требует одно из двух: HTTPS-транспорт, либо явное добавление целевого сервера в список TrustedHosts на клиенте. Это ограничение самого WinRM, задокументированное Microsoft - не то, что придумано в этом приложении. Соответствующая команда (Set-Item WSMan:\localhost\Client\TrustedHosts ...) выполняется пользователем вручную, в системном PowerShell, вне этого приложения - само приложение TrustedHosts никак не читает и не изменяет.

3. Права и запуск

  • Манифест - asInvoker (app.manifest:16): приложение стартует без запроса UAC вообще. Права администратора реально нужны только для локального режима (когда операция идёт против DNS-службы на этой же машине) - для удалённого управления (-ComputerName/ CimSession) права проверяются на стороне целевого сервера через Kerberos/NTLM, локальная элевация тут вообще не при чём.
  • Если локальная операция реально упирается в нехватку прав, приложение само это распознаёт (DnsHelper.cs:30, IsRunningElevated, плюс детектирование "Access Denied" в Invoke()) и предлагает перезапуск с UAC через диалог (MainForm.cs:2463, OfferAdminRelaunch) - Process.Start с Verb="runas", что запрашивает UAC у самой ОС, не у кода приложения. Показывается один раз за сессию (MainForm.cs:2431, _adminPromptShown), не спамит при повторных отказах.
  • Права на конкретные операции DNS (создание/удаление зон, записей и т.д.) отдельно проверяются на целевом сервере через Kerberos/NTLM-авторизацию (обычно требуется членство в группе DnsAdmins/Domain Admins) - то, что пользователь администратор на своей локальной машине, никак не даёт ему прав на чужом DNS-сервере.

4. Что и куда логируется

  • changes.log (FileLogger.cs:15) фиксирует только реальные изменения - создание/ удаление зон, scope, записей, подсетей, политик, а также попытки аутентификации.
  • Запись о попытке входа (FileLogger.LogChange("AUTH", ...), ServerAuthDialog.cs:143) содержит: имя сервера, введённый логин, успех/неуспех, текст ошибки (если была) - пароль в лог не передаётся ни при каком результате, метод LogChange (FileLogger.cs:49) в принципе не принимает такой параметр.
  • settings.ini хранит только пользовательские настройки интерфейса (позиции разделителей, историю адресов серверов) - учётные данные там не хранятся вообще, ни в каком виде.

5. Что было в v2.1.0 и почему убрано в v2.2.1

В v2.1.0 добавлялись два чекбокса в окне аутентификации:

  • "Подключаться через HTTPS" - WinRM поверх TLS (порт 5986) вместо обычного HTTP (5985).
  • "Пропустить проверку сертификата" - при HTTPS принимать любой сертификат сервера без проверки цепочки доверия и совпадения имени (New-CimSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck).

Почему убрано:

  1. Ненадёжно на практике. В реальном тестировании HTTPS-путь либо падал на несовпадении сертификата (сертификаты почти никогда не выпускаются на IP-адрес, только на имя сервера), либо - даже с пропуском проверки сертификата и успешным TLS-рукопожатием - сервер отвечал Access Denied на уровне уже самого WinRM/CIM. Причина в конкретной конфигурации HTTPS-листенера на сервере, не в чём-то поправимом в этом приложении.
  2. "Пропустить проверку сертификата" - осознанное снижение защиты транспорта. Такая опция принимает любой сертификат, включая поддельный (атака "человек посередине"), без предупреждения пользователю в моменте подключения. Даже если она физически не используется, сам факт наличия такого переключателя - обоснованный повод для вопросов при разборе кода. Проще и честнее убрать код целиком, чем оставлять выключенным.
  3. Обычный путь (TrustedHosts + Kerberos/NTLM) уже подтверждён рабочим - то же самое, что делает стандартный Enter-PSSession, ничего дополнительного не требуется.

Сейчас в DnsHelper.TryAuthenticate (DnsHelper.cs:53) нет параметров, включающих HTTPS или отключающих проверку сертификата - такой код физически отсутствует в файле, не просто скрыт из интерфейса.

6. Что приложение НЕ делает

Для полноты - явно перечислено, чего в коде нет:

  • Не открывает никаких сетевых портов самостоятельно (весь сетевой ввод-вывод - через штатные командлеты New-CimSession/Invoke-Command-подобные механизмы PowerShell/CIM).
  • Не хранит и не передаёт учётные данные в открытом виде на диск или по сети сверх того, что делает сам WinRM при обычной Kerberos/NTLM-аутентификации.
  • Не содержит захардкоженных учётных данных, ключей или токенов.
  • Не отключает и не ослабляет какие-либо системные настройки безопасности Windows (файрвол, WinRM-конфигурацию, TrustedHosts) - все подобные действия выполняются пользователем вручную, вне приложения, отдельными системными командами.
  • Не собирает и не отправляет телеметрию за пределы локальной сети - единственное сетевое обращение вовне (не к DNS-серверу) - необязательная проверка обновлений через GitHub API (UpdateChecker.cs), которую пользователь запускает вручную кнопкой в окне "О программе".

There aren't any published security advisories