9 марта 2026 г.

Сокращать ссылки опасно?

Скрытые ловушки Яндекс Кликера и подобных сервисов о которых мы не знаем или забываем

Допустим, у нас есть очень длинная ссылка, которую мы хотим кому-то переслать.

Например, вот так выглядит полная гиперссылка точки в Google Maps на Третьяковскую галерею:

https://www.google.ru/maps/place/%D0%93%D0%BE%D1%81%D1%83%D0%B4%D0%B%
D1%80%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F+%D0%A2
%D1%80%D0%B5%D1%82%D1%8C%D1%8F%D0%BA%D0%BE%D0%B2%D1%81%D0%BA
%D0%B0%D1%8F+%D0%B3%D0%B0%D0%BB%D0%B5%D1%80%D0%B5%D1%8F/@55.74
11429,37.6033703,14z/data=!4m6!3m5!1s0x46b54afe32078357:0xa50d6e8b9a7b028f!8m2!
3d55.741389!4d37.6208639!16zL20vMDRtdnZ6?
entry=ttu&g_ep=EgoyMDI2MDMwNC4xIKXMDSoASAFQAw%3D%3D


Пересылать такое в сообщении неудобно или неэлегантно. Решение: использовать сервис для сокращения ссылок. Например, популярный в России - Яндекс Кликер.

Пример использования Яндекс Кликера

Теперь у нас аккуратный URL: https://clck.ru/3SSRrV. Прекрасно!

Секрет фокуса: короткое доменное имя (адрес сайта) самого сервиса, и преобразование переданной ссылки в уникальный числовой или буквенный идентификатор. В данном случае это "3SSRrV".

Когда кто-то кликает на короткую ссылку, то сервер по идентификатору находит основной адрес и перенаправляет на него браузер клиента.

Что может пойти не так?

Под капотом

Чтобы сервис для сокращения ссылок был востребованным, он должен соответствовать двум требованиям:

  1. Короткая ссылка должна быть валидной (работающей) в любой момент, когда её вызовут.
  2. Преобразование короткой ссылки в длинную должно быть шустрым, незаметным, словно мы сразу обратились по сокращённому адресу.
В открытых источниках информации о посещаемости Кликера нет, но наверняка это значимые цифры. 10-20 тысяч человек в день? Миллион? Сервис должен работать быстро и идемпотентно (выдаёт одинаковый результат при многократном вызове), говоря языком разработчиков.

Как этого добиться?

Каждая ссылка пользователя должна быть сохранена в базу данных, и быстро оттуда извлечена. Самое простое — находить ссылку по уникальному id строки записи. Словно мы говорим серверу: "найди мне адрес, с номером 1038". Поиск по индексу (первичному ключу, primary key) проводится очень быстро, чрезвычайно, и база за миллисекунды найдёт результат.

Значит, при сокращении ссылки можно возвращать что-то такое:

https://clck.ru/1038

Просто и понятно. Ваша ссылка записана в каталог под номером 1038. Однако у этого есть минус: что понятно одному человеку, поймёт и другой. Значит пользователи могут попробовать менять номера: 1037, 1036 и т.д., и видеть ссылки других. Видимых ограничений нет, и авторизация отсутствует для доступа по чужим ссылкам.

Тогда мы решаем замаскировать id. Допустим, в виде букв и символов. Если этот процесс необратим, тогда вместо числовых id нам придётся в базу сохранять этот "хеш", что может замедлить поиск. Лучший сценарий — когда мы можем закодировать число, а когда получим обратно, легко трансформировать снова в числовой id.

Например, кодирование:

id = 3168916193 -> 3SSRrV

Соответственно, декодирование:

3SSRrV -> 3168916193

girls_computer

Внимание, личные данные!

Есть несколько алгоритмов для работы с такими данными. Например, Кликер не проверяет совпадение с уже сохранёнными ссылками, а есть сервисы, которые это контролируют. Минус такого подхода — более быстрое заполнение базы дублями с разными id, плюс — сохранение высокой скорости обработки, нет затрат на проверки.

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

Сервис не использует и алгоритмы запутывания идентификаторов, которые усложнили бы восстановление исходного ID.

Яндекс использует преобразование из десятичной в систему счисления с основанием 62. Это обратимое кодирование (не путать с шифрованием). В отличие от хеширования, оно позволяет легко восстановить исходный числовой идентификатор, что ускоряет поиск в базе данных, но создаёт риск перебора, потому что легко трансформировать в обе стороны.

В Rust есть отдельный крейт (библиотека), который преобразует данные в этой системе в одну строку. Вот пример:

let data = ["3SRYvr", "3SRYuu", "3SRBdY", "3SSRrV"];
for d in &data {
    let value = base62::decode(d).unwrap();
    println!("{}", value);
}

На выходе мы получим числа: 3168704984, 3168615496, 3168916193. Это id длинных ссылок в базе данных сервиса. Отнимем у любого из них 100 миллионов, например, и преобразуем следующие 10 чисел обратно в систему счисления в основанием 62:

let base = 3168704984_u128;
let start = base - 100_000_000;
for id in start..start + 10 {
    let code = base62::encode(id);
    println!("https://clck.ru/{code}");
}

Получится примерно вот такой результат (фрагмент):

Это работающие гиперссылки: кто-то искал Главное управление МЧС России по Республике Коми, другая ведёт на сайт туристического агентства, судя по всему, в Санкт-Петербурге.

screen_komi

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

Выводы

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

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

Никогда не транслируйте чувствительные данные через публичные сервисы, не сокращайте ссылки, ведущие на страницы с личной информацией.

Предупреждение

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

← Назад ко всем записям