Это старая версия документа.


Stunnel это программная обертка, позволяющая спрятать в шифрованный ssl-туннель произвольный трафик.

Собственно этой технологией вы пользуетесь каждый раз, когда заходите на сервера в Интрнет, с которыми устанавливается соединение по протоколу HTTPS (в строке адреса вы видите: https:\\…..). Фактически web-сервер и клиентский браузер работают с HTTP запросами и ответами (не шифрованный трафик), однако в случае с HTTPS весь этот трафик передается внутри ssl-туннеля установленного между клиентом и сервером. Особенность такого туннеля в том весь трафик передается шифрованным сессионными ключами, которые формируют в процессе обмена клиент и сервер по сертификату доступному на сервере. Таким образом - любой клиент может установить защищенное соединение с сервером, однако прочитать информацию передаваемую в канале может только тот клиент который устанавливал соединение и сервер, и никто другой (теоретически1)) эту информацию в процессе передачи прочитать не может.

HTTPS протокол имеет встроенный механизм ssl-туннелирования.

Важно! stunnel создает и поддерживает туннель как TCP соединение и передавать может только tcp-трафик

Особенность stunnel в том, что позволяет обернуть в ssl-туннель трафик совершенно любого сервиса, который не имеет встроенных средств шифрования (однако и шифрованный трафик тоже можно передать через stunnel для того, что бы замаскировать его, допустим, под обмен по https протоколу). За счет чего же достигается возможность туннелировать сетевой трафик изначально не предполагавший ни шифрования ни туннелирования? А дело в том, что на любом компьютере, где реализован TCP/IP стек протоколов, есть такая (часто неприметная и порой забываемая вовсе) вещь как localhost. Механизм туннелирования заключается в том что stunnel:

  • на клиенте: слушает порт на локальном хосте клиента и передает информацию (шифруя) на определенный порт удаленного сервера,
  • на сервере: слушает порт на внешнем адресе и передает информацию (расшифровывая) на определенный порт локального хоста сервера.

При этом клиент свой запрос отправляет не на удаленный сервер, а на тот самый порт localhost, на котором слушает stunnel. Сервер же слушает (ждет запроса клиента) не на внешнем порту, а на локальном порту на который транслирует передачу stunnel. Посмотрите на схему (что бы было понятнее):

Вариант без stunnel (прямое соединение без шифрования)
+----------------------+                                                                                                         +----------------------+
| Клиентский компьютth |                                                                                                         | Сервер               |
|                      |(запрос к ex.t.ser.ver:service_port)                (слушает service_port на внешнем адресе ex.t.ser.ver)|                      |
| приложение клиент >--+-->----->------------------------------------------------------------------------------------------------+--> приложение сервер |
+----------------------+                                                                                                         +----------------------+
Вариант c stunnel (c шифрованием)
+----------------------+                                                                                                         +----------------------+
| Клиентский компьютер |                                                                                                         | Сервер               |
|                      |(запрос к localhost:s1_port)                                  (слушает service_port на localhost сервера)|                      |
| приложение клиент >--+-->-+                                                                                           +--->----+--> приложение сервер |
|                      |    |                                                                                           |        |                      |
| stunnel <------------+----+ (слушает s1_port на localhost)                                                            +---<----+--< stunnel           |
|    | < шифрование    | (отправляет на s2_port ex.t.ser.ver)                                   (слушает s2_port на ex.t.ser.ver)|       | < расшифровка|
|    +----->-----------+-->----->------------------------------------------------------------------------------------------------+--->---+              |
+----------------------+                                                                                                         +----------------------+

Порты s1_port и s2_port - служебные порты stunnel и могут быть выбраны произвольно (как правило s2_port выбирается таким, что бы соединение на него не блокировалось файерволами). С s1_port - никаких ограничений нет т.к. трафик фактически и не покидает клиентского компьютера (передача идет внутри стека TCP/IP протокола). Точно так же и service_port (приложения сервера) на сервере можно изменить со стандартного на произвольный (если нужно).

Если возникает вопрос «как же осуществляется обратный трафик?» то нужно понимать, что каждое клиентское приложение в каждом подключении открывает для передачи произвольный порт (из тех что имеют большие номера, например 50000+) и именно на этот порт stunnel возвращает расшифрованные данные клиента. На клиенте stunnel открывает для передачи на удаленный сервер еще один порт и между ним и портом s2_port собственно и устанавливается шифрованный канал. На сервере же, stunnel выступает в роли клиента и сам открывает произвольный порт (из старших номеров) для получения обратного трафика от приложения-сервера (который он шифрует перед отправкой на клиентский компьютер).
Все эти обратные порты открываются только для связи с другим портом (netstat такие порты отмечает статусом ESTABLISHED) и они не являются слушающими (LISTEN статус в выводе netstat)

И так, с механизмом встраивания stunnel в работу клиент-серверного приложения мы разобрались (возможно даже излишне глубоко копали, «от печки»). Посмотрим теперь как он устанавливается и настраивается.

Установка Stunnel

Несмотря на то что настройки stunnel для сервера и клиента различаются, но устанавливается он и на сервер и на клиент одинаково:

apt-get install stunnel4

