Безопасность SOCKS5-прокси: аутентификация, шифрование и защита от утечек | AdminWiki

Безопасность SOCKS5-прокси: аутентификация, шифрование и защита от утечек

24 сентября 2026 13 мин. чтения
Содержание статьи

SOCKS5 проксирует TCP- и UDP-сессии на транспортном уровне и не разбирает прикладной протокол. Он не шифрует payload и допускает анонимный доступ методом 0x00 из RFC 1928, если конфиг не ограничивает список методов. Порт 1080, открытый в интернет, превращает сервер в открытый релей: выйти через него сможет любой, кто достучался, а содержимое сессий защищено ровно настолько, насколько защищён канал до клиента.

Пять рисков, которые закрывает этот материал:

  • открытый порт 1080, видимый сканерам и ботам;
  • анонимный доступ и брутфорс пары логин/пароль;
  • DNS-утечка: имя резолвится на клиенте и уходит от вашего реального адреса;
  • слабые права процесса: демон работает от root и видит всю файловую систему;
  • логи с именами хостов, логинами и query-параметрами, доступные любому пользователю сервера.

Порядок разбора: аутентификация, шифрование внешним слоем, утечки DNS и IP, изоляция процесса, список разрешённых клиентов, логирование, чек-лист аудита. Примеры конфигов ориентированы на Dante 1.4.x, 3proxy 0.9.x и shadowsocks-libev 3.3.x; синтаксис своей сборки сверяйте с man-страницей, потому что набор директив у форков отличается. Базовые проверки прокси на подмену и утечки собраны в статье о безопасности прокси-сервера.

Что именно мы защищаем в SOCKS5-прокси

Защищать нужно три вещи: сам порт (кто может подключиться), канал между клиентом и сервером (кто может читать), и данные на сервере (конфиги, пароли, логи). Внутри протокола SOCKS5 нет ни шифрования, ни обязательной проверки подлинности клиента, поэтому все три задачи решаются настройками вокруг него.

Чем SOCKS5 отличается от HTTP-прокси и VPN

SOCKS5 передаёт TCP и UDP как есть и не смотрит внутрь прикладного протокола. HTTP-прокси понимает только HTTP/HTTPS и умеет переписывать заголовки. VPN шифрует весь IP-трафик на сетевом уровне и добавляет маршруты на клиенте. Отсюда практический вывод: SOCKS5 даёт универсальность по приложениям, но не даёт шифрования канала и не скрывает содержимое от оператора сети. Сценарии, где SOCKS5 выигрывает у HTTP-прокси, и где выгоднее второй вариант, разобраны в статье SOCKS5 или HTTP-прокси: чем отличаются и когда выбирать.

Модель угроз: от кого и от чего защищаемся

Ниже список угроз с оценкой реалистичности для типового сервера и мерой, которая их закрывает.

УгрозаНасколько реальнаМера
Автоматическое сканирование порта 1080Постоянно, массовоBind на 127.0.0.1 или firewall с allow-списком
Подбор логина и пароляРеальна при публичном портеДлинный пароль, rate limit, fail2ban
Использование как open relay для спама и скановРеальна при анонимном доступеМетод 0x02 вместо 0x00 плюс allow по IP
DNS-утечкаМассовая, часто незамеченнаяsocks5h, remote DNS, блокировка исходящего 53 на клиенте
Чтение логов проксиРеальна при правах 644Права 640, владелец root:socks, ротация и короткий срок хранения
Пассивное прослушивание каналаРеальна без TLS; между своими ДЦ редкаTLS-туннель или SSH поверх SOCKS5
Целенаправленный MITM с подменой сертификатаРедка, но возможнаПроверка цепочки, checkHost, отказ от самоподписанных сертификатов

Отдельная угроза идёт от клиентской стороны: оператор прокси видит, к каким хостам вы ходите, хотя HTTPS-payload ему недоступен. Если прокси ваш, эта угроза снимается, но остаётся риск компромисса сервера.

Аутентификация в SOCKS5: почему анонимный доступ нужно закрывать первым

В рукопожатии SOCKS5 клиент присылает список поддерживаемых методов, а сервер выбирает один. Метод 0x00 (no authentication) означает вход без проверки. Метод 0x02 (username/password, RFC 1929) включает сверку учётных данных. Метод 0x03 (GSSAPI) применяют в схемах с Kerberos. Для любого прокси, доступного по сети, нужен 0x02, а метод 0x00 лучше убрать из ответа сервера, чтобы он даже не предлагал анонимный вход. Трёхфазное рукопожатие и коды методов зафиксированы в RFC 1928.

