Перейти до основного вмісту

Робота Spring-застосунку через Tor

Якщо потрібно виконувати HTTP-запити через мережу Tor із Java-застосунку, найкраще використовувати окремий системний сервіс Tor, а не Tor Browser. Системний Tor працює у фоновому режимі, підтримує SOCKS-проксі, ControlPort та дозволяє програмно змінювати IP-адресу за допомогою команди SIGNAL NEWNYM.

У цій інструкції розглянемо встановлення Tor на Ubuntu, налаштування SOCKS-проксі та інтеграцію зі Spring Boot через RestTemplate.

Встановлення Tor

Оновіть список пакетів та встановіть Tor:

sudo apt update
sudo apt install tor

Переконайтеся, що сервіс працює:

systemctl status tor

Якщо сервіс не запущений:

sudo systemctl start tor
sudo systemctl enable tor

Налаштування Tor

Основний файл конфігурації знаходиться за адресою:

/etc/tor/torrc

Додайте до нього наступні параметри:

# SOCKS-проксі
SocksPort 9052

# Порт керування
ControlPort 9051

# Використовуємо пароль
CookieAuthentication 0
HashedControlPassword 16:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

У цьому прикладі використовується порт 9052, щоб не конфліктувати з Tor Browser, який зазвичай займає порт 9150.

Створення пароля для ControlPort

Пароль зберігається у вигляді хешу.

Згенеруйте його командою:

tor --hash-password "myStrongPassword"

Приклад результату:

16:6D4A0E3F3A1E22A427ADFA1F79CC4721E8BCDC7B5D1A25D6A3E45

Скопіюйте отриманий рядок у параметр HashedControlPassword.

Перезапуск Tor

sudo systemctl restart tor

Перевірка відкритих портів

Переконайтеся, що Tor слухає потрібні порти.

ss -tln | grep 905

Приклад результату:

LISTEN 0 4096 127.0.0.1:9051
LISTEN 0 4096 127.0.0.1:9052

Перевірка ControlPort

Підключіться через telnet:

telnet 127.0.0.1 9051

Виконайте команди:

AUTHENTICATE "myStrongPassword"
SIGNAL NEWNYM
QUIT

У відповідь повинно бути:

250 OK
250 OK

Налаштування RestTemplate

Для роботи через Tor використовується Apache HttpClient.

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder)
        throws Exception {

    System.setProperty("socksProxyHost", "127.0.0.1");
    System.setProperty("socksProxyPort", "9052");
    System.setProperty("jdk.net.socks.allowRemoteResolve", "true");

    SSLContext sslContext = SSLContextBuilder.create()
            .loadTrustMaterial(null, (certificate, authType) -> true)
            .build();

    SSLConnectionSocketFactory sslSocketFactory =
            new SSLConnectionSocketFactory(
                    sslContext,
                    NoopHostnameVerifier.INSTANCE);

    Registry<ConnectionSocketFactory> registry =
            RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.INSTANCE)
                    .register("https", sslSocketFactory)
                    .build();

    PoolingHttpClientConnectionManager connectionManager =
            new PoolingHttpClientConnectionManager(registry);

    CloseableHttpClient httpClient =
            HttpClients.custom()
                    .setConnectionManager(connectionManager)
                    .build();

    HttpComponentsClientHttpRequestFactory factory =
            new HttpComponentsClientHttpRequestFactory(httpClient);

    return builder
            .requestFactory(() -> factory)
            .build();
}

Перевірка роботи

Найпростіше перевірити IP-адресу через спеціальний сервіс.

String ip = restTemplate.getForObject(
        "https://api.ipify.org",
        String.class);

System.out.println(ip);

Якщо все налаштовано правильно, буде виведена IP-адреса вихідного вузла Tor, а не реальна адреса комп'ютера.

Програмна зміна IP

Tor дозволяє створити новий маршрут командою SIGNAL NEWNYM.

public void renewTorIp() throws IOException {

    try (Socket socket = new Socket("127.0.0.1", 9051);
         PrintWriter writer =
                 new PrintWriter(socket.getOutputStream(), true);
         BufferedReader reader =
                 new BufferedReader(
                         new InputStreamReader(socket.getInputStream()))) {

        writer.println("AUTHENTICATE \"myStrongPassword\"");

        String response = reader.readLine();

        if (!response.startsWith("250")) {
            throw new IOException(response);
        }

        writer.println("SIGNAL NEWNYM");

        response = reader.readLine();

        if (!response.startsWith("250")) {
            throw new IOException(response);
        }
    }
}

Особливості зміни IP

Команда SIGNAL NEWNYM не гарантує миттєву зміну IP. Tor лише повідомляється про необхідність побудувати новий маршрут. Якщо вже існують відкриті TCP-з'єднання, вони можуть продовжувати використовувати старий маршрут.

Якщо використовується PoolingHttpClientConnectionManager, після зміни IP бажано закрити існуючі з'єднання або створити новий екземпляр HttpClient, щоб наступний HTTP-запит відкрив нове з'єднання через новий Tor-ланцюг.

Поширені проблеми

Tor Browser не запускається.

Причина найчастіше полягає в конфлікті портів. Якщо системний Tor займає порт 9150, Tor Browser також намагатиметься використати його. Рекомендується використовувати інший SOCKS-порт для системного Tor, наприклад 9052.

RestTemplate використовує реальний IP.

Необхідно переконатися, що застосунок дійсно використовує SOCKS-проксі Tor. Для перевірки достатньо виконати запит до сервісу визначення IP.