Настройка Stunnel

Настройка Stunnel на сервере

stunel использует все файлы с расширением .conf, которые находит в каталоге /etc/stunnel как конфигурационные. В каждом файле могут быть описаны как и общие параметры настройки так и настройки для отдельных сервисов, причем в одном файле можно описать несколько сервисов.

Создадим новый конфигурационный файл:

sudo nano /etc/stunnel/stunnel.conf

В нем нам нужно указать настройки самого stunell:

# Укажем файл сертификата который будет использоваться для шифрования (его мы создадим чуть позже)
cert = /etc/stunnel/stunnel.pem 
# Дадим директиву не использовать скомпрометированный протокол openSSL V2
options = NO_SSLv2

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

compression = zlib

Можно еще указать путь куда будут записываться логи сервиса stunnel

output = /var/log/stunnel.log

Теперь опишем наш сервис по следующему:

[<service1>]
# Укажем, что это конфигурация серверной стороны (в принципе это не обязательно - stunel по умолчанию считает, что она работает как сервер)
client = no
accept = <ex.t.ser.ver>:<s2_port>
connect = localhost:<service_port>

В этом шаблоне нужно будет указать реальные порты приложения сервера (<service_port>) и порт на котором будет принимать соединения stunel для этого сервиса (<s2_port>). Имя хоста или внешний IP адрес сервера (<ex.t.ser.ver>) можно и не указывать (пропустить), тогда stunnel будет слушать этот порт на всех адресах сервера. Пример для сервиса telnet будет выглядеть примерно так (stunnel будет ждать установки соединения с клиентской стороны на порту 8023)

[telnet]
accept = 8023
connect = localhost:23

stunnel имеет достаточно большое количество настроек - все их мы не будем перечислять. О них можно узнать из манула на stunnel

man stunnel

Созданный файл конфигурации закрываем и сохраняем.
Кроме конфигурации stunnel нужно разрешить. Для этого в файле /etc/default/stunnel нужно заменить

ENABLED=0

на

ENABLED=1

Теперь создадим сертификат:

cd /etc/stunnel/
sudo -s
openssl genrsa -out key.pem 2048
openssl req -new -x509 -key key.pem -out cert.pem 
cat key.pem cert.pem >> stunnel.pem
rm key.pem cert.pem
exit

Созданный сертификат нужно также передать (по защищенным каналам) на клиентскую машину.

Настроенный stunnel запускаем:

service stunnel start

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

Настройка на клиентской машине отличается от серверной минимально.
Общие настройки (минимальный вариант):

# Укажем файл сертификата который будет использоваться для шифрования (не забудьте его перенести с сервера на клиента)
cert = /etc/stunnel/stunnel.pem 
# Дадим директиву не использовать скомпрометированный протокол openSSL V2
options = NO_SSLv2

И настройки сервиса по шаблону:

[<service1>]
# Укажем, что это конфигурация клиентской стороны
client = yes
accept = localhost:<s1_port> 
connect = <ex.t.ser.ver>:<s2_port>

Для telnet такая конфигурация будет выглядеть так:

[<service1>]
client = yes
accept = localhost:23
connect = aa.bb.cc.dd:8023

где aa.bb.cc.dd - IP адрес или DNS-имя внешнего сервера.

Настроенный stunnel запускаем:

service stunnel start

Команда telnet соединения с внешним сервером по ssl-туннелированному протоколу будет выглядеть так:

telnet localhost

Соединиться по нешифрованному каналу с telnet сервером можно было бы командой

telnet aa.bb.cc.dd

Но этого делать не стоит, и особенно не стоит telnet сервис выставлять в интернет (крайне вероятно что ваш сервер очень скоро взломают хакеры).

На самом деле, пример с telnet - исключительно умозрительный и надуманный (хотя и может применяться для отладки, но с соблюдением мер предосторожности), для удаленного логина в консоль сервера гораздо проще использовать ssh (там уже есть встроенное шифрование).

Особенности настроек приложений при работе через stunnel

Нужно понимать, что указание в строке подключения клиента localhost вместо IP адреса или имени сервера может оказать влияние на работу сервиса.
К примеру, если вы решили обернуть трафик OpenVPN в stunnel (довольно популярное решение при маскировке openVPN соединения под https трафик, для обмана умных файерволов), то в маршрутизацию клиента (route) при установленном соединении с OpnVPN сервером будет записан маршрут не на внешний сервер, а на localhost (ведь соединение было с localhost а не с удаленным сервером), что приведет к практически полной неработоспособности сети на клиенте. Что бы исправить эту ситуацию, правильный маршрут нужно прописать в конфигурационный файл OpenVPN:

route аа.bb.cc.dd 255.255.255.255 net_gateway

здесь аа.bb.cc.dd - IP адрес внешнего сервера. При этом строка соединения

remote аа.bb.cc.dd 1194 

заменяется на соединение с localhost:

remote localhost <s1_port>

Ссылки

1)
На практике крипто-стойкость канала целиком и полностью зависит от алгоритмов шифрования, которые используются (и к примеру протокол OpenSSL v.2 уже объявлен не безопасным т.к. в нем были выявлены серьезные уязвимости).