Свой tor2web-сервис при помощи Nginx и 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
    • +18
    • 20,5k
    • 8
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 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.*) и протестировать его. Не думаю, что он будет работать быстрее текущего варианта. И опять же, это место кода не является бутылочным горлышком, поэтому не вижу смысла его оптимизировать.

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