Сайт о телевидении

Сайт о телевидении

» » Типы прокси и их различия. Transparent proxy. Быть или не быть

Типы прокси и их различия. Transparent proxy. Быть или не быть

  • Tutorial

Привет, хабровчане! Я думаю, многие в последнее время столкнулись с проблемами доступа к нужным ресурсам из-за попыток Роском позора надзора заблокировать Телеграм. И я думаю, комментарии тут излишни. Факт - эти ресурсы ни в чем не виноваты, но они заблокированы. Проблемы возникли с Viber, ReCaptcha, GoogleFonts, Youtube и др. (кроме самого телеграма). Это случилось и в моей организации, причем некоторые невинные сервисы нужны нам как воздух. В какое-то время решалось все использованием прокси серверов, но они были нестабильны или вовсе отключались (их также блокировал наш великий и могучий РКН).

После прочтения кучи статей, пришла идея научить Squid пускать отдельные URL через Tor. Использовать ли такой метод, решать вам. Но скажу, что после реализации пропали все проблемы, которые были до этого. Кому интересно, идем под кат.

Зачем это?

Статья написана исключительно в целях помощи тем, кто неправомерно страдает от тотального бреда, который творится у нас в стране. Также она ориентирована на тех, кому нужен именно «прозрачный» Squid с HTTPS без подмены сертификатов и возможностью отслеживания посещений как по HTTP так и по HTTPS, поскольку статья по сути является продолжением статьи, так как здесь я предлагаю исправление давнего бага, который не позволял видеть в логах доменные имена https ресурсов и не позволял использовать более новые версии Squid. Ну а также просто для тех, кому интересно использование Squid.


Какие преимущества?

  • Неограниченные возможности масштабирования
  • Относительная легкость в поддержке и администрировании
  • Если это важно, то можно предоставлять анонимный доступ на указанные в списке ресурсы (хоть это и не тема статьи, но анонимность предоставляется «искаропки»
  • Стабильность. При использовании нескольких сервисов Tor (разные конфиг файлы) их можно подключить к Squid, и получить round robin.
  • Абсолютная бесплатность. Навсегда.

Я ничего не знаю, Squid\Tor медленный, пойду и подниму VPS с VPN за бугром

Поздравляю! Вы действительно решили, что Роскомнадзор доставил вам неудобства, и вам же еще за это платить, чтобы выйти из положения? Ок. Можете смело пропускать статью, и поднимать VPN туннели. Кстати, VPN успешно блокируется. Легко. И в свете последних событий, я подскажу, что в скором времени никто не сможет использовать VPS для обхода блокировок на уровне закона. И плюс ко всему, ваш VPS может так же угодить в блокировку «просто потому что рядышком сидит телеграм». Tor не заблокируется, никак. Если его настроить с obfs, то никогда и нигде (тема, пожалуй, для отдельной статьи, так как в этой obfs не рассматривается). И сколько нужно будет поднимать таких VPS с VPN? Как это обслуживать? Здесь же решение легче в разы, надежное, и при желании, вполне скоростное, к тому же бесплатное. Так что прежде чем вводить в заблуждение других читателей, пожалуйста, еще раз обдумайте все + и - VPS с VPN, и только после этого утверждайте, что Squid+Tor - это тормознутое, ненадежное решение.


Tor заблокируют! В Китае, вон, уже заблокирован

Нет. Нет. И еще раз нет. В Китае Tor работает при настроенном obfs. Прекрасно работает. Нет в Мире способа заблокировать Tor. Даже Китаю с его мощностями, умами и финансами не удалось это сделать.


Tor медленный! А если работать через obfs, то вообще жуть!

Обратитесь к оф.документации и куче статей в Интернете, где описывается, как сделать так, чтобы скорость была на приличном уровне. И опять же, настроив таким образом несколько копий Tor с разными конфигами, их можно пристроить к Squid и получить round robin.


Итак, для начала немного теории. Как мы все знаем, Tor - это не HTTP-прокси, его нельзя сделать прямым peer для нижележащего Squid"а. Он предоставляет SOCKS-проксирование (конечно же, не только, но нам нужно именно это). Чтобы нам поженить Tor со Squid, нужно что-то, что могло бы играть роль проводника от Tor к Squid и обратно. И конечно же, дамы и господа, это Privoxy. Как раз таки он способен быть прямым peer, и отправлять все далее в Tor.

Было, как я уже говорил, прочтено куча статей, но ни одна не подходила мне. Попалась вот эта статья, но и она мне не совсем подходила, так как мне не нужен bump. Вообще, все имеющиеся статьи, практически все, подразумевают либо бамп, либо только http, а в моем случае нужно и HTTPS, и splice, и прозрачность. Также видал вот это и , но там совсем другие подходы. Свои плюсы и минусы. Я выбрал для себя именно связку Squid + Tor.

Я уже писал о том, как сделать прозрачный Squid с проксированием HTTPS без подмены сертификатов. И конечно же, я попробовал реализовать идею на нем. Но меня ждало разочарование. HTTP запросы прекрасно уходили в TOR, а вот HTTPS нет. Проблема не очень-то и известная, и я узнал у одного из разработчиков, что это недостаток старых версий Squid. Но в ходе экспериментов было найдено решение - Squid 3.5.27, в котором исправлен данный баг + красивые доменные имена в логах (https), вместо ip адресов. Но и тут меня ждали несколько разочарований, о которых речь пойдет ниже. Но всё, как говорится, допиливается напильником.

Итак, исходные данные:

  1. Debian Stretch (9) x86 (в х64 не пробовал)
  2. Сорцы Squid 3.5.23 из репозитория
  3. Свеженькие сорцы Squid с оф.сайта
  4. OpenSSL
  5. Libecap3
  6. Privoxy
  7. Прямые руки и много кофе с печеньками
Собирать Squid ручками или ставить готовые пакеты (ссылки ниже), решать вам. Если вы думаете, что я впендюрил в них блекджек и ш… вирусы, то компильте сами. Также компилировать нужно, если у вас дистрибутив другой (если Убунта, то поставите). Собирать мы будем версию Squid 3.5.23, которая на момент написания статьи валяется в репозитории Stretch , повысив ее до свежих исходников 3.5.27 с оф.сайта. В отличие от моей первой статьи про HTTPS+Squid, собирать будем без Libressl.

Итак, подготовимся к сборке:

Apt-get install fakeroot build-essential devscripts apt-get build-dep squid3 apt-get install libecap3 apt-get install libecap3-dev apt-get install libssl1.0-dev apt-get install libgnutls28-dev

ВАЖНО!

Очень важно ставить именно libssl1.0-dev, а не другую версию, иначе Squid будет либо лагать, либо не соберется вовсе из-за непонятных ошибок

Apt-get source squid3
Качаем именно этот архив с исходниками Squid:

Wget -O squid-3.5.27-2018.tar.gz http://www.squid-cache.org/Versions/v3/3.5/squid-3.5.27-20180318-r1330042.tar.gz
Переходим в каталог исходников Squid и обновляем исходники до новоскаченных сорцов:

Cd squid3-3.5.23/ uupdate -v 3.5.27-2018 ../squid-3.5.27-2018.tar.gz
Переходим в новоиспеченный каталог с обновленными исходниками:

Cd ../squid3-3.5.27-2018
Добавляем в debian/rules опции для компиляции:

Enable-ssl \ --enable-ssl-crtd \ --with-openssl

Совет

Можете, кстати, вырубить ненужные вам опции, это ускорит компиляцию


Дальше нужно пропатчить исходники вот таким патчем:

client_side_request.patch --- src/client_side_request.cc Thu Aug 18 00:36:42 2016 +++ src/client_side_request.cc Mon Sep 19 04:41:45 2016 @@ -519,20 +519,10 @@ // note the DNS details for the transaction stats. http->request->recordLookup(dns); - if (ia != NULL && ia->count > 0) { - // Is the NAT destination IP in DNS? - for (int i = 0; i < ia->count; ++i) { - if (clientConn->local.matchIPAddr(ia->in_addrs[i]) == 0) { - debugs(85, 3, HERE << "validate IP " << clientConn->local << " possible from Host:"); - http->request->flags.hostVerified = true; - http->doCallouts(); - return; - } - debugs(85, 3, HERE << "validate IP " << clientConn->local << " non-match from Host: IP " << ia->in_addrs[i]); - } - } - debugs(85, 3, HERE << "FAIL: validate IP " << clientConn->local << " possible from Host:"); - hostHeaderVerifyFailed("local IP", "any domain IP"); + debugs(85, 3, HERE << "validate IP " << clientConn->local << " possible from Host:"); + http->request->flags.hostVerified = true; + http->doCallouts(); + return; } void
Для чего он нужен? Я объясню. Когда я писал первую статью про peek and splice, я говорил что более новые версии не работают, и это было так, и вот как раз таки этот патч исправляет ту самую проблему, которая заключалась в том, что Squid выборочно рвет HTTPS соединения, с интересным сообщением в cache.log:

SECURITY ALERT: Host header forgery detected on ... (local IP does not match any domain IP)
Дело в том, что на одном хосте что-то резолвится в один IP, на соседнем иногда в другой, на самом Squid в третий, т.к. существует кеш DNS и обновляется он не синхронно. Squid не находит соответствия ip-домен в своём кеше (потому что обновил свой кеш немного раньше или позже) и прерывает соединение. Вроде как, защита, но в наше время это считается нормальным (round-robin DNS). Разработчики перестраховались. И нам это не нужно совершенно! Тем, кто скажет, что данный патч, возможно, несет в себе угрозу безопасности, я отвечу, что по поводу этого патча я консультировался с Юрием Воиновым, который имеет непосредственное отношение к команде разработчиков Squid. Никакой угрозы здесь нет!

Итак, файлик для патча создали, код кинули, надо пропатчить:

Patch -p0 -i client_side_request.patch
Далее необходимо отменить применение одного патча при компиляции (иначе получите ошибку, что этот патч применить невозможно, так как он уже применен). Идем в debian/patches/series и закомментим там 0003-SQUID-2018_1.patch , поставив перед ним знак # :

Dpkg-buildpackage -us -uc -nc
Установим squid-langpack

Apt-get install squid-langpack
и установим свеженькие пакеты

Dpkg -i squid-common_3.5.27-2018-1_all.deb dpkg -i squid_3.5.27-2018-1_i386.deb dpkg -i squid3_3.5.27-2018-1_all.deb
Если apt матерится на зависимости, сделайте

Systemctl disable squid
и создать systemd сервис в директории /etc/systemd/system (файл сервиса есть в исходниках, и полностью скопирован сюда)

Cat /etc/systemd/system/squid3.service ## Copyright (C) 1996-2018 The Squid Software Foundation and contributors ## ## Squid software is distributed under GPLv2+ license and includes ## contributions from numerous individuals and organizations. ## Please see the COPYING and CONTRIBUTORS files for details. ## Description=Squid Web Proxy Server After=network.target Type=simple ExecStart=/usr/sbin/squid -sYC -N ExecReload=/bin/kill -HUP $MAINPID KillMode=process WantedBy=multi-user.target
Включим его
systemctl enable squid3.service

Установим tor, privoxy

Apt-get install tor privoxy
Конфиг Tor я лично вообще не трогал, а вот конфиг Privoxy можно привести к такому виду:

Listen-address 127.0.0.1:8118 toggle 0 enable-remote-toggle 0 enable-remote-http-toggle 0 enable-edit-actions 0 forward-socks5t / 127.0.0.1:9050 . max-client-connections 500
Почти готово. Перейдем в каталог /etc/squid , кое-что там изменим. Создадим pem файлик, необходимый для splice:

Openssl req -new -newkey rsa:1024 -days 365 -nodes -x509 -keyout squidCA.pem -out squidCA.pem
И приведем squid.conf к следующему виду:

Acl localnet src 192.168.0.0/24 # Ваша локалка 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 acl SSL method CONNECT #Укажем DNS для Squid. Крайне рекомендую использовать одинаковые DNS тут и у клиентов dns_nameservers 77.88.8.8 # Список доменов, которые нужно пустить через Tor acl rkn url_regex "/etc/squid/tor_url" http_access deny !Safe_ports http_access deny CONNECT !SSL_ports http_access allow localhost manager http_access deny manager http_access allow localnet http_access allow localhost http_access deny all icp_access deny all htcp_access deny all #прозрачный порт указывается опцией intercept http_port 192.168.0.1:3128 intercept options=NO_SSLv3:NO_SSLv2 #также нужно указать непрозрачный порт, ибо если захотите вручную указать адрес #прокси в браузере, указав прозрачный порт, вы получите ошибку доступа, поэтому нужно #указывать непрозрачный порт в браузере, если конечно такое желание будет, к тому же в логах #сыпятся ошибки о том, что непрохрачный порт не указан=) http_port 192.168.0.1:3130 options=NO_SSLv3:NO_SSLv2 #и наконец, указываем HTTPS порт с нужными опциями https_port 192.168.0.1:3129 intercept ssl-bump options=ALL:NO_SSLv3:NO_SSLv2 connection-auth=off cert=/etc/squid/squidCA.pem 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 #терминируем соединение, если клиент заходит на запрещенный ресурс ssl_bump terminate blocked ssl_bump splice all # Никогда не пускать напрямую домены, указанные в списке РКН never_direct allow rkn # Указываем прокси, куда отправлять домены из списка, в нашем случае - Privoxy cache_peer 127.0.0.1 parent 8118 0 no-query no-digest default cache_peer_access 127.0.0.1 allow rkn cache_peer_access 127.0.0.1 deny all 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 logfile_rotate 4 pid_filename /var/run/squid.pid
Список url_regex имеет примерно такой вид (список дан для примера!):

Zenway\.ru \.*google\.com \.*viber\.* \.amazon\.com \.fbcdn\.net \.slack\.* media\.api\.viber\.com* static\.viber\.com* secure\.viber.* \*.cloudfront\.net fonts\.gstatic\.com med-edu\.ru

Понадобилось мне недавно поставить прозрачный прокси-сервер в одной конторе. Выход в интернет там организован через роутер ASUS WL-550g, на котором стояла альтернативная прошивка.

Для тех кто не в теме, поясню, что прозрачный прокси отличается от обычного в первую очередь тем, что в броузерах на клиентских машинах не нужно явно прописывать настройки прокси-сервера. Прозрачный прокси просто перехватывает идущий HTTP-трафик и дальше уже предпринимает с ним разные действия. У пользователя при этом создается ощущение, что он работает в интернете без прокси-сервера.

Вобщем для выполнения этой задачи я установил Debian на отдельный ПК, затем поставил туда проси Squid, Apache и Lightsquid для просмотра статистики. После этого встал вопрос каким образом завернуть весь трафик 80-го TCP порта на комп прокси-сервера.

Самое просто что пришло в голову это прописать на шлюзе что-то типа:
iptables -t nat -A PREROUTING -s localnetwork -p tcp -dport 80 -j DNAT -to-destination proxy-server-ip:port
Заработало… Весь трафик реально стал заворачиваться на прокси-сервер, вот только в отображаемой Лайтсквиде статистике получился небольшой казус. Все запросы в интернет отправленные с компьтеров сети в статистике стали отображаться как запросы, отправленные непосредственно с локального IP-адреса маршрутизатора. Почему так произошло, ведь DNAT меняет в IP-пакете только адрес назначения? Все очень просто. Общее правило, по которому вся сеть выходила в интернет никуда не делось, а там у нас было прописано примерно вот что:
iptables -t nat -A POSTROUTING -s localnetwork -j MASQUERADE
На деле получалось так, что в цепочке PREROUTING у нас менялся адрес назначения, а затем, в цепочке POSTROUTING еще и адрес отправителя.
Делаем правильно!
Порывшись в интернете я набрел на доку, в которой написано как наиболее правильно делать перенаправление на прозрачный прокси.
Итак, сначала пишется правило, которое пропускат без изменений весь трафик идущий от прокси-сервера в интернет:
iptables -t mangle -A PREROUTING -j ACCEPT -p tcp -dport 80 -s proxy-server-ip
Трафик идущий в интернет от других компьютеров локальной сети мы маркируем:
iptables -t mangle -A PREROUTING -j MARK -set-mark 3 -p tcp -dport 80
Затем мы создаем правило маршрутизации - весь промаркированный трафик засовываем в новую таблицу 2:
ip rule add fwmark 3 table 2
После этого прописсываем маршрут дл таблицы 2:
ip route add default via proxy-server-ip dev router-lan-interface table 2
После этих шагов весь трафик будет заворачиваться на проски-сервер на момент принятия решения о маршрутизации, т.е. не доходя до цепочки POSTROUTING.
Но тут есть один маленький ньюанс, весь трафик с компьютеров локальной сети будет приходить на прокси-сервер на 80й порт, поэтому Squid нужно настраивать на 80-м порту либо делать REDIRECT с 80-го на какой-нибудь 3128. Правило на прокси-сервере будет выглядить примерно таким образом:
iptables -A PREROUTING -t nat -i eth0 -p tcp -dport 80 -j REDIRECT -to-port 3128
Так как 80й порт на прокси-сервере у нас будет в любом случае занят не зависимо от того повесим мы на него Squid или будем делать редирект, не забудте Apache привязать к другому порту, т.к. по умолчанию он тоже висит на TCP 80.

Под прозрачными прокси понимаются стандартные прокси-серверы, которые не изменяют данные пользователя, оставляя их в «первозданном» виде. То есть они не прячут IP-адрес.

Transparent Proxy обрабатывает весь HTTP-трафик, при этом пользователю не нужно указывать никаких настроек.

Такие прокси помогают ускорить доступ к страницам сайтов, которые определяет пользователь – в основном часто посещаемым. Ускорение загрузки происходит за счет помещения сайтов в кэш. Как правило, прозрачные прокси работают быстрее (скорость загрузки выше), чем их элитные или анонимные «товарищи».

Работодатели используют этот тип прокси для ограничения доступа сотрудников к определенным сайтам (социальные сети, например).

Основной недостаток – низкий уровень скрытности. В основном прозрачные прокси применяются для накрутки счетчиков на странице, при скачивании файлов с файлообменников, для блокировки локальных фаерволов.

Transparent Proxy примерно так передают HTTP-заголовки:

REMOTE_ADDR – демонстрирует IP прокси

Присутствие переменной _X_ говорит о необязательности использования данной переменной. Передача аналогичной переменной происходит в виде HTTP_X_FORWARDER_FOR.

Однако лидеры прокси (Cash Engine, Squid) довольно активно поддерживают эту переменную.

Анонимные прокси (Anonymous proxy)

Если говорить о кэшировании, анонимные прокси имеют преимущества, аналогичные прозрачным. Плюс еще одно неоспоримое преимущество, суть которого передается в самом названии, – анонимность. А поскольку конфиденциальность в интернете – это гарантия того, что компьютер не будет взломан со всеми вытекающими отсюда последствиями, любителей анонимных прокси становится все больше и больше.

Анонимные прокси скрывают данные пользователя при интернет-серфинге. Они меняют IP-адрес случайным образом. И IP-адрес не является зарегистрированным по простой причине: значение HTTP_X_FORWARDER_FOR конечному сайту вообще не передается. Впечатляет, не правда ли?!

Анонимный прокси тоже выдает:

REMOTE_ADDR - демонстрирует IP прокси

HTTP_VIA – демонстрирует адрес прокси-сервера

HTTP_X_FORWARDER_FOR - сообщает прокси ваш IP-адрес.

Однако все сведения заполняются исключительно «для галочки» и не несут правдивой информации. А больше ничего и не нужно, как считают многие интернет-пользователи.

Элитные прокси (Elite Proxy)

Использование элитного прокси – наиболее продвинутый уровень защиты, потому как такой прокси может в максимальной степени обеспечить безопасность нахождения в интернете.

Elite Proxy превосходно маскируется. Это значит, что в интернет-пространстве не появится никаких признаков использования прокси-сервера. Но узнать ваш IP-адрес будет невозможно. Заголовки HTTP_X_FORWARDED_FOR, HTTP_PROXY_CONNECTION, HTTP_VIA вообще не отправляются. Хост не получает никаких сведений: ни об использовании прокси, ни IP-адрес. В этом плане элитные прокси превосходят все остальные прокси-серверы.

Однако недостаток у Elite Proxy тоже имеется: заголовок REMOTE_ADDR сохраняет IP-адрес прокси. Поэтому при отправке пакетов с куками, сохраненными в результате интернет-серфинга, когда вы не использовали элитный прокси, сайты вас не узнают. Не хотите допустить подобное? Чистите кэш и cookies заранее.

Хотя прозрачный прокси сервер меняет ваш IP-адрес и использует свой собственный, ваш настоящий IP-адрес легко найти в запросе. Он не скрывается, а лишь перемещается в другое место.

Не отказывайтесь от бесплатных прокси серверов слишком быстро. Их преимущество – скорость. Они быстрее анонимных или элитных серверов, поскольку их использует меньше людей. Например, если вы хотите пройти через локальный фаерволл, прозрачные прокси серверы – лучшее решение для вас. Они позволят вам продвинуться, не скрывая свой IP. Вместо этого вы можете скрыть сайты, которые открываете.

Что такое анонимный прокси сервер?

Анонимный прокси сервер никогда не передаёт информацию, связанную с вашим настоящим IP-адресом. Это значит, что в Интернет вы невидимы. Поскольку никто не знает, где вы на самом деле находитесь, никто не может незаконно подключиться к вашему компьютеру и похитить ценную и личную информацию.

Если вы подключаетесь к Интернет через прокси сервер, это вполне нормально. Далее, анонимный прокси сервер позволит вам безопасно скрыть свой IP-адрес. В некоторых случаях, например, для мониторинга при использовании мобильного WAP-Интернет, все пользователи вынуждены использовать для подключения прокси сервер. Это вовсе не значит, что вы что-то скрываете.

Что такое элитный прокси сервер?

Элитный прокси сервер особенно безопасен, поскольку он скрывает не только ваш IP-адрес, но и тот факт, что вы используете прокси сервер. Другими словами, эти серверы позволяют вам выглядеть так, как будто вы не используете прокси сервер, а IP-адрес прокси сервера – это ваш настоящий адрес. Главное, что вам следует знать об элитном прокси сервере – что он безопаснее, чем анонимный. Поэтому они очень популярны среди сетевых пользователей и, как следствие, у них низкая скорость.

ДМИТРИЙ РЕПИН

Transparent proxy . Быть или не быть?

Весь текст этой статьи является исключительно личным мнением автора и не претендует на сборник аксиом. Все описанные в статье исследования и выводы также следует рассматривать через призму субъективности автора, ибо, как говорили древние мудрецы, «Errare humanum est». Также автор не несёт ответственности за любые действия (и их последствия), произведённые читателем после прочтения этой статьи.

Лирическое отступление

Работа системного администратора неразрывно связана с программированием. Только наличие знаний в области разработки программ может помочь при решении проблем с программным обеспечением, ибо анализ является частью решения. Специалист обязан чётко представлять себе внутренние механизмы работы системы, а это приходит только с опытом в написании и, что более важно, модификации ПО.

Системы семейства UNIX-подобных являются величайшим источником знаний для самообразования и полигоном для экспериментов. Открытость исходного кода системы и прикладного ПО, низкоуровневый доступ к настройкам и их гибкость... – всё это позволяет глубже вникнуть в принципы работы компьютерных систем и сетей. Кроме того, это позволяет создавать всевозможные нестандартные конфигурации привычного программного обеспечения. Для чего это нужно? В первую очередь для того, чтобы расширить возможности системы. Вторым аргументом в пользу подобных «хирургических вмешательств» в ПО является наличие различных ошибок при разработке программного обеспечения.

Данная статья посвящена проблемам прозрачного проксирования на примере популярного сервера Squid. В качестве ОС использовалась стабильная версия FreeBSD 4.7.

Общие принципы прозрачного проксирования

При работе прокси-сервера в прозрачном режиме (Trans-parent mode) для веб-доступа пользователей в Интернет не требуется настраивать браузер для взаимодействия с прокси на каждом рабочем месте, а сами пользователи могут вообще не знать о существовании прокси-сервера. В таком режиме администраторы и техники получают меньше вопросов и жалоб от пользователей по настройке пользовательского ПО.

Технически этот режим реализуется следующим образом. С помощью firewall все соединения на определённый порт (в случае HTTP – порт 80) внешних серверов перенаправляются на локальный порт прокси-сервера (обычно – 3128).

По стандарту протокола HTTP 1.1 (RFC2616) каждый запрос клиента должен содержать заголовок «Host», в котором указывается адрес сервера-получателя запроса. Именно с помощью этого заголовка прокси-сервер определяет адресата и соединяется с ним. Что же касается других популярных протоколов (FTP, HTTPS, и т. д.), то такой возможности в них просто не предусмотрено. На этой «весёлой ноте» можно начать описание проблем.

Авторизация на прокси-сервере позволяет производить учёт работы и разграничение доступа в Интернет пользователей локальной сети, используя их имена (логины) независимо от того, за каким компьютером находится пользователь и какой адрес имеет данный компьютер. В противном случае администратор имеет возможность контролировать работу сотрудников только на основе IP-адресов, что позволяет пользователям обходить ограничения. Таким образом, авторизация на прокси-сервере является необходимым элементом инфраструктуры локальной сети. А теперь о грустном: авторизация на «прозрачном» прокси-сервере практически невозможна. Однако подобное утверждение явно противоречит стандартам.

Обратимся к первоисточнику – описанию протокола HTTP – документу RFC2616. По стандарту, HTTP-клиент при получении статуса-ответа сервера с кодом 407 (Proxy Authentication Required) обязан отправить данные авторизации серверу. Для иллюстрации работы и для тестов автором был написан небольшой http-сервер на языке Perl, который выдавал нужные статусы и заголовки, а также писал лог запросов и ответов.

В результате работы сервера получение данных клиентом будет происходить в 4 этапа:

  1. Клиент запрашивает документ, а сервер сообщает о необходимости Proxy-авторизации.
  2. Клиент снова запрашивает документ, но уже с данными авторизации на прокси.
  3. Для проверки работоспособности системы сервер просит авторизоваться ещё и для Web – модель ситуации, когда пользователь обращается к защищённому документу на удалённом сервере через прокси с авторизацией.
  4. Клиент послушно авторизуется «вдвойне» – на прокси-сервере и веб-сервере.

В качестве тестовых клиентов использовались браузеры Mozilla FireBird 0.6.1, Microsoft Internet Explorer 6.0.2800.1106 и Opera 6.05.

Код тестового сервера:

#!/usr/bin/perl -w

use strict;

use Socket;

# Создаётся сокет, привязывается ко всем адресам (для удобства) на порт 8080 и включается прослушивание.

socket(SERVER,PF_INET,SOCK_STREAM,getprotobyname("tcp"));

setsockopt(SERVER,SOL_SOCKET,SO_REUSEADDR,1);

bind(SERVER,sockaddr_in(8080,INADDR_ANY));

listen(SERVER,SOMAXCONN);

$|=1;

my $CR="?15?12";

# Приём входящих соединений

while (1){

# Приём клиента, определение его адрес/порт/хост и вывод на экран (для отладки)

My $paddr = accept(CLIENT,SERVER);

My ($ip,$port,$name) = remote($paddr);

Print "Connection from $ip:$port ($name) ";

# Чтение всего запроса от клиента в одну переменную

My $DATA;

While(){

Chomp;

$_=~s/ //g;

Last unless $_;

$DATA.=$_." ";

# Запись запроса в лог-файл

Log($DATA);

# Теперь простая проверка на наличие в запросе нужных заголовков, отправка соответствующего ответа клиенту

# и запись ответов в лог-файл.

If($DATA !~/Proxy-Authorization/){

Log(Response407());

Print CLIENT Response407();

}elsif($DATA !~/?12Authorization/){

Log(Response401());

Print CLIENT Response401();

}else{

Log(Response200());

Print CLIENT Response200();

Print "Connection closed. ";

Close CLIENT;

# Закрытие текущего соединения

# Закрытие сокета сервера

close SERVER;

# Составление ответов сервера для удобства вынесено в отдельные функции

sub Response401{

Return "HTTP/1.1 401 Unauthorized$CR".

"Mime-Version: 1.0$CR".

"Content-Length: 20$CR".

"WWW-Authenticate: Basic realm=" --== Protected web-Area ==--"$CR".

"Connection: close$CR$CR

sub Response407{

Return "HTTP/1.1 407 Proxy Authentication Required$CR".

"Server: squid/2.5.STABLE3$CR".

"Mime-Version: 1.0$CR".

"Content-Type: text/html$CR".

"Content-Length: 20$CR".

"Proxy-Authenticate: NTLM$CR".

"Proxy-Authenticate: Basic realm="<-- 407 Protected Proxy-->"$CR".

"Connection: close$CR$CR

sub Response200{

Return "HTTP/1.1 200 OK$CR".

"Server: squid/2.5.STABLE3$CR".

"Mime-Version: 1.0$CR".

"Content-Type: text/html$CR".

"Content-Length: 19$CR".

"Connection: close$CR$CR

# Функция определения адреса, порта и имени хоста клиента

sub remote{

My $rem = shift;

Return undef unless $rem;

My ($port,$ip) = sockaddr_in($rem);

Return (inet_ntoa($ip),$port,gethostbyaddr($ip,AF_INET));

# Функция для записи в файл протокола

sub Log{

Open(F,">>connection.log");

Print F scalar(localtime)." ";

For(split/ /,$_){

Print F " $_ ";

Print F " //====// ";

Close(F);

Первый запрос браузера:

GET /?test HTTP/1.1

Host: localhost

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5a) Gecko/20030728 Mozilla Firebird/0.6.1

Сервер отвечает:

Сервер сообщает, что всё в порядке:

HTTP/1.1 200 OK

Server: squid/2.5.STABLE3

Mime-Version: 1.0

Content-Type: text/html

Content-Length: 19

Connection: close

Данный протокол на примере Mozilla FireBird 0.6.1 иллюстрирует вполне «законную» возможность использования авторизации на прозрачном прокси-сервере. Возникает резонный вопрос: почему в FAQ сервера Squid наличествует фраза «...proxy_auth can’t be used in a transparent proxy...»?

Для начала обратимся к исходным кодам Squid. Связь между авторизацией и режимом работы сервера прослеживается в двух файлах – acl.c и client_side.c. При анализе кода становится ясно, что возможность использования авторизации в данном случае просто игнорируется!

Участок исходного кода acl.c:

Http_hdr_type headertype;

If (NULL == r) {

Return -1;

} else if (!r->flags.accelerated) {

/* Proxy authorization on proxy requests */

Headertype = HDR_PROXY_AUTHORIZATION;

} else if (r->flags.internal) {

/* WWW authorization on accelerated internal requests */

} else {

#if AUTH_ON_ACCELERATION

/* WWW authorization on accelerated requests */

Headertype = HDR_AUTHORIZATION;

#else

Debug(28, 1) ("aclAuthenticated: authentication not applicable on accelerated requests. ");

Return -1;

#endif

Участок исходного кода client_side.c:

If (answer == ACCESS_REQ_PROXY_AUTH || aclIsProxyAuth(AclMatchedName)) {

If (!http->flags.accel) {

/* Proxy authorisation needed */

Status = HTTP_PROXY_AUTHENTICATION_REQUIRED;

} else {

/* WWW authorisation needed */

Status = HTTP_UNAUTHORIZED;

If (page_id == ERR_NONE)

Page_id = ERR_CACHE_ACCESS_DENIED;

} else {

Status = HTTP_FORBIDDEN;

If (page_id == ERR_NONE)

Page_id = ERR_ACCESS_DENIED;

Подобная странность, обнаруженная в ходе исследования, ещё больше разогрела интерес автора к обсуждаемому вопросу.

В связи с этим, естественно, исходный код сервера претерпел изменения. Результатом явилась модифицированная версия сервера Squid с совместной работой авторизации и прозрачного режима. Но...

В ходе дальнейшего исследования выяснилось, что популярнейший браузер Microsoft Internet Explorer не способен следовать стандартам! Если в настройках этого клиента явно не указано использование прокси-сервера, то MSIE просто игнорирует обработку http-статуса 407 и выдаёт ошибку. Мало того, старые версии под Windows 9X вообще «сыпятся» с критической ошибкой в библиотеке WININET.DLL при получении вышеописанного статус-кода.

В связи с этим становится ясно, что использование авторизации при прозрачном проксировании невозможно. Ведь подавляющее большинство пользователей работают именно с Microsoft Internet Explorer. Если в вашей сети используются браузеры только на основе Mozilla, вы можете модифицировать ваш сервер Squid-2.5.STABLE3 с помощью патчей, которые находятся по адресу http://www.comprice.ru/cmapuk/squid_patch.tgz

В дополнение к вышесказанному стоит добавить, что все нынешние браузеры, так или иначе, не полностью соблюдают стандарты. Например, HTTP-статус 305 (Use Proxy), сообщающий клиенту о необходимости использовать указанный в ответе прокси-сервер, игнорируется как браузером Microsoft Internet Explorer, так и Mozilla FireBird и Opera. Кроме того, браузер Opera (проверено на версии 6.05) не поддерживает NTLM-авторизацию, хотя статус-код 407 обрабатывает правильно и легко авторизуется по типу Basic.

Итак, в действительном существовании проблемы и практической невозможности её решения теперь сомнений нет. Однако остаётся неизвестной «политическая» подоплёка несоблюдения стандартов. После некоторых размышлений на эту тему автор статьи вывел гипотезу о причине «нестандартности» MSIE как HTTP-клиента.

Если абсолютно стандартный браузер при получении ответа сервера с кодом 407 отправляет данные для авторизации, то эта информация может быть получена любым третьим лицом. На примере это выглядит следующим образом. Пользователь-злоумышленник настраивает веб-сервер (внешний, либо в локальной сети) на ответ вышеозначенным кодом при любых запросах (это может быть элементарный «самописный» сервер в 10-15 строк). После этого путём простейших приёмов социальной инженерии пользователь-жертва заманивается в ловушку с целью получить всего лишь один HTTP-сеанс между жертвой и сервером злоумышленника. В результате «хакер» получает данные авторизации пользователя (например, данные NTLM-авторизации), что может повлечь за собой несанкционированный доступ к информации со всеми вытекающими последствиями.

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

Множество протоколов

Как правило, в задачу прокси-сервера входит обслуживание клиентов не только по протоколу HTTP, но и FTP и HTTPS. Кроме того, часто возникает необходимость HTTP-соединения по альтернативным портам (8000, 8080, и т. п.). С этим связана вторая и, пожалуй, самая сложная проблема прозрачного проксирования – прокси-сервер Squid в режиме прозрачности может обслуживать соединения только по одному протоколу – HTTP.

В связи с тем, что решение данной проблемы является отнюдь не тривиальным, эта часть статьи будет посвящена рассмотрению причин данной проблемы и только теоретических способов её решения.

Альтернативные HTTP-порты

Как уже было сказано в начале статьи, спецификация протокола HTTP 1.1 предписывает клиенту включать в запрос обязательный заголовок «Host». Этот заголовок содержит имя сервера, которому адресован запрос. Таким образом, для получения данных по адресу http://www.server.info при прямом соединении минимальным HTTP-запросом будет следующий:

GET / HTTP/1.1

Host: www.server.info

Если клиентское ПО адаптировано для работы через прокси-сервер и настроено соответственно, то запрос будет выглядеть так:

GET http://www.server.info HTTP/1.1

Host: www.server.info

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

GET http://www.server.info:8080 HTTP/1.1

Host: www.server.info

При прямом соединении с удалённым сервером запрос клиента не меняется в зависимости от порта и остаётся таким же, как в первом примере. В результате при работе в прозрачном режиме прокси-сервер не может определить реальный порт удалённого сервера, к которому обратился клиент, так как клиент вообще не подозревает о существовании «посредника».

Современные версии прокси-сервера Squid поддерживают возможность определения хоста и порта с помощью библиотек пакетных фильтров, таких как ipfilter в BSD-системах или netfilter в Linux. Для работы с этими библиотеками при компиляции сервера необходимо указать соответствующие опции (--enable-ipf-transparent). После сборки сервера ему будет доступна подробная информация о соединении.

Участок кода client_side.c:

#if IPF_TRANSPARENT

NatLookup.nl_inport = http->conn->me.sin_port;

NatLookup.nl_outport = http->conn->peer.sin_port;

NatLookup.nl_inip = http->conn->me.sin_addr;

NatLookup.nl_outip = http->conn->peer.sin_addr;

Как может показаться, при таком подходе возникает необходимость использовать на firewall фильтрацию на основе ipfilter/ipnat и отказаться от ipfw. Однако для работы Squid достаточно просто включить поддержку данного пакетного фильтра, а перенаправлять пакеты можно по-прежнему с помощью ipfw.

Проксирование FTP и HTTPS

При обычном проксировании запросы клиента прокси-серверу на получение файла с удалённого сервера по протоколу FTP выглядят так же, как и HTTP-запросы:

GET ftp://ftp.server.info HTTP/1.1

Host: ftp.server.info

Клиентом, реализующим этот протокол FTP, в данном случае является сам прокси-сервер. Получив файл, прокси-сервер отвечает клиенту обычным HTTP-ответом и возвращает данные.

Также клиент может «потребовать» от прокси-сервера прямого соединения с удалённым хостом для обмена данными. Тогда запрос будет выглядеть так:

CONNECT ftp.server.info:21 HTTP/1.1

Host: ftp.server.info

Благодаря такому виду запросов посредник чётко понимает поставленную перед ним задачу и выполняет её в соответствии с рекомендациями системного администратора в виде директив acl и http_access в конфигурационном файле.

Общение клиента с удалённым сервером по SSL-защищённым протоколам всегда происходит по методу CONNECT:

CONNECT secure.server.info:443 HTTP/1.1

Host: secure.server.info

При прямом соединении клиента с удалённым хостом без посредников (а при прозрачном проксировании клиент «считает» именно так) он сам реализует протоколы прикладного уровня, такие как FTP и HTTP. В результате прокси-сервер не может определить поставленную перед ним задачу. При перенаправлении с помощью firewall всех соединений к портам 21 и 443 на порт прокси (3128) последний получает в первом случае строку «USER username», а во втором вообще набор несвязных символов.

Решение данной проблемы требует «хирургического» вмешательства в исходный код прокси-сервера Squid. Задача модификации сервера состоит в том, чтобы «научить» сервер становиться почти таким же посредником, как при методе CONNECT, в зависимости от номера порта запрашиваемого удалённого сервера.

Для демонстрации этой идеи напишем ещё один простейший сервер:

#!/usr/bin/perl -w

use strict;

use Socket;

# Локальный адрес мини-прокси

my $maddr = sockaddr_in(30021,inet_aton("localhost"));

# Допустим, мы уже знаем адрес удалённого FTP

my $paddr = sockaddr_in(21,inet_aton("ftp.freebsd.org"));

# Открываем сокет для прокси-сервера и начинаем прослушивать

socket(SOCK,PF_INET,SOCK_STREAM,getprotobyname("tcp")) or die $!;

setsockopt(SOCK,SOL_SOCKET,SO_REUSEADDR,1) or die $!;

bind(SOCK,$maddr) or die $!;

listen(SOCK,SOMAXCONN);

# Перехватываем сигнал PIPE. Этот сигнал появляется при попытке работы с закрытым потоком

$SIG{PIPE}=sub{

Close(SERVER);

Close(CLIENT);

Close(SOCK);

Exit;

$|=1; # отключаем буферизацию потока STDOUT

# Принимаем подключения

while (accept(CLIENT,SOCK)){

Print "Connection detect. ";

# Соединяемся с удалённым FTP

Socket(SERVER,PF_INET,SOCK_STREAM,getprotobyname("tcp")) or die $!;

Connect(SERVER,$paddr);

# Начинаем обмен информацией

While(1){

My $server="";

# Отключаем буферизацию потоков клиента и сервера

Select(CLIENT); $|=1;

Select(SERVER); $|=1;

Select(STDOUT);

# Пока сервер не завершил передачу

# идентификатором статуса принимаем все данные, отдаём клиенту, а заодно выводим на экран

While($server !~/^d{3}s/){

$server=;

Print CLIENT $server;

Print $server;

# Принимаем команду от клиента и передаём серверу. Также выводим на экран

My $client=;

Print SERVER $client;

Print $client;

Close SERVER;

Close CLIENT;

close SOCK;

Добавляем в firewall правило перенаправления всех запросов к 21-му порту на локальный порт 30021 и запускаем тестовый сервер.

ipfw add 30002 fwd 127.0.0.1,30021 tcp from 192.168.0.0/24 to any 21 via xl0

Теперь открываем браузер и пробуем зайти на ftp://ftp.freebsd.org (естественно, без прокси-настроек). Результат простейшего теста показывает, что прозрачное проксирование по протоколам, отличным от HTTP, вполне возможно. Теперь поставим уже конкретную задачу по модификации прокси-сервера Squid.

1. Добавить в возможности конфигурирования сервера новую директиву (назовём её direct_port) следующего формата:

direct_port PORT PROTOCOL

где PORT – конечный порт удалённого сервера; PROTOCOL – протокол, по которому прокси-серверу следует выступать посредником. Пример:

direct_port 21 FTP, direct_port 443 SSL

2. Добавить к уже имеющейся «услуге» посредничества при методе CONNECT её модифицированную версию, в которой исключены вмешательства прокси-сервера в общение клиента и удалённого сервера лишними заголовками.

3. Установить контроль над новым типом соединения с помощью директив ACL.

Решение этой задачи для исследователя, никогда не участвовавшего в разработке прокси-сервера Squid, является весьма трудоёмким процессом. Посему у автора данной статьи на данный момент нет готового решения в виде патчей и т. п. Однако, возможно, это исследование привлечёт внимание энтузиастов (или самих разработчиков Squid) к вышеописанной проблеме и решение появится.

Вывод

Исследование показало, что настоящее прозрачное проксирование без ущерба для пользователей и администраторов – это реальность. Единственной серьёзной проблемой на пути к внедрению технологии прозрачного проксирования остаётся несоответствие стандартам браузера Microsoft Internet Explorer. Вполне возможно, что в будущем этот недостаток у MSIE исчезнет, если обратить внимание специалистов из Microsoft на данную проблему. В настоящий момент, а точнее, после того, как прокси-сервер Squid будет модифицирован, любая организация, в чьи корпоративные стандарты не входит использование браузера MSIE, смогут полноценно пользоваться прозрачным проксированием.

Ещё одна проблема, оставшаяся в тени, заключается в том, что прокси-сервер может определить адрес удалённого сервера, но не его имя. В связи с этим может возникнуть проблема с доступом по FTP и HTTPS на сервера с виртуальными доменами, которые часто используются на бесплатных хостингах (и не только).

В заключение хотелось бы сказать хоть одну фразу от первого лица. Я надеюсь, что проделанная работа не оставит равнодушной общественность свободных разработчиков к несовершенствам прикладного программного обеспечения и подтолкнёт любителей и профессионалов к новым исследованиям.