Вернуться в блог
ПутешествияБезопасность

Опубликовал посадочный талон — потерял аккаунт: что мы измерили о закрытии QR-кода

Опубликовано8 min read
Поделиться

Сколько можно вытащить из одного корешка билета

Начну с задокументированного случая, а не с гипотезы.

Журналист по безопасности Брайан Кребс написал об этом разбор в 2015 году. Читатель по имени Кори увидел, что его друг выложил в Facebook фотографию посадочного талона. Он сделал скриншот, увеличил штрихкод и прогнал его через бесплатный онлайн-декодер. Через несколько секунд у него были данные аккаунта часто летающего пассажира этого друга.

Дальше и начинается суть. Кори мог просматривать все будущие рейсы этого аккаунта, менять места уже оформленным пассажирам и отменять любой предстоящий вылет. Хуже того, раскрытых данных хватало, чтобы пройти первую половину процедуры сброса PIN-кода у авиакомпании.

Друг просто радостно выложил фотографию из поездки.

Одну вещь упускают почти все: штрихкоды и QR-коды — не украшение, а контейнеры машиночитаемых данных. Вы видите чёрно-белые квадратики, сканер видит номер брони, имя, рейс, дату и место. Именно этот разрыв и составляет весь риск.

Закрыть половину не работает, и я измерил насколько

Этот раздел мне хотелось написать больше всего, потому что неправильный способ опаснее бездействия: вы считаете себя защищённым и спокойно публикуете.

В QR-код по замыслу встроена мощная коррекция ошибок. Спецификация позволяет сканеру восстановить полное содержимое, даже когда заметная часть символа повреждена, испачкана или закрыта. В физическом мире это полезно: помятый билет или смазанная печать всё равно считываются. Применительно к рассуждению «закрою половину, и хватит» это превращается в уязвимость.

Поэтому я взял и измерил.

Какую площадь на самом деле нужно закрыть

Метод воспроизводим. С помощью библиотеки qrcode для Python я сгенерировал QR-код условного ваучера — содержимое представляет собой ссылку погашения с номером брони и проверочным кодом — на уровнях коррекции M (15 %), Q (25 %) и H (30 %). К каждому применил четыре способа закрытия в семи долях площади, после чего пробовал декодировать через QRCodeDetector из OpenCV. Засчитывалось «всё ещё читается» только при полном восстановлении исходной ссылки.

Результат оказался хуже, чем я ожидал.

Способ закрытия Перестаёт читаться (M, 15 %) Перестаёт читаться (Q, 25 %) Перестаёт читаться (H, 30 %)
Сплошная заливка по центру 15 % площади 20 % площади 25 % площади
Сплошная заливка в правом нижнем углу 20 % площади 25 % площади 25 % площади
Горизонтальная полоса 10 % площади 20 % площади 20 % площади
Мозаика по центру 15 % площади 20 % площади 25 % площади

Читать так: указанный процент — та доля, с которой декодирование начинает давать сбой. Всё, что ниже, по-прежнему считывается.

Три наблюдения стоит запомнить.

Первое: билет с высокой коррекцией ошибок читается даже при закрытой пятой части площади. На уровне H при закрытых 20 % центральная заливка, угловая заливка и мозаика — все три способа вернули содержимое. Тот солидный на вид прямоугольник, которым вы замазали код, на деле не закрыл ничего.

Второе: мозаика повела себя ровно так же, как сплошная заливка — одинаковые пороги на всех трёх уровнях. Это опровергает интуицию, что размытие хотя бы лучше, чем ничего. Оно не безопаснее, оно лишь создаёт видимость проделанной работы.

Третье: горизонтальная полоса оказалась самым действенным из четырёх способов. На уровне M хватало одной полосы, закрывающей 10 % высоты. Причина в том, что полоса пересекает всю ширину символа, и повреждения распределяются по нескольким блокам кодовых слов, тогда как компактный квадрат попадает ровно в ту область, где коррекция ошибок сильнее всего.

Скажу честно: третий вывод противоречит тому, который я собирался написать. Предупреждение о том, что «зачёркивание билета не делает его недействительным», верно — речь там о действительности и читаемости данных. Но если вопрос ставится иначе — какой способ зачёркивания лучше останавливает сканер, — эти данные отвечают, что полоса выигрывает у квадрата. Такую разницу узнаёшь только измерением.

Где закрыть важнее, чем сколько закрыть

Самый полезный результат пришёл в последней серии проверок.

Три больших квадрата в углах QR-кода — это поисковые шаблоны (finder patterns), по ним сканер определяет ориентацию и границы. Я закрыл верхний левый, и все три уровня коррекции не смогли декодировать код — при том что эта область занимает всего 2,0–3,6 % площади изображения.

Иначе говоря: закрыть 2 % в правильном месте лучше, чем 20 % в неправильном.

Границы этой проверки тоже назову. Я использовал декодер OpenCV, единственное содержимое и одну версию QR-кода. Коммерческие сканеры и камеры телефонов реализованы иначе и могут восстанавливать больше. Поэтому считайте приведённые пороги нижней границей, а не гарантией: декодер реального злоумышленника, скорее всего, окажется терпимее моей тестовой среды.

На практике остаётся одно правило: закрывайте весь символ непрозрачной заливкой, с заходом за края. Не угол, не пара штрихов, не мозаика. Если инструмент не позволяет, закройте целиком хотя бы один из трёх поисковых углов.

Закрыто небрежно — значит не закрыто.

Три слоя утечки в скриншотах из поездки

Скриншоты, которые появляются в поездке, делятся на три слоя с принципиально разной природой риска.

