docs(tradein/scrapers): в репозитории лежало опровергнутое обоснование хранилища сессий Яндекса
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 10s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 4m44s
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 10s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 4m44s
#3195 замержен с утверждением, что авторизованная сессия раскрывает контакты продавца. Утверждение неверно, а лежит оно в двух местах, которые читают в первую очередь: докстринг app/services/yandex_session.py и шапка миграции 274. Повторный замер (#3192, 2026-08-28) сделан на ПРОД-транспорте — curl_cffi + прокси из пула, тот же путь, что у yandex_detail_backfill, — а не на сайдкаре, как первый: - offerCard.card.author у целевой карточки не несёт phones/phoneNumbers ни в одном из 12 случайных объявлений (6 AGENCY, 6 DEVELOPER), одинаково с куками и без; только encryptedPhones (1 токен) и redirectPhones; - phoneNumbers во всём INITIAL_STATE встречается только под offerCard.visitedOffers[*].author — истории просмотров НАШЕЙ учётки; анонимно список пуст, с куками в нём 9-10 записей; - первый замер («0 → 3,4,5,6») считал рост именно этой истории: +1 на каждый фетч; - authorStats.phones (коммутатор застройщика) отдаётся анонимно — тот же номер в обеих ветках. Правка только текстовая: ни схема, ни поведение не меняются. Шапку применённой миграции правлю сознательно — файл повторно не выполняется (учёт по имени в _schema_migrations), а неверное описание пережило бы любой следующий разбор. Таблицу не трогаю: она пуста, но DROP без явного решения владельца делать нельзя. Судьба #3195 — на владельце, #3192 помечен needs-human. Refs #3192, #3195
This commit is contained in:
parent
fcc6c6576a
commit
c995af73c2
2 changed files with 45 additions and 27 deletions
|
|
@ -1,9 +1,25 @@
|
||||||
"""Yandex.Nedvizhimost session cookie management — load/save/invalidate encrypted cookies.
|
"""Yandex.Nedvizhimost session cookie management — load/save/invalidate encrypted cookies.
|
||||||
|
|
||||||
Замер на проде (#3192, сайдкар, две карточки, режимы вперемежку, 2026-08-28):
|
⚠️ ОБОСНОВАНИЕ ЭТОГО МОДУЛЯ ОПРОВЕРГНУТО (#3192, замер 2026-08-28, разбор в тикете).
|
||||||
авторизованная сессия Яндекс.Недвижимости отдаёт ключ `mainPhone` и на 11 больше
|
Модуль строился под гипотезу «авторизованная сессия раскрывает контакты продавца».
|
||||||
уникальных телефонов продавца (90→101 / 89→100), чем анонимный запрос той же
|
Повторный замер на ПРОД-транспорте (curl_cffi + прокси, тот же путь, что у
|
||||||
карточки — контакты продавца физически недоступны без валидной сессии.
|
yandex_detail_backfill, а не сайдкар) её опроверг:
|
||||||
|
|
||||||
|
- offerCard.card.author — целевая карточка — не несёт phones/phoneNumbers ни в
|
||||||
|
одном из 12 проверенных объявлений (6 AGENCY, 6 DEVELOPER), одинаково с куками
|
||||||
|
и без; есть только encryptedPhones (1 токен) и redirectPhones;
|
||||||
|
- phoneNumbers во всём INITIAL_STATE встречается ТОЛЬКО под
|
||||||
|
offerCard.visitedOffers[*].author — это история просмотров НАШЕЙ учётки;
|
||||||
|
анонимно она пуста, с куками содержит 9-10 записей;
|
||||||
|
- первоначальный вывод «0 → 3,4,5,6 телефонов» считал именно рост этой истории:
|
||||||
|
+1 запись на каждый фетч, а не свойство карточек;
|
||||||
|
- authorStats.phones (коммутатор застройщика) отдаётся анонимно — тот же номер
|
||||||
|
в обеих ветках.
|
||||||
|
|
||||||
|
То есть измеримой разницы по данным объявления авторизация не даёт. Хранилище
|
||||||
|
работает и покрыто тестами, но пока не имеет доказанного применения и НЕ
|
||||||
|
заполнено. Судьба модуля — за владельцем (#3192, label needs-human); удалять
|
||||||
|
таблицу самовольно нельзя. Ниже — исходное описание устройства, оно актуально.
|
||||||
|
|
||||||
Cookies хранятся зашифрованно (pgp_sym_encrypt) в yandex_session_cookies —
|
Cookies хранятся зашифрованно (pgp_sym_encrypt) в yandex_session_cookies —
|
||||||
зеркалит app.services.cian_session / app.services.domclick_session, но:
|
зеркалит app.services.cian_session / app.services.domclick_session, но:
|
||||||
|
|
@ -15,8 +31,8 @@ Cookies хранятся зашифрованно (pgp_sym_encrypt) в yandex_se
|
||||||
browser context (следующая часть #3192) требует domain/path, не только value;
|
browser context (следующая часть #3192) требует domain/path, не только value;
|
||||||
- НЕТ allowlist-фильтра на сохранение (см. filter_analytics_cookies docstring) —
|
- НЕТ allowlist-фильтра на сохранение (см. filter_analytics_cookies docstring) —
|
||||||
Cian/DomClick фильтруют payload по списку известных cookie-имён перед
|
Cian/DomClick фильтруют payload по списку известных cookie-имён перед
|
||||||
сохранением, здесь так делать нельзя: замер выше сделан на ПОЛНОМ наборе из
|
сохранением, здесь так делать нельзя: замеры делались на ПОЛНОМ наборе из
|
||||||
44 cookies, и какая из них существенна для mainPhone-раскрытия — неизвестно.
|
44 cookies, и какая из них за что отвечает — неизвестно.
|
||||||
|
|
||||||
MVP: без verify_session (аналогично domclick_session) — верификация Yandex-сессии
|
MVP: без verify_session (аналогично domclick_session) — верификация Yandex-сессии
|
||||||
требует реального browser-фетча, не простого curl_cffi-запроса; вне рамок этой
|
требует реального browser-фетча, не простого curl_cffi-запроса; вне рамок этой
|
||||||
|
|
@ -48,10 +64,10 @@ COOKIE_EXPIRY_WARN_DAYS = 5
|
||||||
# ВАЖНО: это НЕ allowlist для фильтрации того, что сохранять (в отличие от
|
# ВАЖНО: это НЕ allowlist для фильтрации того, что сохранять (в отличие от
|
||||||
# CIAN_REQUIRED_COOKIES / DOMCLICK_REQUIRED_COOKIES) — используется ТОЛЬКО в
|
# CIAN_REQUIRED_COOKIES / DOMCLICK_REQUIRED_COOKIES) — используется ТОЛЬКО в
|
||||||
# has_auth_marker() для проверки "дамп вообще похож на авторизованную сессию".
|
# has_auth_marker() для проверки "дамп вообще похож на авторизованную сессию".
|
||||||
# Замер #3192 сделан на ПОЛНОМ наборе из 44 cookies, какая именно cookie
|
# Замеры #3192 делались на ПОЛНОМ наборе из 44 cookies, за что отвечает каждая —
|
||||||
# существенна для mainPhone-раскрытия — неизвестно, поэтому save_session хранит
|
# неизвестно, поэтому save_session хранит весь дамп целиком (за вычетом аналитики),
|
||||||
# весь дамп целиком (за вычетом аналитики), а не только эти имена. НЕ сужай
|
# а не только эти имена. НЕ сужай набор, который реально сохраняется, до этого
|
||||||
# набор, который реально сохраняется, до этого списка.
|
# списка.
|
||||||
YANDEX_CRITICAL_COOKIES: set[str] = {
|
YANDEX_CRITICAL_COOKIES: set[str] = {
|
||||||
"Session_id",
|
"Session_id",
|
||||||
"sessionid2",
|
"sessionid2",
|
||||||
|
|
@ -77,12 +93,12 @@ ANALYTICS_COOKIE_PREFIXES: tuple[str, ...] = ("_ym_", "yabs-", "_yasc")
|
||||||
def filter_analytics_cookies(cookies: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
def filter_analytics_cookies(cookies: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
||||||
"""Drop только заведомую аналитику (_ym_*, yabs-*, _yasc*) — остальное как есть.
|
"""Drop только заведомую аналитику (_ym_*, yabs-*, _yasc*) — остальное как есть.
|
||||||
|
|
||||||
В отличие от Cian/DomClick здесь нет allowlist на сохранение: замер #3192
|
В отличие от Cian/DomClick здесь нет allowlist на сохранение: замеры #3192
|
||||||
сделан на ПОЛНОМ наборе из 44 cookies, значимость конкретной cookie для
|
делались на ПОЛНОМ наборе из 44 cookies, значимость конкретной cookie
|
||||||
mainPhone-раскрытия неизвестна. Сужать этот фильтр до allowlist известных
|
неизвестна. Сужать этот фильтр до allowlist известных "критичных" имён —
|
||||||
"критичных" имён — значит потерять часть замера у следующего инженера,
|
значит потерять часть замера у следующего инженера, который решит его
|
||||||
который решит его "оптимизировать". YANDEX_CRITICAL_COOKIES используется
|
"оптимизировать". YANDEX_CRITICAL_COOKIES используется только в
|
||||||
только в has_auth_marker(), не здесь.
|
has_auth_marker(), не здесь.
|
||||||
"""
|
"""
|
||||||
return [c for c in cookies if not str(c.get("name", "")).startswith(ANALYTICS_COOKIE_PREFIXES)]
|
return [c for c in cookies if not str(c.get("name", "")).startswith(ANALYTICS_COOKIE_PREFIXES)]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,20 @@
|
||||||
-- 274_yandex_session_cookies.sql
|
-- 274_yandex_session_cookies.sql
|
||||||
-- Purpose: Encrypted storage for Yandex.Nedvizhimost browser session cookies.
|
-- Purpose: Encrypted storage for Yandex.Nedvizhimost browser session cookies.
|
||||||
-- Замер на проде (сайдкар, две карточки, вперемежку с/без кук, 2026-08-28):
|
|
||||||
-- author.phoneNumbers присутствует ТОЛЬКО в авторизованном режиме
|
|
||||||
-- (0 без кук → 2 с куками, одинаково на обеих карточках), плюс три
|
|
||||||
-- номера в author.phones сверху. Это контакт продавца с тегом канала
|
|
||||||
-- и redirectId.
|
|
||||||
-- NB: mainPhone НЕ собирать — он лежит в паспортном блоке рядом с
|
|
||||||
-- login/passportHost/passportPhones, то есть это номер НАШЕЙ учётки,
|
|
||||||
-- а не продавца. Первая версия этого замера приняла его за данные
|
|
||||||
-- объявления; счётчики по конкретным полям это опровергли.
|
|
||||||
-- encryptedPhones одинаков в обоих режимах (54) — зашифрованные токены
|
|
||||||
-- отдаются всегда, различие не в них.
|
|
||||||
-- Uses pgcrypto pgp_sym_encrypt for AES encryption at rest (зеркалит
|
-- Uses pgcrypto pgp_sym_encrypt for AES encryption at rest (зеркалит
|
||||||
-- 027_cian_session_cookies.sql / 174_domclick_session_cookies.sql).
|
-- 027_cian_session_cookies.sql / 174_domclick_session_cookies.sql).
|
||||||
|
--
|
||||||
|
-- ⚠️ ОБОСНОВАНИЕ ЭТОЙ ТАБЛИЦЫ ОПРОВЕРГНУТО (#3192, замер 2026-08-28).
|
||||||
|
-- Шапка этого файла утверждала, что авторизованная сессия раскрывает
|
||||||
|
-- author.phoneNumbers. Повторный замер на прод-транспорте (curl_cffi +
|
||||||
|
-- прокси, а не сайдкар) показал: у целевой карточки
|
||||||
|
-- (offerCard.card.author) телефонов нет никогда — 12 из 12 объявлений,
|
||||||
|
-- с куками и без, только encryptedPhones + redirectPhones.
|
||||||
|
-- phoneNumbers встречается ТОЛЬКО под offerCard.visitedOffers[*].author
|
||||||
|
-- — это история просмотров НАШЕЙ учётки, растущая на +1 с каждым
|
||||||
|
-- фетчем; именно её рост первый замер принял за данные объявления.
|
||||||
|
-- Таблица создана и пуста. Оставлена как есть: DROP без явного решения
|
||||||
|
-- владельца не делаем (#3192, label needs-human). Разбор — в тикете и
|
||||||
|
-- в докстринге app/services/yandex_session.py.
|
||||||
-- Dependencies:
|
-- Dependencies:
|
||||||
-- - pgcrypto extension (installed here via CREATE EXTENSION IF NOT EXISTS)
|
-- - pgcrypto extension (installed here via CREATE EXTENSION IF NOT EXISTS)
|
||||||
-- Deploy order: Apply after 273.
|
-- Deploy order: Apply after 273.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue