Хочу поделиться информацией по поднятию прозрачного HTTP и HTTPS прокси сервера Squid с фильтрацией сайтов и без подмены сертификатов на FreeBSD 13.0 RELEASE. На Хабре уже есть похожая статья по настройке прозрачного прокси сервера Squid с фильтрацией ресурсов и без подмены сертификатов на Linux. Решил актуализировать информацию на свежо установленной ОС FreeBSD 13.0 и поделиться с вами.

При использовании действий «peek-and-splice», сквид выдергивает имя ресурса с помощью SNI и клиент дальше работает с ресурсом. Т.е. не происходит подмена сертификата. Этот режим подходит для нашего прозрачного прокси.

Ставить Squid мы будем из портов, так как необходимо включить некоторые параметры в сборку, также для заворачивания трафика на порт прокси мы будем использовать пакетный фильтр PF.

Для начала скачиваем порты:

portsnap fetch extract

Если порты уже установлены в системе (/usr/ports), то выполняем обновление:

portsnap fetch update

Ставим пакет libressl — форк openssl:

pkg install -y libressl
rehash

После установки выполняем подмену OpenSSL на LibreSSL:

mv /usr/bin/openssl /usr/bin/openssl.old
ln -s /usr/local/bin/openssl /usr/bin/openssl
openssl version

В файле /etc/make.conf определим параметры для сборки нашего сквида:

DEFAULT_VERSIONS+=ssl=libressl
OPTIONS_FILE_SET+=ECAP
OPTIONS_FILE_SET+=GSSAPI_NONE
OPTIONS_FILE_UNSET+=GSSAPI_BASE
OPTIONS_FILE_UNSET+=TP_IPFW
OPTIONS_FILE_SET+=TP_PF

Переходим в директорию порта:

cd /usr/ports/www/squid

Выполняем установку порта:

make install clean BATCH=yes

Создадим сертификат для SSL-bump'инга:

cd /usr/local/etc/squid
/usr/local/bin/openssl req -new -newkey rsa:1024 -days 365 -nodes -x509 -keyout squidCA.pem -out squidCA.pem

Инициализируем файл базы SSL:

/usr/local/libexec/squid/security_file_certgen -c -s /var/log/squid/ssl_db -M 4MB

Приводим squid.conf к следующему виду:

#
# Squid configuration:
#

# Set a hostname
visible_hostname proxy.local

# Set nameservers (optional)
dns_nameservers 1.1.1.1

# Local area network
acl localnet src 192.168.0.0/16

# Blocked domains
acl blocked_urls url_regex -i "/usr/local/etc/squid/blocked_urls.acl"

# Squid ports listening
http_port 0.0.0.0:3128 
http_port 0.0.0.0:3129 intercept
https_port 0.0.0.0:3130 intercept ssl-bump connection-auth=off cert=/usr/local/etc/squid/squidCA.pem

always_direct allow all
sslproxy_cert_error allow all

acl blocked_https ssl::server_name "/usr/local/etc/squid/blocked_urls.acl"
acl step1 at_step SslBump1
ssl_bump peek step1

ssl_bump terminate blocked_https 
ssl_bump splice all

sslcrtd_program /usr/local/libexec/squid/security_file_certgen -s /var/log/squid/ssl_db -M 4MB

# Allowed ports 
acl open_ports port 80		# http
acl open_ports port 443		# https
acl ssl_ports port 443
acl CONNECT method CONNECT

#
# Access Permission configuration:
#

# Deny requests to certain unsafe ports
http_access deny !open_ports

# Deny CONNECT to other than secure ssl ports
http_access deny CONNECT !ssl_ports

# Only allow cachemgr access from localhost
http_access allow localhost manager
http_access deny manager

# Deny access to localhost
http_access deny to_localhost

# Deny access to domains
http_access deny blocked_urls 

# Allow access from local networks
http_access allow localnet
http_access allow localhost

# And finally deny all other access to this proxy
http_access deny all

# Disk cache directory
cache_dir ufs /var/squid/cache 100 16 256

# Leave coredumps in the first cache dir
coredump_dir /var/squid/cache

#
# Add any of your own refresh_pattern entries above these.
#
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

# Errors pages
error_directory /usr/local/etc/squid/errors/ru
error_default_language ru

Далее создадим файл со списком запрещенных сайтов:

vi /usr/local/etc/squid/blocked_urls.acl
.youtube.com
.instagram.com

Проверяем конфиг на наличие ошибок:

squid -k parse

Инициализируем кэш:

squid -z

Пробуем запустить прокси сервер:

/usr/local/etc/rc.d/squid onestart

Проверяем статус запущенной службы:

/usr/local/etc/rc.d/squid onestatus
sockstat -l | grep squid

Подгружаем пакетный фильтр PF как модуль ядра:

kldload pf
kldstat | grep pf.ko

Включаем пакетный фильтр PF:

pfctl -e

Добавляем правила в PF для заворачивания трафика на порт прокси:

vi /etc/pf.conf
rdr pass inet proto tcp from any to any port http -> 127.0.0.1 port 3129
rdr pass inet proto tcp from any to any port https -> 127.0.0.1 port 3130

Проверяем и применяем правила:

pfctl -nvf /etc/pf.conf
pfctl -f /etc/pf.conf

Так как мы используем пакетный фильтр PF для заворачивания трафика на порт сквида, необходимо предоставить пользователю squid доступ на чтение /dev/pf, иначе получите ошибку в логе:

PfInterception PF open failed: (13) Permission denied.

Открываем /etc/devfs.conf  и добавляем в конец следующее:

own     pf      root:squid
perm    pf      0640

Перезапускаем devfs:

/etc/rc.d/devfs restart

Не забываем включить пересылку пакетов между интерфейсами:

sysctl net.inet.ip.forwarding=1

Настраиваем автозапуск в файле /etc/rc.conf:

gateway_enable="YES"	# параметр sysctl net.inet.ip.forwarding=1
squid_enable="YES"		# запускать прокси сервер Squid
pf_enable="YES"				# запускать пакетный фильтр PF
pflog_enable="YES"		# возможность логирования трафика через интерфейс pflog

Дополнения:

Иногда сквид может прерывать HTTPS соединения на некоторых ресурсах и в логах могут сыпаться ошибки вида:

SECURITY ALERT: Host header forgery detected on ... (local IP does not match any domain) IP)

Как решение можно использовать локальный кэширующий DNS резолвер, который будут использовать клиенты и сам сквид в том числе.

Источники:

https://habr.com/ru/post/267851/ 

https://habr.com/ru/post/354708/ 

https://www.ew8bak.ru/2017/02/14/freebsd-%D0%BF%D1%80%D0%BE%D0%B7%D1%80%D0%B0%D1%87%D0%BD%D1%8B%D0%B9-%D0%BF%D1%80%D0%BE%D0%BA%D1%81%D0%B8-squid-http-https/

Комментарии (15)


  1. volchenkodmitriy
    02.11.2021 11:11
    +2

    Спасибо за статью. Правильно я понимаю что такой прокси https трафик не вскрывает и не дает возможности его анализировать по содержанию?


    1. isobby Автор
      02.11.2021 11:55
      -1

      Не совсем. Прокси подключается к HTTPS ресурсу, получает его сертификат, и может «посмотреть» некоторые данные о ресурсе, в частности имя сервера с помощью SNI и применяет действие terminate согласно списку ACL.


      1. volchenkodmitriy
        02.11.2021 12:04

        Это я понял из статьи. Но если хочется анализировать сам трафик, например не разрешать скачивать определенные типы файлов, производить антивирусную проверку, кэшировать трафик - это не получится?


        1. isobby Автор
          03.11.2021 09:00

          К сожалению, нельзя полностью просмотреть какая именно интернет-страница была открыта, как при MITM-атаке. К плюсам можно отнести: 1) Это не MITM-атака, и не будет проблем с банк-клиентами. 2) Отображение доменных имен в статитстике сайтов запрашиваемых по https.


          1. volchenkodmitriy
            03.11.2021 10:19
            +1

            Ясно, спасибо!


  1. denaturat
    02.11.2021 11:28
    +2

    А зачем для такой "фильтрации" городить сквид? Проще поднять, если на FreeBSD, локальный unbound, на котором заблэклистить нужные DNS-зоны.

    Ровно тот же эффект будет. Плюс ещё и нестандартные порты закроет.


    1. isobby Автор
      02.11.2021 12:06
      -1

      Фильтровать запросы на уровне DNS не совсем правильное решение. Так как на уровне прокси вы можете определить список групп пользователей, которым необходим доступ к ресурсу и список пользователей, которым доступ запрещен. Из соображений безопасности SNAT по различным портам лучше не использовать и пускать юзеров только через прокси.


      1. denaturat
        02.11.2021 13:19
        +2

        Тут вы "пользователя" определяете по IP адресу, при прозрачном проксировании. Ну и по DNS точно так же views налепить можно.

        Если непрозрачное проксирование - там да, гибче. Но и требует настройки на клиентах, особенно мобильных. И часть кривого софта типа поделий яндекса и whatsapp не хочет брать настройки прокси и лезет напрямую.


        1. isobby Автор
          04.11.2021 10:18

          Чтобы обойти ограничения по DNS, пользователю достаточно включить протокол DoH в браузере.


          1. denaturat
            04.11.2021 17:41
            -1

            оторвать DoH и DoT, равно как и беготню в интернет мимо прокси вообще, раз уж мы начинаем ограничивать свободу беготни клиентов вовне - ничего сложного, по сути плюс одно-два правило пакетного фильтра

            даже, скорее обязательный пункт, фильтрация некоторых сервисов

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


  1. Dukat
    02.11.2021 11:31

    Куча статей про настройку SSL-bump, а вот как настроить шифрованный канал до прокси? Т.е. мне не надо анализировать трафик клиент-сайт, но хочется добавить дополнительный уровень шифрования для защиты от внешнего анализа трафика клиент-прокси. Это вообще возможно средствами Squid?


    1. denaturat
      05.11.2021 04:26

      1. Dukat
        05.11.2021 07:53

        Да.

        "Популярные браузеры пока не умеют"... Что ж, значит, если сильно надо, можно, например, сделать локальный прокси, отправляющий трафик через VPN/SSH/etc. Но это уже будет какой-то стационарный костыль.


  1. post_ed
    02.11.2021 20:29

    Спасибо огромное, я джва года этого ждал!


  1. danfe
    04.11.2021 06:50
    +1

    Ставим пакет libressl — форк openssl:
    Чем дефолтный не устраивает? Не вижу в порте сквида каких-то особых требований к используемой реализации OpenSSL. От LibreSSL нынче больше геморроя, чем пользы; понятно, что у народа подгорело из-за хартблида в 2014 г., но тот урок был выучен и с тех пор OpenSSL маинтейнится сильно лучше, а эти его форки лишь вносят сумятицу и оттягивают усилия разработчиков.
    После установки выполняем подмену OpenSSL на LibreSSL:
    mv /usr/bin/openssl /usr/bin/openssl.old
    ln -s /usr/local/bin/openssl /usr/bin/openssl
    Никогда так не делайте и не советуйте другим. Вместо того, чтобы грязными руками лезть в базовую систему, внося неучтенную зависимость от внешнего пакета, настройте свой интерпретатор командной строки, чтобы при поиске бинарников обходил каталоги в нужном порядке.