К содержанию
← Все записи

Как tapeshelf шифрует видео и почему не хранит ключи

Приватное видео на tapeshelf видят владелец и те, кому он сам его дал. Расскажем, как приложение за этим следит и где его защита заканчивается.

От загрузки до потока

Браузер загружает файл прямо в закрытый бакет S3-совместимого хранилища, частями по 16 МБ. Если связь оборвётся, загрузка продолжится с того же места. Через наши API-серверы файл не проходит.

Фоновый обработчик (воркер) проверяет файл через ffprobe и убирает из него метаданные: место и время съёмки, камеру, автора, комментарии. Файл пересобирается без перекодирования, так что картинка и звук не меняются. Скачивают уже этот очищенный файл. У видео, загруженных до 18 октября 2026 года, метаданные остались.

Видео в H.264 до 1080p, если оно проходит ещё несколько проверок, достаточно переупаковать, это секунды. Остальное перекодируется в H.264 до 1080p. Потом ffmpeg режет результат на шестисекундные сегменты HLS. Safari играет их сам, остальные браузеры через hls.js.

Шифруем сегменты

ffmpeg умеет шифровать HLS и сам, но ключ ему нужен файлом на диске. Мы не хотели, чтобы ключ попадал на диск, поэтому сегменты шифрует воркер:

  • каждый сегмент шифруется AES-128 в режиме CBC, как описано в стандарте HLS;
  • ключ — 16 байт, у каждого видео свой, и существует он только в памяти воркера, пока тот работает;
  • вектор инициализации — порядковый номер сегмента: его плеер HLS подставляет сам, если плейлист не указывает другой.

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

Ключи, которых нет

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

ключ видео = HKDF-SHA256(мастер-ключ, "video:" + id видео + версия) → 16 байт

Версия растёт при монтаже, и у отредактированного видео ключ новый.

Мастер-ключ — один секрет в конфигурации сервера. Его нет ни в базе данных, ни в хранилище, ни в бэкапах. В копии базы нет ни одного ключа видео, в бакете лежат только зашифрованные сегменты, так что понадобится ещё и конфигурация сервера.

Потеряете мастер-ключ, и ни одно видео больше не воспроизведётся, бэкап базы тут не поможет. Особенно это важно, если вы держите tapeshelf на своём сервере.

Три запроса при просмотре

  1. Начало просмотра. API проверяет, можно ли вам смотреть: вы автор, видео стоит на вашей полке или оно публичное. Тогда API отдаёт адрес плейлиста с подписанным токеном на час. В токене записаны видео и вы (или никто, если вы не вошли).
  2. Плейлист. API снова проверяет токен и права и переписывает плейлист на лету. Каждый сегмент превращается в подписанную ссылку на хранилище, а строка с ключом указывает обратно на API.
  3. Ключ. Токен должен быть выписан на это видео. Для приватного видео ещё и сессия, под которой вы вошли, должна принадлежать тому, на кого выписан токен. Только тогда API вычисляет ключ и отдаёт 16 байт.

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

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

Ссылки на сегменты тоже подписаны и истекают через час или позже. Плеер загружает плейлист один раз, и короткие ссылки ломали бы даже обычную паузу. Если ссылка истекла, плеер тихо запрашивает просмотр заново и продолжает с того же места. А без ключа сегмент всё равно бесполезен.

Почему нет файла, который можно унести

Плеер никогда не получает ссылку на сам файл видео. У него есть плейлист, привязанный к токену, зашифрованные куски и ключ за проверкой. Скопируйте адрес плейлиста приватного видео в браузер друга, и ничего не заиграет: ключ требует вашей сессии.

Скачивание — отдельное действие. Вошедшие скачивают то, что им можно смотреть. Без аккаунта скачать можно только по временной ссылке, которую вам прислали, или то, что вы получили как гость в обмене, в течение недели. Ссылка на скачивание живёт две минуты.

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

От чего это защищает

  • Тот, у кого нет доступа, не получает ни плейлиста, ни сегмента, ни ключа.
  • Утёкшая ссылка на сегмент — зашифрованный шум. Утёкшая ссылка на плейлист приватного видео не работает без сессии того, кому её выдали, и в любом случае истекает через час.
  • Украденная копия базы не раскрывает ни одного ключа.

От чего не защищает

  • Кто может смотреть, тот может и записать. Человек с доступом может записать экран или сохранить поток подходящими инструментами. Ключ ему выдан законно. DRM в tapeshelf нет. Настоящий DRM вроде Widevine или FairPlay зависит от коммерческих лицензионных серверов и всё равно бессилен против камеры, направленной на экран.
  • Те, с кем вы поделились. Если вы поделились видео или обменялись им, у человека остаётся постоянная копия, и он может скачать файл. Скачать может и любой, кто открыл вашу временную ссылку, пока она действует. Что будет с файлом дальше, от нас уже не зависит. Делитесь с теми, кому доверяете.
  • Сам сервер. Это не сквозное шифрование. Ключи вычисляет сервер, поэтому тот, кто им управляет, может воспроизвести любое видео. На tapeshelf.com это мы, и приватные видео мы открываем, когда это нужно для работы сервиса и модерации. На своём сервере это его администратор.

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