Проверить, какие методы сервер предлагает, можно до правок конфига: nmap -p 1080 --script socks-auth-info с внешнего хоста. Строка про отсутствие аутентификации в выводе означает, что прокси открыт.

Dante: обязательная аутентификация и запрет анонимного метода

# /etc/dante/socks.conf
logoutput: syslog
internal: 127.0.0.1 port = 1080
external: eth0
method: username

client pass {
    from: 0.0.0.0/0 to: 0.0.0.0/0
    log: error
}

socks pass {
    from: 0.0.0.0/0 to: 0.0.0.0/0
    command: connect
    protocol: tcp udp
    method: username
    log: error
}

Директива method: username на верхнем уровне и внутри socks pass убирает 0x00 из ответа: клиент, который умеет только анонимный вход, получит отказ. Учётные данные лежат в /etc/dante/socks.passwd в формате логин:пароль; добавьте запись через danted -a или вручную, затем выставьте chmod 600 и владельца сервисного пользователя. Список допустимых методов задаётся директивой socksmethod в порядке предпочтения: если метод не указан в списке, он никогда не будет выбран, а по умолчанию список пуст, что блокирует все socks-запросы. При запуске без включённых методов Dante выдаёт предупреждение no socks authentication methods enabled и блокирует запросы после согласования — синтаксис директив сверяйте с man-страницей danted.conf.

Проверка: запрос с логином и паролем проходит, запрос без них падает с сообщением об отсутствии подходящего метода аутентификации.

3proxy: аутентификация и ограничение методов

# /etc/3proxy/3proxy.cfg
daemon
maxconn 200
nserver 127.0.0.1
nscache 65536
auth strong
users user1:CL:Str0ngPass
allow user1
log /var/log/3proxy/3proxy.log D
rotate 7
socks -p1080 -i127.0.0.1

Директива auth strong задаёт аутентификацию по логину и паролю и отключает анонимные методы. Запись users хранит пароль в открытом виде, поэтому файл конфига закрывают правами 600 и не кладут в git. Строка allow user1 ограничивает доступ одним пользователем, а loopback-адрес в -i не даёт слушать внешний интерфейс. Примеры конфигураций с логином/паролем и с анонимным доступом приведены в документации 3proxy.

ss-server: пароль как обязательный параметр

ss-server -s 127.0.0.1 -p 1080 -k 'Str0ngPass' -m chacha20-ietf-poly1305 -u

Важная деталь: ss-server — серверный демон Shadowsocks-libev, который принимает зашифрованные соединения от клиентских компонентов (ss-local, ss-redir, ss-tunnel), расшифровывает трафик и пересылает его к целевым серверам, а локальный SOCKS5 поднимает клиент ss-local. Пароль здесь не отдельный метод аутентификации, а часть ключа шифрования: без -k сервер не запустится, анонимного режима нет. Клиент с неверным паролем не установит сессию, потому что не сможет расшифровать ответ. Поддерживаются AEAD-шифры, включая chacha20-ietf-poly1305, которые рекомендуются для лучшей безопасности — описание компонента и примеры запуска есть в документации ss-server. Пароль не держите в командной строке юнита, используйте EnvironmentFile с правами 600: значения Environment= видны через systemctl show.

Шифрование трафика: SOCKS5 сам не шифрует, что делать

SOCKS5 передаёт байты без изменений и не знает, что внутри. Если канал проходит через недоверенную сеть (интернет, публичный Wi-Fi, транзит между ДЦ через третью сторону), добавьте внешний слой шифрования. Внутри доверенного периметра, между сервисами одной приватной сети, хватает штатного SOCKS5 с аутентификацией.

TLS-туннель поверх SOCKS5 через stunnel

# /etc/stunnel/stunnel.conf, клиент
[socks5-tls]
client = yes
accept = 127.0.0.1:1081
connect = proxy.example.net:8443
verifyChain = yes
CAfile = /etc/ssl/certs/ca-certificates.crt
checkHost = proxy.example.net
# /etc/stunnel/stunnel.conf, сервер
[socks5-tls]
accept = 8443
connect = 127.0.0.1:1080
cert = /etc/stunnel/fullchain.pem
key = /etc/stunnel/privkey.pem

Клиент поднимает локальный порт 1081 и заворачивает соединение в TLS до сервера, сервер разворачивает его и отдаёт локальному SOCKS5 на 1080. Проверка цепочки: openssl s_client -connect proxy.example.net:8443 -servername proxy.example.net должен показать валидную цепочку и Verify return code: 0. Параметр checkHost защищает от подмены сертификата на другой домен. Самоподписанные сертификаты в продакшене не используйте: клиент не отличит ваш сертификат от поддельного.

