# Onion-сервіс

## Що це таке

Звичайний сайт знаходять за DNS-ім'ям, що вказує на IP-адресу, а onion-сервіс досяжний лише
всередині мережі Tor, і його ім'я виведене з власного відкритого ключа сервісу. У розмові часто
кажуть просто onion, один демон tor може тримати кілька onion-сервісів поруч, а специфікація й
досі вживає давнішу назву hidden service.

Саме ім'я — це 56 символів base32, за якими йде `.onion`. Після декодування з них виходить 35
байтів: 32-байтовий ідентифікаційний ключ ed25519, двобайтова контрольна сума, взята з геша
SHA3-256 цього ключа, і байт версії зі значенням 3. Цей байт стоїть останнім, тому кожна чинна
адреса закінчується літерою d. Мітку ніхто не обирає: це і є ключ, записаний літерами. Імена
версії 2, що були до неї, складалися з 16 символів, відрізаних від геша SHA-1 ключа RSA-1024, і
tor відмовився від них у випуску 0.4.6.1-alpha 2021 року.

Щоб дві сторони зустрілися й жодна не розкрила, де вона є, протокол використовує два види місць
зустрічі. Сервіс обирає кілька ретрансляторів точками знайомства (introduction points), тримає до
них відкриті ланцюжки й публікує на ретрансляторах-каталогах підписаний дескриптор з їхнім
переліком. Дескриптор зберігається під засліпленим ключем, який змінюється щоперіоду, а його вміст
зашифровано, тож ретранслятор, що зберігає його, не знаючи адреси, переліку не прочитає. Клієнт,
якому адреса відома, завантажує дескриптор, перевіряє підпис ключем з імені, сам обирає
ретранслятор точкою зустрічі (rendezvous point) і через одну з точок знайомства просить сервіс
прийти туди. Сервіс будує власний ланцюжок до точки зустрічі й завершує рукостискання, а
ретранслятор з'єднує два ланцюжки. Увесь шлях проходить через шість ретрансляторів, по три від
кожної сторони, і жоден кінець не дізнається IP-адреси іншого. Необов'язковий режим, що тепер
зветься restricted discovery, а раніше звався client authorization, додатково шифрує дескриптор
для ключа кожного дозволеного клієнта, тож лише ці клієнти дізнаються, де точки знайомства.

## Чому це важливо

Для звичайного сайту DNS і центр сертифікації ділять між собою завдання сказати читачеві, з ким
він має справу. Onion-сервісу не потрібен жоден з них, бо цю роботу виконує саме ім'я. Перевіривши
підпис дескриптора й завершивши рукостискання, клієнт знає, що на тому боці той, хто володіє
приватним ключем за адресою. RFC 7686, який резервує `.onion` як доменне ім'я спеціального
призначення, описує такі імена як поєднання розташування та автентифікації й робить висновок:
onion-ім'я не можна зареєструвати, призначити, передати чи відкликати. Володіти ним означає
розпоряджатися парою ключів, і нічого більше.

Шифрування випливає з тієї самої конструкції. Трафік до onion-сервісу ніколи не залишає мережі
Tor, тож на дальньому кінці немає вихідного ретранслятора й немає останнього відрізка відкритим
текстом. Звичайний `http://` на onion-адресі несе сторінку, зашифровану на всьому шляху, до хоста,
чию особу клієнт звірив з ім'ям, яке отримав.

З погляду експлуатації не менш важливий напрямок з'єднань. Сервіс лише сам дзвонить назовні — до
своїх точок знайомства й до кожної точки зустрічі, — тож йому не потрібен відкритий вхідний порт,
і він працює за NAT. Перелік відкритих портів хоста лишається таким самим, як був.

Адресу читачам усе одно треба якось дізнатися. Сайт може оголосити її заголовком відповіді
`Onion-Location`, і тоді Tor Browser показує в адресному рядку фіолетову кнопку, що веде до
onion-копії сторінки. Tor Project ставить три умови: значення — це URL `http:` або `https:` з
onion-хостом, сторінку, що його надсилає, отримано через HTTPS, і сама вона не розміщена на onion.
Там, де заголовки задати неможливо, те саме оголошення може нести метатег, але без шляху, тож
кожна сторінка вказує на одну незмінну адресу.

## Як це виглядає на практиці

[Onion-дзеркало компанії на читабельній адресі](/uk/portfolio/published-the-site-as-a-tor-onion-mirror-on-a-readable-168/)
описано крок за кроком. Демон встановлено з власного пакета дистрибутива, а вихідний порт проксі
вимкнено. Приватний ключ, який і є адресою, згенеровано поза хостом, і він ніколи не потрапляв ні
до репозиторію, ні на ноутбук; роль відмовляється перезаписувати особу, якої не генерувала сама,
тож покладений вручну ключ використовується як є. Адреса записана в інвентарі як оголошене
значення, і кожне зведення стверджує, що файл особи на хості з ним збігається, тож підмінений ключ
із застарілим оголошенням зупиняє прогін. Обидві сторожі секретів ловлять файл ключа — після того
як вимірювання показало, що очевидний шаблон для файлу ключа збігався з ключем розгортання й
проминав цей.

