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
- Адрес прослушивания. ss -tulpn | grep 1080. Для локального прокси ожидается 127.0.0.1:1080; адрес 0.0.0.0:1080 или [::]:1080 означает доступ из сети.
- Видимость порта снаружи. nmap -p 1080 с внешнего хоста. Ожидается filtered или closed. Open означает, что сканеры до порта доходят.
- Анонимный доступ. запрос через прокси без логина и пароля должен упасть с сообщением об отсутствии подходящего метода аутентификации. Если запрос проходит, метод 0x00 всё ещё активен.
- Доступ с паролем. curl --socks5-hostname 127.0.0.1:1080 https://<адрес-проверки> возвращает страницу, а запрос к сервису проверки IP отдаёт адрес сервера, а не ваш.
- DNS-утечки. tcpdump -i any port 53 -n на клиенте во время работы приложения. Пакетов быть не должно: имена резолвит прокси.
- IPv6. тот же запрос с флагом -6 проверяет второй стек отдельно. Утечка по IPv6 закрывается отключением стека или настройкой прокси на оба семейства.
- Изоляция процесса. systemd-analyze security danted.service, ориентир ниже 3.0.
- Права на файлы. stat -c '%a %U:%G %n' /etc/dante/socks.passwd /var/log/dante/*.log. Ожидается 600 для файла паролей и 640 root:socks для логов.
- Шифрование канала. если трафик идёт через недоверенную сеть, openssl s_client -connect <хост>:<порт> -servername <хост> должен показать Verify return code: 0 либо подключение идёт через SSH или WireGuard.
Что делать, если проверка не прошла
| Симптом | Причина | Исправление |
|---|---|---|
| nmap показывает open | Демон слушает 0.0.0.0 | Привязать к 127.0.0.1 или добавить allow-правило в nftables |
| Запрос без пароля проходит | Остался метод 0x00 | auth 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 шагов
- Привяжите прокси к 127.0.0.1, а если нужен внешний доступ, ограничьте порт nftables-правилом с allow-списком подсетей.
- Включите обязательную аутентификацию и уберите метод 0x00: method: username у Dante, auth strong у 3proxy, обязательный -k у ss-server.
- Добавьте TLS-туннель или SSH, если трафик идёт через недоверенную сеть; внутри приватного периметра штатного SOCKS5 достаточно.
- Переведите приложения на socks5h и проверьте утечки командой tcpdump -i any port 53 на клиенте, отдельно проверьте IPv6 и WebRTC в браузере.
- Изолируйте процесс systemd-юнитом с User, ProtectSystem=strict, RestrictAddressFamilies и ограничьте логирование уровнем error с правами 640.
Пройдите чек-лист из девяти пунктов на каждом узле: он ловит и открытый порт, и включённый анонимный метод, и тихую DNS-утечку. Дополнительные схемы с прокси-цепочками и WireGuard для корпоративного периметра разобраны в смежных материалах базы знаний.