SSH-туннель: когда это самый быстрый способ

ssh -D 127.0.0.1:1080 -N -C -o ExitOnForwardFailure=yes user@server

SSH открывает локальный SOCKS5 и сам шифрует весь поток, отдельный демон не нужен. Ограничения: пропускная способность ниже, чем у отдельного сервиса, туннель живёт вместе с SSH-сессией (для стабильности нужен autossh или systemd-юнит), а для множества клиентов схема плохо масштабируется. Проверка: ss -tulpn | grep 1080 показывает локальный адрес, а запрос через --socks5-hostname отдаёт серверный IP. Для постоянного защищённого канала в CI/CD чаще берут WireGuard, разбор подходов есть в материале про обход блокировок и защищённый канал для CI/CD.

Матрица выбора: штатный SOCKS5, TLS, SSH или WireGuard

СценарийРешениеПочему
Прокси и клиент на одном хостеШтатный SOCKS5 на 127.0.0.1 с аутентификациейТрафик не покидает машину, внешний слой не нужен
Сервисы в одной приватной сетиSOCKS5 плюс allow по IPПериметр доверенный, накладные расходы на TLS не оправданы
Канал между ДЦ через третью сторонуSOCKS5 внутри TLS-туннеля (stunnel)Сеть не под вашим контролем, содержимое нужно закрыть
Клиенты из публичного интернетаTLS или SSH поверх SOCKS5, аутентификация, firewallПорт виден сканерам, канал недоверенный
Мобильные клиенты и роумингWireGuardШифрование и роуминг из коробки, потери пакетов не рвут сессию
Разовый доступ на 10 минутSSH-туннель ssh -DНе нужен отдельный сервис и конфиг

Схемы с цепочками прокси, Squid и WireGuard для корпоративного периметра разобраны в статье про обход ограничений в корпоративной сети.

Защита от утечек DNS и IP в SOCKS5

Утечка DNS случается, когда приложение само резолвит имя и отправляет запрос напрямую, минуя прокси. Клиент видит прокси, а DNS-запрос уходит от реального адреса: этого достаточно, чтобы связать пользователя с посещаемым ресурсом.

socks5 vs socks5h: где резолвится имя