Читабельний префікс можна знайти, але не обрати. Кожен наступний символ множить очікуваний пошук
на 32, тож вісім літер `engineer` потребують у середньому близько 1,1 трильйона пар ключів.
Випадкову адресу, з якою дзеркало запрацювало спершу, вивели з ужитку поетапним переходом, і
опублікована адреса відповідала весь час. Один крок здавався останнім, але ним не був: ключ ліг на
місце, зведення повідомило про відсутність змін, а нову адресу так і не опублікували, бо ніщо не
називало її теки. Тепер роль валиться на будь-якій особі на диску, якої не називає жодна служба.

[Сторінка подяк](/uk/credits/) наводить повну адресу,
`engineer2ezpeji52ipphljcflzyhetvy5r6tnqubtq45nzlxxv6rsqd.onion`, поруч з адресами Gemini та
Gopher. Усі четверо вхідних дверей ведуть до однієї теки з файлами, тож onion-адресу оновлює те саме
розгортання, що й три інші, а вебверсія надсилає `Onion-Location`, і Tor Browser сам пропонує
onion-адресу. Сторінка також пояснює, що бачить власна мережа читача крізь кожні двері: через Gopher
— яку сторінку читають, через Gemini — яку адресу запитали, через onion-сервіс — ні того, ні іншого.
Префікс вона називає зручністю, а не доказом, і просить звіряти всю адресу.

Будову адреси можна перевірити без мережі. Ці рядки декодують її й заново обчислюють контрольну
суму, і обидва порівняння друкують `True`:

```python
import base64
import hashlib

label = "engineer2ezpeji52ipphljcflzyhetvy5r6tnqubtq45nzlxxv6rsqd"
raw = base64.b32decode(label.upper())
key, checksum, version = raw[:32], raw[32:34], raw[34:]
digest = hashlib.sha3_256(b".onion checksum" + key + version).digest()
print(version == b"\x03", digest[:2] == checksum)
```

Правильна контрольна сума показує, що адресу складено коректно, але не те, кому вона належить. Це
підтверджує її поява на власних HTTPS-сторінках компанії.

## Де виникають проблеми

**Ключ — єдиний документ на володіння.** За ім'ям не стоїть жоден реєстратор, тож утрачений
приватний ключ означає втрачену адресу, а скопійований дає змогу комусь іншому відповідати на ній.
Посібник Tor Project з налаштування радить тримати файли ключів у таємниці й робити резервну копію
ключа, якщо сервіс має жити довго. Ставтеся до нього як до ключа підпису, а не як до конфігурації.

**Читають лише перші літери.** RFC 7686 застерігає, що зловмисник може знайти ключі, чиї імена
схожі на потрібне, і що ризик більший, бо людині ці імена нічого не кажуть. Читабельні імена,
здобуті ціною значних обчислень, RFC вважає одним із засобів захисту, але восьмисимвольний префікс
лишає решту 48 символів такими ж непрозорими, як і раніше. Звіряйте всю адресу або приходьте через
закладку чи посилання на власних HTTPS-сторінках сайту.

**Сервер видає себе сам.** Tor приховує, де працює сервіс, але програмне забезпечення за ним
однаково може це сказати. Серед способів, якими ламається захист, RFC 7686 називає сервер, що
розкриває свою особу в повідомленні рівня застосунку, і сторінка помилки зі справжнім іменем хоста
машини — саме такий випадок. Посібник з налаштування також радить передавати трафік вебсерверу
через Unix-сокет, а не TCP, щоб сервіс не просочувався в локальну мережу:

```text
HiddenServiceDir /var/lib/tor/my-website/
HiddenServicePort 80 unix:/var/run/tor/my-website.sock
```

Найбільше це важить там, де саме розташування і є таємницею.

**Ім'я потрапляє до DNS.** Програма, що не вміє працювати з Tor, питає про onion-ім'я звичайний
резолвер, і локальна мережа та постачальник DNS дізнаються, про який onion ішлося. RFC 7686
вимагає, щоб така програма повертала помилку без запиту, а DNS-сервери відповідали, що такого
імені не існує. Передавайте ім'я клієнтові Tor.

**Кнопка `Onion-Location`, яка так і не з'являється.** Заголовок, заданий лише на переадресації зі
звичайного HTTP, порушує умову про HTTPS, а заголовок з помилкою в адресі веде читачів у нікуди.
Перевіряйте заголовок на остаточній HTTPS-відповіді.

## Що почитати далі

- [Tor Rendezvous Specification, version 3](https://spec.torproject.org/rend-spec/) — увесь
  протокол: ідентифікаційні й засліплені ключі, дескриптори, знайомство та зустріч.
- [Encoding onion addresses](https://spec.torproject.org/rend-spec/encoding-onion-addresses.html)
  — формула, що перетворює відкритий ключ на 56-символьне ім'я, з прикладами адрес.
- [How do Onion Services work?](https://community.torproject.org/onion-services/overview/) — точки
  знайомства, дескриптори й точка зустрічі, розібрані крок за кроком.
- [Set up Your Onion Service](https://community.torproject.org/onion-services/setup/) — рядки
  torrc, файли, які створює tor, і поради щодо ключів та витоків розташування.
- [Onion-Location](https://community.torproject.org/onion-services/advanced/onion-location/) —
  налаштування заголовка й метатега для Apache, Nginx і Caddy та умови, яким має відповідати
  заголовок.
- [RFC 7686](https://www.rfc-editor.org/rfc/rfc7686) — чому `.onion` зарезервовано і що з ним
  мають робити резолвери, оператори DNS та реєстратори.

<https://engineer.company/uk/glossary/onion/>
