«Прозорий» Squid з фільтрацією HTTPS ресурсів без підміни сертифікатів

Не секрет, що у великих конторах тема фільтрації Інтернету досить актуальна. З цим завданням справляється чимало програмних і апаратних рішень. Але в даний час всі ті сайти, які ми різали раніше, працюють по протоколу HTTPS, тобто порт 443. Як відомо, даний протокол простежити, прослухати і т. п., неможливо. А будь кеширующий фільтруючий проксі-сервер, редиректор і т. п. фільтрує HTTP, тобто порт 80. Як же різати Вконтакте, Однокласники, iphide.info і багато інші подібні сайти? Як блокувати доступ до особистої пошти в організації, якщо використання оной заборонено порядками в організації? Так, можна фільтрувати по IP адресам, але вони частенько змінюються, так і на багатьох ресурсах кілька IP адрес. Блокувати їх на рівні файрвола як-то зовсім не православне рішення, і не зовсім зручне.

І ось, зовсім недавно, мені один товариш розповів, що він піднімає у себе в конторі кеширующий проксі з фільтрацією HTTPS, мене це зацікавило. А він піднімав Squid 3.5.8. Як з'ясувалося, в ньому перероблена організація перехоплення шифрованих HTTPS-сеансів (ssl_bump), замість режимів перехоплення («modes») введено в ужиток дії («actions»), які в тому числі можна використовувати в ACL. Режим «server-first, при якому спочатку здійснюється з'єднання з цільовим сервером, а потім створюється захищене з'єднання між клієнтом і проксі, тепер доступний як дія «bump». Режим «none», при якому створюється TCP-тунель без дешифрування трафіку, тепер доступний як дія «splice».

Для забезпечення зворотної сумісності додано дія «peek-and-splice», при якому рішення про тип створюваного спочатку з'єднання (клієнт-проксі або проксі-сервер) приймається на основі SSL hello-повідомлень. Додано дії «peek» і «stare» для отримання клієнтського або серверного сертифіката із збереженням можливості подальшого застосування режимів «splice» і «bump» для сполук. Додано дія «terminate» для закриття з'єднань до клієнта або сервера. От як раз SSL BUMP, PEEK-and-SPLICE і Terminate нам і потрібні. Взагалі, схема роботи насправді досить проста. Squid підключається до HTTPS ресурсу, отримує його сертифікат, і може «подивитися» деякі дані про ресурс, зокрема ім'я сервера, яке нам якраз і потрібно для блокування! Всі мануали, які є в Інтернеті, то і справа описують Man in the middle (MITM) атаку з підміною сертифікатів, при якій в принципі не працюють деякі сайти і банк-клієнти, так і юзери явно бачать, що за ними стежать. Ми ж з товаришем спільними зусиллями домоглися сбособа фільтрації і відстеження HTTPS без підміни сертифікатів, без MITM і іншого, і все це в прозорому режимі без налаштування браузерів!

Згодом я зіткнувся з деякими труднощами, зокрема Squid починав сегфолтиться на великому навантаженні. Але проблема була вирішена. Справа в тому, що у Openssl є деякі помилки, які виправлені в бібліотеці Libressl. Тому спочатку необхідно інтегрувати в систему Libressl, потім вже після внесення патча в файл bio.cc в исходниках Squid приступати до компіляції останнього. Поїхали! Обмовлюся, що в мене використовується дистрибутив Debian Jessie x86, і Squid я в підсумку зібрав версії 3.5.9 (остання на даний момент версія), і стаття розрахована на більш-менш досвідченого користувача Linux, так як деякі моменти опускаються, а йдеться лише найголовніше, так як мені лінь все розжовувати. Отже, якщо вам цікаво, йдемо під кат.

Для початку, підготуємося до складання пакетів:

apt-get install git fakeroot build-essential devscripts
apt-cache policy squid3
apt-get build-dep squid3
apt-get build-dep libecap2
apt-get install libssl-dev libgnutls28-dev

Не забудьте перейти у папку, де ви будете збирати исходники, щоб не засрати собі Хоум. Далі скачати, скомпилируем і встановимо Libressl:

wget http://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.1.6.tar.gz
tar -xzvf libressl-2.1.6.tar.gz
cd libressl-2.1.6

Збираємо та встановлюємо, після чого перечитаємо хеші бібліотек:

./configure
make
make install
ldconfig

Ну і треба налаштувати використання LibreSSL за замовчуванням:

mv /usr/bin/openssl /usr/bin/openssl-1
update-alternatives --install /usr/bin/openssl openssl /usr/bin/openssl-1 10
update-alternatives --install /usr/bin/openssl openssl /usr/local/bin/openssl 50
update-alternatives --config openssl

Перевіримо, чи вийшло поставити Libressl:

openssl version
LibreSSL 2.1.6

Вийшло!

Після виконання цих дій, необхідно відредагувати sources.list, включивши туди исходники з гілки testing (це необхідно, так як нам потрібно компілювати новий libecap, який у свою чергу необхідний для складання Squid):

deb-src http://ftp.de.debian.org/debian/ testing main contrib non-free

Оновимо кеш пакунків:

apt-get update

А тепер скачаємо з Testing потрібні джерело:


apt-get source squid3/testing
apt-get source libecap3/testing

Далі зберемо libecap:

cd libecap-1.0.1/
dpkg-buildpackage -us -uc -nc -d

Видалимо мотлох, і встановимо новье:

apt-get purge libecap2
dpkg -i libecap3_1.0.1-2_i386.deb
dpkg -i libecap3-dev_1.0.1-2_i386.deb

Качаємо останній снепшот Squid'a:

wget http://www.squid-cache.org/Versions/v3/3.5/squid-3.5.9-20150922-r13918.tar.gz

Оновимо отримані раніше исходники Squid'a до нових, і далі будемо працювати вже в директорії з новоспеченими джерела:

cd squid3-3.5.7/
uupdate -v 3.5.9 ../squid-3.5.9-20150922-r13918.tar.gz
cd ../squid3-3.5.9/

Щоб всі потрібні нам плюшки заробили, треба компілювати Squid з потрібними опціями, тому внесемо в debian/rules наступні опції компіляції:

--enable-ssl
--enable-ssl-crtd
--with-openssl

Завантажити патч для bio.cc, який потрібен для коректної роботи з Libressl, звідси bugs.squid-cache.org/attachment.cgi?id=3216 і застосуємо його

patch -p0 -i bug-4330-put_cipher_by_char-t1.patch

Тепер можна приступати до компіляції і збірки Squid'а. Але не так швидко! Все відбудеться створення без проблем, принаймні на х86 архітектури, але в самому кінці, на етапі складання пакетів deb, вам люб'язно скажуть в консолі: «ай ай ай, не можу зрозуміти, які залежно потрібні для libssl.so.32» (це версія бібліотеки з Libressl). Воно і зрозуміло, звідки Debian у знати про неї. Ми обдуримо систему, вказавши опцію «не перевіряти залежності», ось так:

export DEB_DH_SHLIBDEPS_ARGS_ALL=--dpkg-shlibdeps-params=--ignore-missing-info
/source>
А ось тепер приступимо до компіляції і збірки:

<source lang="bash">dpkg-buildpackage -us -uc -nc

Після складання встановимо пакет з мовами для Squid'a:

apt-get install squid-langpack

Далі встановимо новоспечені пакети:

dpkg -i squid-common_3.5.9-1_all.deb
dpkg -i squid_3.5.9-1_i386.deb
dpkg -i squid3_3.5.9-1_all.deb
dpkg -i squidclient_3.5.9-1_i386.deb

Якщо система заматюкалася па на незадоволені залежності, зробимо:

apt-get -f install

Майже готово! Перейдемо в каталог /etc/squid, дещо там змінимо. Створимо pem файлик, необхідний для SSL-Bump'інга:

openssl req -new -newkey rsa:1024 -days 365 -nodes -x509 -keyout squidCA.pem -out squidCA.pem

І наведемо squid.conf до наступного вигляду:

acl localnet src 192.168.1.0/24 # RFC1918 possible internal network

acl SSL_ports port 443
acl Safe_ports port 80 # http
acl Safe_ports port 21 # ftp
acl Safe_ports port 443 # https
acl Safe_ports port 70 # gopher
acl Safe_ports port 210 # wais
acl Safe_ports port 1025-65535 # unregistered ports
acl Safe_ports port 280 # http-mgmt
acl Safe_ports port 488 # gss-http
acl Safe_ports port 591 # filemaker
acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT

dns_nameservers 8.8.8.8
http_access deny !Safe_ports

http_access deny CONNECT !SSL_ports

http_access allow localhost manager
http_access deny manager

#вкажемо шлях до файлу з білим списком https ресурсів, які взагалі не будемо чіпати
acl whitehttps ssl::server_name "./etc/squid/white_https.txt"

http_access allow localnet
http_access allow localhost
http_access deny all

#прозорий порт вказується опцією intercept
http_port 192.168.1.254:3128 intercept options=NO_SSLv3:NO_SSLv2

#також потрібно вказати непрозорий порт, бо якщо захочете вручну вказати адресу
#проксі в браузері, вказавши прозорий порт, ви отримаєте помилку доступу, тому потрібно
#вказувати непрозорий порт в браузері, якщо, звичайно, таке бажання буде, до того ж в логах #сипляться помилки про те, що непрохрачный порт не вказано=) 
http_port 192.168.1.254:3130 options=NO_SSLv3:NO_SSLv2 

#і нарешті, вказуємо HTTPS порт з потрібними опціями
https_port 192.168.1.254:3129 intercept ssl-bump options=ALL:NO_SSLv3:NO_SSLv2 connection-auth=off cert=/etc/squid/squidCA.pem

always_direct allow all
sslproxy_cert_error allow all
sslproxy_flags DONT_VERIFY_PEER

#вкажемо правило зі списком заблокованих ресурсів (у файлі домени виду .domain.com)
acl blocked ssl::server_name "./etc/squid/blocked_https.txt"
acl step1 at_step SslBump1
ssl_bump peek step1 !whitehttps

#терминируем з'єднання, якщо клієнт заходить на заборонений ресурс
ssl_bump terminate blocked 
ssl_bump splice all !whitehttps

sslcrtd_program /usr/lib/squid/ssl_crtd -s /var/lib/ssl_db -M 4MB

coredump_dir /var/spool/squid
refresh_pattern ^ftp: 1440 20% 10080
refresh_pattern ^gopher: 1440 0% 1440
refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
refresh_pattern . 0 20% 4320
cache_dir aufs /var/spool/squid 20000 49 256
maximum_object_size 61440 KB
minimum_object_size 3 KB

cache_swap_low 90
cache_swap_high 95
maximum_object_size_in_memory 512 KB
memory_replacement_policy lru
logfile_rotate 4

#у версії 3.5.9 чомусь в логах cache.log іноді сипляться повідомлення виду 
#«Sequrity Alert <тудым-сюдым>», у версії 3.5.8 їх немає, мене це дістало, просто 
#вимкнув цей лог
cache_log /dev/null

Далі загорнемо файрволом потрібні порти на Squid:

iptables -t nat -A PREROUTING -p tcp -m tcp -s 192.168.1.0/24 --dport 443 -j REDIRECT --to-ports 3129
iptables -t nat -A PREROUTING -p tcp -m tcp -s 192.168.1.0/24 --dport 80 -j REDIRECT --to-ports 3128

Все готово! Можна урочисто запускати Squid:

systemctl start squid

Подивимося, чи все зі Squid'ом нормально:

systemctl status squid
● squid.service - LSB: Squid HTTP Proxy version 3.x
Loaded: loaded (/etc/init.d/squid)
Active: active (running) since Сб 2015-09-26 21:09:44 YEKT; 2h 6min ago
Process: 1798 ExecStop=/etc/init.d/squid stop (code=exited, status=0/SUCCESS)
Process: 1818 ExecStart=/etc/init.d/squid start (code=exited, status=0/SUCCESS)
CGroup: /system.slice/squid.service
├─1850 /usr/sbin/squid -YC -f /etc/squid/squid.conf
├─1852 (squid-1) -YC -f /etc/squid/squid.conf
├─1853 (logfile-daemon) /var/log/squid/access.log
└─1854 (pinger)

сен 26 21:09:44 squid squid[1850]: Squid Parent: will start 1 kids
сен 26 21:09:44 squid squid[1850]: Squid Parent: (squid-1) process 1852 started
сен 26 21:09:44 squid squid[1818]: Starting Squid HTTP Proxy: squid.

Якщо помилок немає, можна працювати! На жаль, при блокуванні HTTPS ресурсів, не з'являється повідомлення Squid'a «Доступ заборонений», а замість цього, браузер видає помилку про неможливість створення з'єднання. Якщо хтось підкаже, як це зробити, буду дуже радий.

UPD: у версії Кальмара, яку компилировал я, знайдений прикрий баг (або фіча), з-за якого через деякий час перестають відкриватися деякі HTTPS сайтів. Рішення: компілювати версію 3.5.8 !

UPD2: створив черговий багрепорт з проблеми 3.5.9, тему буду оновлювати, якщо щось проясниться

Хочу сказати спасибі товаришу Дмитру Рахматулліну, без нього б не вийшло зробити те, що написано вище. Також, окреме спасибі розробникам Squid'а, які оперативно відповіли на мій баг-репорт про помилку libssl. І спасибі хлопцям Nadz Goldman і gmax007 з Тостера, які направили в потрібне русло мої ідеї щодо перенесення Squid'а на фізично окремий від основного шлюзу сервер!

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.