Слой Типичный источник Что утекает Худший сценарий
Первый: сканируемый документ Ваучеры Klook/KKday, билеты на мероприятия, посадочные талоны Сам документ, номер брони, зацепки к бонусному аккаунту Билет использован раньше вас, захват аккаунта
Второй: текстовые идентификаторы Подтверждения Ostrovok/Booking.com, номера брони и комнаты Имя, даты проживания, адрес объекта Звонки в отель от вашего имени, социальная инженерия
Третий: данные внутри изображения Экран, сфотографированный другим устройством GPS в EXIF, время съёмки, устройство Вывод о текущем местоположении или доме

Первый слой самый срочный. Ценность электронного ваучера — в самом коде; если его отсканируют раньше, вы узнаете об этом уже на месте. Есть задокументированные случаи, когда злоумышленники брали опубликованные билеты на мероприятия, изменяли их и обманывали желающих купить — пострадавшим оказывается не только автор публикации.

Второй слой выглядит безобидно и служит топливом для социальной инженерии. Имени, дат проживания и названия отеля достаточно, чтобы позвонить на стойку от вашего лица и изменить бронь — или наоборот, позвонить вам от имени отеля и попросить «повторно подтвердить карту». В высокий сезон такого мошенничества заметно больше.

Третий слой упускают чаще всего. В скриншотах с телефона GPS обычно нет, но если вы сфотографировали экран вторым устройством, в этом снимке окажутся координаты места съёмки. Это случается чаще, чем кажется, когда нужно переслать кому-то экран компьютера.

Что делать, когда попутчикам действительно нужны детали

Это самый практичный вопрос. Информацией о маршруте приходится делиться: попутчики должны знать время встречи, содержание билетов и адрес жилья.

Порядок приоритетов такой.

Первый вариант — штатная функция обмена на самой площадке. Klook, KKday, Ostrovok и большинство других поддерживают передачу или совместный доступ к брони для попутчика. По официальному пути действительность документа остаётся под контролем площадки, и никакого гуляющего по чатам скриншота не появляется.

Второй вариант — отправить текст, а не картинку. «26.09, 9 утра, главный вход, билеты у меня» содержит всё необходимое при нулевом риске.

Третий вариант — изображение, но с контролем доступа. Если картинка действительно нужна (сложная таблица маршрута, схема), используйте способ с контролем доступа, а не открытую публикацию.

На lpic.cc при загрузке можно задать пароль на просмотр, и короткая ссылка выдерживает пересылку: без пароля её не откроют. Пароли хранятся в виде bcrypt-хеша, а не сравниваются в открытом виде. Для маршрута, который «нужно показать только этим пятерым», это ощутимо управляемее, чем бросить его в общий чат и отпустить в свободное плавание.

Ограничения тоже проговорю заранее: изображение до 8 МБ, файлы хранятся 30 дней с последнего просмотра, загруженное автоматически оптимизируется, поэтому оригинал не сохраняется. И главное — пароль останавливает тех, кому видеть не следует, но не остановит имеющего доступ, который сделает скриншот и перешлёт его дальше. У любого механизма обмена есть этот потолок. Не считайте его всесильным.

Последний рубеж обороны прежний: по-настоящему чувствительный документ вообще не должен превращаться в файл изображения.

Часто задаваемые вопросы

В1: Я выложил посадочный талон давно. Есть ли смысл удалять сейчас?

Удаление снижает дальнейшую видимость, но не доказывает, что никто не сохранил снимок. Важнее другие два действия: немедленно сменить пароль и контрольные вопросы в аккаунте авиакомпании и проверить будущие брони на несанкционированные изменения. В случае Кребса первым, что мог сделать атакующий, была смена мест и отмена рейсов.

В2: Мой ваучер Klook кто-то отсканировал. Смогу ли я всё же пройти?

Зависит от типа билета. Одноразовый ваучер, погашенный раньше, на месте покажет статус «использован». В такой ситуации нужно немедленно обращаться в поддержку площадки, хотя результат не гарантирован, а в высокий сезон ответ приходит медленно. Именно поэтому здесь профилактика надёжнее исправления.

В3: Достаточно ли замазать QR-код мозаикой?

Недостаточно, и я это измерил. На всех трёх уровнях коррекции пороги отказа у мозаики и сплошной заливки совпали: у билета высокого уровня требовалось закрыть 25 % площади, прежде чем он переставал считываться. Используйте непрозрачную заливку по всей области кода, а лучше закройте его физически ещё при съёмке.

В4: В подтверждении только номер брони и имя. Это тоже риск?

Да. Имени и номера брони на некоторых площадках хватает, чтобы проверить статус бронирования, а с датами проживания набор для социальной инженерии становится полным. В реальных случаях повторяется одна и та же схема: атакующему не нужен ваш пароль, ему хватает достаточного количества обрывков, чтобы убедить сотрудника поддержки.

В5: А сами фотографии из поездки?

Риск другой природы. Там главная проблема — координаты GPS в EXIF. Большинство соцсетей удаляет EXIF при загрузке, а вот облачные диски и отправка «оригинальным файлом» обычно сохраняют его полностью. Как поступает каждый сервис, показано в нашей проверке EXIF по полям на 8 хостингах.

Источники

#QR-код#посадочный талон#приватность в поездке#электронный ваучер#угон аккаунта#утечка данных#тест безопасности
K

Автор

Kevin Wu

Консультант по безопасности

Конфиденциальность и безопасность данных. Ведь каждая фотография рассказывает историю, которую не все должны читать.