14 ноября 2014 в 11:57

Свой tor2web-сервис при помощи Nginx и Lua

Lua*
Tor

Обсудим, как сделать шлюз из Интернета в скрытые сайты Tor.

Сеть Tor — это система прокси-серверов, позволяющая устанавливать анонимное сетевое соединение. С помощью Tor можно анонимно подключаться к обычным серверам и хостить непрослушиваемые серверы в самой сети Tor. В последнем случае создается скрытый сервер в зоне onion. Имя сервера включает 16 букв и цифр (фингерпринт).

зеркало facebook в onion

Как можно заходить на скрытые серверы:

  1. установить Tor и направить через него трафик браузера. Tor-браузер — это portable-приложения, которое включает всё необходимое;
  2. однако не все люди устанавливают Tor-браузер, поэтому нужен способ показать содержимое скрытого сервера обычному пользователю сети. На помощь приходят сервисы tor2web, предоставляющие прямой доступ к скрытым сайтам.

Сайт Hidden Wiki (kpvzxxbbraaigawj.onion) можно открыть в обычном браузере (kpvzxxbbraaigawj.tor2web.fi). Если пользователь подключается к сайту через tor2web, то он теряет анонимность в обмен на доступ к скрытому сайту без установки Tor. Приведу список подобных сервисов, некоторые из которых закрылись.

  • *.Tor2web.org (3 сервера)
  • *.Tor2web.fi
  • *.Tor2web.blutmagie.de
  • *.onion.sh (отключен)
  • *.onion.to (отключен)
  • *.onion.lu (отключен)
  • *.t2w.pw (отключен)
  • *.tor2web.ae.org (отключен)

Рассмотрим существующие способы запустить tor2web-сервис, после чего я поделюсь своим собственным.

Проект Tor2web-3.0?



tor2web-3.0

Tor2web-3.0 — важная часть проекта GlobaLeaks, которая облегчает доступ пользователей сети к скрытым серверам.

Пример сайта: kpvzxxbbraaigawj.tor2web.org

К проекту Tor2web-3.0 подключено 3 сервера. Можно установить Tor2web на свой сервер и примкнуть к их сети. Отключенные серверы .lu и .to принадлежат тем же людям.

Tor2web-3.0 устанавливается как отдельная служба. Код написан на Python. К Tor2web-3.0 практически нет нареканий, но мне хотелось избежать дополнительного участника (пользователь — Nginx — Tor2web-3.0 — Tor — целевой сайт). Кроме того, мне не по душе сетевой софт, написанный на Python.

Polipo?


polipo

Polipo — HTTP-сервер, который умеет перенаправлять подключения в SOCK5-сервер. Раньше Polipo использовался для этой цели в составе Tor-браузера.

Можно было бы выстроить цепочку: Nginx — Polipo — Tor. Как и в случае с Tor2web-3.0, возникает лишний участник, так как Nginx не умеет проксировать трафик через SOCK5-сервер. Кроме того, для нормального отображения сайтов хочется заменять в ответе сервера onion-ссылки ссылками на шлюз: s/.onion/.onion.xx/

Патчим Nginx?


Существует патч для Nginx, который добавляет возможность проксировать трафик через SOCK5-сервер. На самом деле, протокол SOCKS5 очень простой, поэтому странно, что до сих пор нет официального модуля. Это решение выглядит заманчивым, но оно не доведено до ума: пришлось бы патчить Nginx при каждом обновлении. Хочется иметь решение, которое бы работало на обычном Nginx из коробки Debian Wheezy. Кроме того, нет возможности заменять ссылки в ответе сервера.

Пишем модуль для Nginx на Lua



openresty

Nginx давно поддерживает возможность встраивать сценарии на Lua. Коду на Lua предоставляется широкий круг возможностей, в том числе манипуляции с сокетами прямого доступа. К сожалению, модуль для подключения к SOCKS5-серверу я не нашел, поэтому написал свой. Для каждого запроса устанавливается соединение с программой Tor через порт 9050, проходит рукопожатие SOCKS5 и передаётся адрес целевого сайта. После этого сокет используется, как если бы это был прямой сокет к целевому сайту. Запрос пользователя считывается в память, редактируется и передаётся серверу. Ответ сервера считывается, редактируется (замена ссылок) и передается пользователю. Все операции неблокирующие. Эту часть я оформил как отдельный модуль onion2web.

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

Модуль socks5 содержит функции, с помощью которых сокет пробрасывается через SOCK5-сервер. Функции описаны на страничке модуля. Модуль onion2web содержит одну функцию handle_onion2web, которая обслуживает tor2web-шлюз. Пример использования см. ниже. Есть возможность задать адрес и порт тора и отключить форму подтверждения захода на сайт.