curl с ключом --socks5 резолвит имя локально и отправляет на прокси уже готовый IP. Ключ --socks5-hostname (в URL-схеме это socks5h://) передаёт имя на прокси, и резолвинг идёт на сервере. Разница видна на клиенте: запустите tcpdump -i any port 53 -n и повторите оба варианта, в первом случае появятся DNS-пакеты, во втором их не будет. В Firefox нужный параметр называется network.proxy.socks_remote_dns и по умолчанию выключен, в Chrome SOCKS5 резолвит имена на прокси.

Настройка DNS на клиенте и сервере

На сервере поднимите локальный резолвер (dnsmasq или unbound) на 127.0.0.1 и укажите его же в конфиге прокси, как nserver 127.0.0.1 у 3proxy. Для приложений, которые не умеют socks5h, используйте tun2socks или proxychains-ng с включённым proxy_dns:

# /etc/proxychains4.conf
strict_chain
proxy_dns
tcp_read_time_out 15000
tcp_connect_time_out 8000

[ProxyList]
socks5 127.0.0.1 1080

Жёсткий вариант для клиента: запретить исходящий UDP и TCP на 53 наружу в firewall. Тогда приложение физически не сможет резолвить мимо прокси и упадёт с ошибкой вместо тихой утечки.

Проверка утечек: команды и сервисы

Минимальный набор проверок:

  • IP: запрос к сервису, который показывает исходящий адрес, через --socks5-hostname должен вернуть адрес сервера; тот же запрос без прокси возвращает ваш адрес;
  • DNS: tcpdump -i any port 53 -n на клиенте во время работы приложения покажет, уходят ли запросы напрямую;
  • IPv6: запрос с флагом -6 проверяет отдельный стек, утечка по IPv6 часто остаётся незамеченной, если прокси слушает только IPv4;
  • браузер: публичный тест на DNS- и WebRTC-утечки, плюс проверка media.peerconnection.enabled в about:config, потому что WebRTC использует UDP и может пойти мимо прокси.

Ограничение по IPv6 закрывают либо полным отключением стека на клиенте, либо настройкой прокси на AF_INET и AF_INET6 одновременно.

Изоляция процесса и минимизация прав

Компромисс прокси не должен превращаться в компромисс сервера. Демон, запущенный от root с полным набором capabilities, при удачной атаке читает ключи SSH, конфиги баз данных и переменные окружения соседних сервисов.

Готовый systemd-юнит с ограничениями

[Unit]
Description=Dante SOCKS5 proxy
After=network-online.target
Wants=network-online.target

[Service]
Type=forking
User=socks
Group=socks
ExecStart=/usr/sbin/danted -f /etc/dante/socks.conf
NoNewPrivileges=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectSystem=strict
ProtectHome=yes
ProtectKernelTunables=yes
ProtectControlGroups=yes
RestrictAddressFamilies=AF_INET AF_INET6
CapabilityBoundingSet=
AmbientCapabilities=
MemoryDenyWriteExecute=yes
RestrictNamespaces=yes
LockPersonality=yes
ReadWritePaths=/var/log/dante

[Install]
WantedBy=multi-user.target

Что закрывает каждый параметр: User и Group лишают процесс root-прав; NoNewPrivileges запрещает повышать привилегии через setuid-бинарники; PrivateTmp выделяет изолированный /tmp; ProtectSystem=strict и ProtectHome монтируют /usr, /boot и домашние каталоги только для чтения; RestrictAddressFamilies оставляет только IPv4 и IPv6, отсекая unix-сокеты и netlink; MemoryDenyWriteExecute мешает выполнять код из записываемой памяти. ReadWritePaths нужен, чтобы демон мог писать лог. CapabilityBoundingSet пустой, потому что порт 1080 выше 1024 и CAP_NET_BIND_SERVICE не требуется; для портов ниже 1024 оставьте только эту capability.

Проверка изоляции: systemd-analyze security

Объективную оценку даёт команда systemd-analyze security danted.service: она вычисляет общий уровень экспозиции (exposure level) в диапазоне от 0.0 до 10.0, показывающий, насколько сервис незащищён, и печатает список незакрытых пунктов. Ориентир для продакшена: значение ниже 3.0. Чаще всего оценку портят PrivateTmp=no, отсутствие ProtectSystem, пустые RestrictAddressFamilies и открытые capability. Ограничения включаются добавлением специальных опций в unit-файл, среди них PrivateNetwork=, User=/DynamicUser=, DeviceAllow= и IPAddressDeny= — описание подхода есть в руководстве по усилению systemd-сервисов. Дополнительный слой дают AppArmor или seccomp-профиль: они ограничивают системные вызовы и доступ к файлам даже при ошибке в конфиге юнита.

Ограничение списка клиентов и защита от сканирования

Три уровня защиты дают предсказуемый результат: привязка к интерфейсу, allow/deny в конфиге прокси и пакетный фильтр.

Bind на 127.0.0.1 и allow/deny в конфиге

Если прокси нужен только локальным процессам, слушайте loopback: internal: 127.0.0.1 port = 1080 у Dante, socks -p1080 -i127.0.0.1 у 3proxy, -s 127.0.0.1 у ss-server. Это самый надёжный способ, потому что порт физически недоступен из сети. Для доступа извне добавьте allow-список доверенных подсетей в конфиге и оставьте deny по умолчанию.

Firewall и fail2ban против брутфорса

table inet filter {
  chain input {
    type filter hook input priority filter; policy drop;
    ct state established,related accept
    iif "lo" accept
    ip saddr { 10.0.0.0/8, 192.168.0.0/16 } tcp dport 1080 accept
    tcp dport 1080 counter drop
  }
}

Правило оставляет порт 1080 открытым только для двух приватных диапазонов, остальное отбрасывается. Проверка с внешнего хоста: nmap -p 1080 даёт filtered или closed, а не open. Для защиты от подбора паролей добавьте jail, который читает лог прокси и банит адрес после трёх неудач:

[danted]
enabled = true
port = 1080
filter = danted
logpath = /var/log/dante/socks.log
maxretry = 3
findtime = 600
bantime = 3600
action = nftables-multiport

Статус банов смотрят через fail2ban-client status danted. Если демон пишет в syslog, а не в отдельный файл, укажите в logpath journalmatch или системный путь. Port knocking скрывает порт от сканеров, но добавляет зависимость от клиентского скрипта и ломает автоматизацию, поэтому в CI/CD он редко уместен.

Логирование без утечки чувствительных данных

Access log прокси содержит имена хостов, порты, время и логин. Если по той же цепочке идёт HTTP-трафик или включён подробный режим, в лог попадают URL с токенами и query-параметры. Такой файл с правами 644 читает любой пользователь сервера.

Настройки log-level для Dante, 3proxy и ss-server

Держите минимальный уровень: у Dante log: error в блоках client pass и socks pass вместо info или connect, у 3proxy формат с датой без лишних полей, у ss-server не включайте -v в продакшене. Подробное логирование поднимайте только на время отладки и отключайте сразу после: в debug-режиме в лог уходят детали соединений, которых там быть не должно.

Ротация и права на логи

/var/log/dante/*.log {
    daily
    rotate 7
    compress
    missingok
    notifempty
    create 640 root socks
}

Права 640 и владелец root:socks не дают читать лог посторонним. Храните логи ограниченное время: семь дней покрывают разбор инцидента и не превращают сервер в архив истории обращений. Перед отправкой во внешний SIEM прогоняйте записи через фильтр rsyslog или journald с маскированием полей, иначе токены из query-строк уедут за пределы вашего периметра.

Чек-лист аудита работающего SOCKS5-прокси

Проверки ниже занимают 10-15 минут на одном хосте.

Команды проверки: ss, nmap, curl, tcpdump

  1. Адрес прослушивания. ss -tulpn | grep 1080. Для локального прокси ожидается 127.0.0.1:1080; адрес 0.0.0.0:1080 или [::]:1080 означает доступ из сети.
  2. Видимость порта снаружи. nmap -p 1080 с внешнего хоста. Ожидается filtered или closed. Open означает, что сканеры до порта доходят.
  3. Анонимный доступ. запрос через прокси без логина и пароля должен упасть с сообщением об отсутствии подходящего метода аутентификации. Если запрос проходит, метод 0x00 всё ещё активен.
  4. Доступ с паролем. curl --socks5-hostname 127.0.0.1:1080 https://<адрес-проверки> возвращает страницу, а запрос к сервису проверки IP отдаёт адрес сервера, а не ваш.
  5. DNS-утечки. tcpdump -i any port 53 -n на клиенте во время работы приложения. Пакетов быть не должно: имена резолвит прокси.
  6. IPv6. тот же запрос с флагом -6 проверяет второй стек отдельно. Утечка по IPv6 закрывается отключением стека или настройкой прокси на оба семейства.
  7. Изоляция процесса. systemd-analyze security danted.service, ориентир ниже 3.0.
  8. Права на файлы. stat -c '%a %U:%G %n' /etc/dante/socks.passwd /var/log/dante/*.log. Ожидается 600 для файла паролей и 640 root:socks для логов.
  9. Шифрование канала. если трафик идёт через недоверенную сеть, openssl s_client -connect <хост>:<порт> -servername <хост> должен показать Verify return code: 0 либо подключение идёт через SSH или WireGuard.

Что делать, если проверка не прошла

СимптомПричинаИсправление
nmap показывает openДемон слушает 0.0.0.0Привязать к 127.0.0.1 или добавить allow-правило в nftables
Запрос без пароля проходитОстался метод 0x00auth strong у 3proxy, method: username у Dante
tcpdump показывает DNS-пакетыПриложение резолвит локальноПерейти на socks5h, включить proxy_dns в proxychains или заблокировать 53 наружу
Запрос через прокси отдаёт ваш IPПрокси не используется или IPv6 идёт мимоПроверить -x/--socks5-hostname и отключить IPv6 на клиенте
systemd-analyze security показывает 6 и вышеЮнит без ProtectSystem и RestrictAddressFamiliesДобавить директивы из примера выше
В логе видны URL с токенамиПодробный уровень логированияВернуть log: error, урезать формат, ротация с правами 640

Итог: минимальный безопасный SOCKS5 за 5 шагов

  1. Привяжите прокси к 127.0.0.1, а если нужен внешний доступ, ограничьте порт nftables-правилом с allow-списком подсетей.
  2. Включите обязательную аутентификацию и уберите метод 0x00: method: username у Dante, auth strong у 3proxy, обязательный -k у ss-server.
  3. Добавьте TLS-туннель или SSH, если трафик идёт через недоверенную сеть; внутри приватного периметра штатного SOCKS5 достаточно.
  4. Переведите приложения на socks5h и проверьте утечки командой tcpdump -i any port 53 на клиенте, отдельно проверьте IPv6 и WebRTC в браузере.
  5. Изолируйте процесс systemd-юнитом с User, ProtectSystem=strict, RestrictAddressFamilies и ограничьте логирование уровнем error с правами 640.

Пройдите чек-лист из девяти пунктов на каждом узле: он ловит и открытый порт, и включённый анонимный метод, и тихую DNS-утечку. Дополнительные схемы с прокси-цепочками и WireGuard для корпоративного периметра разобраны в смежных материалах базы знаний.

Поделиться:
Сохранить гайд? В закладки браузера