Перейти до вмісту
← Документація API

Specification

Формат пакета INTD v1

Формат відкритий навмисно: конфіденційність і цілісність дають шифрування та підпис запиту, а не невідомість розмітки. Фіксована структура і CRC32 дозволяють серверу дешево відкидати сміття до запису в сховище.

Stable Big-endian CRC-32/IEEE X25519 · HKDF · AES-256-GCM

Контейнер

ЗміщенняРозмірПолеЗначення
0 4 MAGIC 0x49 0x4E 0x54 0x44 («INTD»)
4 1 VERSION 0x01
5 1 FLAGS 0x00, зарезервовано
6 8 TIMESTAMP uint64 BE, unix мс — база для дельт
14 4 EVENTS_COUNT uint32 BE
18 4 BLOB_LENGTH uint32 BE, довжина EVENTS_BLOB
22 N EVENTS_BLOB події поспіль
22+N 4 CRC32 uint32 BE, CRC-32/IEEE від EVENTS_BLOB

Підсумковий розмір рівно 26 + N байтів; зайві байти — помилка.

Подія

РозмірПолеЗначення
1 TYPE 0x01 pageview, 0x02 search
4 TS_DELTA uint32 BE, мс після TIMESTAMP
2 + var DOMAIN uint16 довжина ≤ 255, UTF-8
2 + var URL uint16 довжина ≤ 2048, UTF-8
2 + var QUERY uint16 довжина ≤ 500, 0 якщо немає
1 + var LANG uint8 довжина ≤ 20, BCP 47
1 DEVICE_TYPE 0x00 unknown, 0x01 desktop, 0x02 mobile, 0x03 tablet, 0x04 bot

Рядки обрізаються по межі символу UTF-8. Сервер відхиляє пакет, якщо довжина більша за ліміт, рядок не є коректним UTF-8, кількість подій не збігається із заголовком або CRC32 не сходиться.

Що робить сервер

  • Домен перераховується з URL (eTLD+1), значення клієнта не використовується.
  • З URL і запиту вирізаються токени, паролі, e-mail і номери карток.
  • Події, старші за 7 днів, і з майбутнього (більше ніж 10 хвилин) відкидаються.
  • Країна визначається за IP з’єднання, ідентифікатор установки хешується окремо для кожного розширення.

Шифрування і підпис

envelope
sessionKey   = random(32)
iv           = random(12)
ciphertext   = AES-256-GCM(sessionKey, iv, bucket)
ephemeral    = X25519 — нова пара на кожен пакет
shared       = X25519(ephemeral.private, extension.publicKey)
derivedKey   = HKDF-SHA256(IKM = shared, salt = iv, info = "intentd-bucket-v1", 32)
encryptedKey = AES-256-GCM(derivedKey, iv, sessionKey)   // 48 байтів
signature
X-Signature = hex(HMAC-SHA256(secret,
  "intentd-v2|bucket|" + X-Timestamp + "|" + X-API-Key + "|" + hex(SHA-256(body))))

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

Тестові вектори

bucket (hex)
// Одна подія search: база 1758000000000, дельта 7,
// домен a.io, URL https://a.io/?q=x, запит x, мова en, desktop
494e5444 01 00 0000019950f72c00 00000001 00000025
02 00000007 0004 612e696f 0011 68747470733a2f2f612e696f2f3f713d78 0001 78 02 656e 01
cee33ee2
hkdf
HKDF-SHA256(IKM = 0x11 × 32, salt = 0x22 × 12, info = "intentd-bucket-v1", L = 32)
=> 4a359b8818fc073f6f81a3cb4acd9065302e285fbef0d35d2ff71fba107e6056