Недоработки:

  • реализован очень простой HTTP-клиент версии 1.0, в котором отключены keep-alive и сжатие передаваемых данных.
  • Запрос и ответ читаются целиком в память, после чего передаются получателю. Это увеличивает расход памяти и замедляет передачу информации, особенно в направлении от сайта к пользователю. Подозреваю, что с SOCKS5-сервером нужно общаться в отдельной сопрограмме. Возникнут сложности с подменой адресов в ответе сервера (граница блоков данных может прийтись на заменяемый адрес).
  • Форма загрушки не содержит защиты от CSRF и всегда перенаправляет на главную страницу (лучше перенаправлять на путь, который был открыт изначально).
  • Ответ сервера надо редактировать более аккуратно: заменять ссылки только в HTML и только в атрибутах.

На этом варианте я и остановился и использовал его для своего tor2web-шлюза. К недостаткам самого сайта можно отнести отсутствие SSL. Думаю, есть и другие недостатки. И вообще пока решение скорее костыльное.

Как поднять свой tor2web-шлюз


Нужны домен, сервер и wildcard SSL-сертификат на этот домен.

В домене нужно прописать всем поддоменам IP-адрес нашего сервера:
Редактор DNS замечательного сервиса pdd.yandex.ru

На сервере потребуется Tor, Nginx со свежим ngx_lua и мой модуль onion2web для подключения к SOCKS5-серверу из Nginx. В Debian Wheezy есть пакет nginx-extras, который содержит слишком старый ngx_lua. (Этой старый ngx_lua не поддерживает некоторых используемых методов, например, ngx.req.raw_header.) Версия nginx-extras из wheezy-backports содержит достаточно свежий ngx_lua. Модуль onion2web можно установить через luarocks (это автоматически установит модуль socks5 как зависимость).

Установка для Debian Wheezy:

# echo deb http://ftp.us.debian.org/debian/ wheezy-backports main > /etc/apt/sources.list.d/wheezy-backports.list
# apt-get update
# apt-get install tor luarocks nginx-extras/wheezy-backports
# luarocks install onion2web

В Nginx создаем такой сайт:

server {
    listen 80;
    server_name *.onion.gq;
    location / {
        default_type text/html;
        content_by_lua '
            require("onion2web").handle_onion2web(".onion.gq");
        ';
    }
}

Домен фигурирует в конфиге в двух местах: server_name и внутри Lua-кода.

Сайт готов: kpvzxxbbraaigawj.onion.gq

Исходники модуля socks5: github.com/starius/lua-resty-socks5
Исходники модуля onion2web: github.com/starius/onion2web
Boris Nagaev @starius
карма
40,7
рейтинг 0,0
Похожие публикации
Самое читаемое Разработка

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

  • –5
    лично я против подобных данных в паблике.
    Ты бы еще ссылки на «самые популярные ресурсы» опубликовал.
    • +3
      1. Содержимое onion-сайтов и так в открытом доступе, так как Tor-браузер в открытом доступе.
      2. Вы бы не стали возражать, если бы я поднял обычный веб-прокси? Как и в обычной сети, в онионе есть сайты разных тематик. Мне, например, нравятся их материалы по криптографии.
      3. Ссылки на различные сайты ониона выложены много где, кому надо — найдёт без моей помощи.
  • +1
    Можно еще завернуть это на CDN. Хотя это будет ещё одна точка деанонимизации.
  • 0
    Хоть и не по теме, но отмечу, что у Polopo знатно утекают файловые дескрипторы на высоких нагрузках, т.к. где-то не закрываются корректно сокеты.
  • +1
    Для битовых операций в socks5.lua лучше было бы использовать Lua BitOp, в частности, bit.bswap
    • 0
      Мне кажется, лучше оставить текущий вариант. Из битовых операций вроде бы только преобразование номера порта к big endian, а это не самое нагруженное место. Если воспользоваться bit.*, всё равно потребуется привести к строке (string.char), а для этого нужно будет добыть отдельные байты (сдвигами или теми же делениями). Добавится зависимость от bit.* (а OpenResty может быть собран со стандартным Lua, в котором нет bit.*). Кроме того, такой код закладывается на то, что оборудование little-endian. Текущий вариант ни от чего не зависит и работает на любом оборудовании.
  • 0
    Lua BitOps поставляется вместе с FFI и там есть функция для обределения ednianess.
    • 0
      Действительно, есть ffi.abi(«le»). Однако кода будет больше (определить ednianess, развернуть порядок байт, достать байты, склеить в строку). Последних двух стадий избежать не получится в любом случае, а в текущем решении только они и есть.

      Предлагаю написать двустрочник, который будет реализовывать ваш подход (bit.*) и протестировать его. Не думаю, что он будет работать быстрее текущего варианта. И опять же, это место кода не является бутылочным горлышком, поэтому не вижу смысла его оптимизировать.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.