Після SIGNAL NEWNYM IP не змінюється.

Найчастіше причина полягає у використанні пулу HTTP-з'єднань. Після зміни маршруту необхідно закрити існуючі з'єднання або створити новий HttpClient.

Комбінація системного Tor, ControlPort та RestTemplate забезпечує гнучке рішення для анонімного виконання HTTP-запитів і може бути інтегрована практично в будь-який Java-проєкт.

Коментарі

Популярні публікації

Колекції в Elixir

Списки Що таке список у Elixir У Elixir список — це впорядкована колекція елементів, реалізована як однозв’язний список . Це означає, що кожен елемент (вузол) зберігає посилання на наступний, але не на попередній. Така структура дозволяє швидко додавати елементи на початок списку, але повільно доступати до довільного елементу. У Java подібну структуру представляє LinkedList — частина Java Collections Framework. Вона реалізована як двозв’язний список, що забезпечує зручне додавання/видалення елементів з початку або кінця списку. Створення списків У Elixir список створюється за допомогою квадратних дужок: list = [1, 2, 3, 4] Додавання елементів У Elixir новий елемент можна додати тільки на початок списку за допомогою оператора | : # Elixir list = [2, 3, 4] new_list = [1 | list] # [1, 2, 3, 4] Доступ до елементів У Elixir немає прямого доступу до елементів за індексом, але це можна зробити через Enum.at : Enum.at([10, 20, 30], 1) # 20 Ітерація по списку У Elixir ...

Інструменти для роботи з Node.js

Що таке npm? npm (Node Package Manager) — це офіційний пакетний менеджер для Node.js . Він дозволяє: Встановлювати сторонні бібліотеки та фреймворки Керувати залежностями проєкту Запускати скрипти (команди) через package.json Приклад ініціалізації проєкту з npm npm init -y Файл package.json (скорочений приклад) { "name": "my-project", "version": "1.0.0", "scripts": { "start": "ts-node src/index.ts", "build": "tsc" }, "dependencies": { "express": "^4.18.0" }, "devDependencies": { "typescript": "^5.0.0", "ts-node": "^10.0.0" } } Що таке tsconfig.json? tsconfig.json — це файл конфігурації для компілятора TypeScript, який визначає, як слід компілювати код. Приклад файлу tsconfig.json { "compilerOptions": { "target": "ES2020...

Атоми в мові програмування Elixir

Атоми в Elixir Атоми є фундаментальною концепцією в Elixir , що відіграє ключову роль у створенні надійних та масштабованих систем. В Elixir це специфічний тип даних, який є константою , незмінною , ідентифікованою за своїм ім'ям . Отже, атом в Elixir — це іменована константа, що представляє себе. Уявіть, що ви даєте унікальне ім'я певній речі, і це ім'я завжди посилається саме на цю річ, і ніколи на щось інше. Наприклад, атом :ok завжди буде означати саме успішне завершення операції, а не якесь інше значення. Технічно, атоми є похідними від чисел . Кожен унікальний атом зберігається у таблиці атомів, і йому присвоюється унікальний цілочисельний ідентифікатор. Це робить їх надзвичайно ефективними для порівняння: замість порівняння рядків (що є повільною операцією), Elixir порівнює цілочисельні ідентифікатори. Переваги та особливості використання атомів Переваги атомів: Ефективність. Завдяки своєму числовому представленню, порівняння атомів є дуже швидким. Це осо...

Встановлення PostgreSQL на Ubuntu-сервер

Встановлення Оновлюємо пакети та встановлюємо PostgreSQL: sudo apt update sudo apt install -y postgresql postgresql-contrib Перевіряємо статус сервісу: sudo systemctl status postgresql Якщо PostgreSQL не запущений, запустимо його: sudo systemctl start postgresql sudo systemctl enable postgresql Налаштування безпеки Зміна пароля: sudo -u postgres psql У консолі PostgreSQL: ALTER USER postgres PASSWORD 'міцний_пароль'; \q \q - вихід з консолі. Список основних команд для роботи з PostgreSQL можна переглянути за посиланням. За замовчуванням PostgreSQL слухає localhost (127.0.0.1). Щоб дозволити доступ із зовнішніх машин, редагуємо конфігурацію: sudo nano /etc/postgresql/17/main/postgresql.conf (замість 17 вкажи версію PostgreSQL, яку встановлено) Шукаємо рядок: #listen_addresses = 'localhost' та замінюємо на listen_addresses = '*' Зберігаємо (Ctrl + X, Y, Enter). Тепер редагуємо pg_hba.conf: sudo nano /etc/postgresql/17/main/pg_hba.conf...

Основи Node.js

Що таке Node.js? Node.js — це середовище виконання JavaScript поза браузером, побудоване на рушії Google V8 . Воно дозволяє запускати JavaScript на сервері, створюючи серверні застосунки з високою продуктивністю. Основні характеристики: Однопотокова модель з неблокуючим I/O Асинхронне виконання за допомогою event loop Висока продуктивність у роботі з мережевими запитами npm — найбільший реєстр пакетів Що таке event loop? Event loop — це механізм в Node.js, який дозволяє неблокуючим асинхронним операціям виконуватись у середовищі з єдиним потоком. Він постійно перевіряє наявність подій у черзі та викликає відповідні колбеки. Як працює однопоточність у Node.js? Node.js використовує один потік (main thread) для обробки JavaScript-коду. Операції, які займають час (мережеві запити, читання з файлової системи), делегуються до системних API або thread pool, і після завершення результат повертається у основний потік через event loop. Приклад: асинхронна о...