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

Если ответ звучит как «знание адреса», то у вас не система прав, а секрет в виде строки. Такая строка может быть длинной и случайной, и это лучше, чем адрес из слов all-hands. Но она отвечает на вопрос «знает ли владелец адрес», а не на вопрос «имеет ли этот человек право смотреть». Дальше разберём, как устроена разница и что с ней делать, когда эфир закрытый, зрители известны, а доступ иногда приходится отзывать.

Кабинет и медиапоток — это две разные двери

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

Поэтому задача делится на две части. Портал отвечает на вопрос «кто это и можно ли ему смотреть этот эфир». Медиасервер отвечает на вопрос «разрешено ли этому запросу получить именно этот поток». Связующее звено между ними — документ, который портал выдаёт после своей проверки, а медиасервер проверяет сам, не ходя за подсказками к порталу при каждом чихе (или ходя, в зависимости от схемы, об этом ниже).

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

Три способа сообщить медиасерверу, кто пришёл

В документации MediaMTX описаны три механизма аутентификации: внутренние пользователи, внешний HTTP-обработчик и JWT с JWKS (MediaMTX: аутентификация). Это разные уровни зрелости под разные задачи, и выбирать между ними стоит по тому, сколько у вас зрителей и как часто они меняются.

  • Внутренние пользователи — список логинов и прав прямо в конфигурации сервера. Подходит для небольшой стабильной группы, например для трёх операторов и двух редакторов. Для сотен сотрудников, которые приходят и уходят, это превращается в ручное редактирование конфигурации.
  • Внешний HTTP-обработчик — медиасервер при каждой попытке подключения спрашивает ваш сервис, пускать ли. Решение принимает ваш код, а значит, отзыв может вступить в силу при следующем же вопросе. Цена — сервис проверки становится критической зависимостью эфира: если он недоступен, нужно заранее решить, что делает медиасервер.
  • JWT с JWKS — портал выдаёт подписанный токен, медиасервер проверяет подпись по публичным ключам и читает из токена права. Никаких обращений к порталу на каждый запрос, но и отозвать уже выданный токен до его истечения просто так нельзя.

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

Выдача временного доступа конкретному человеку

Теперь посмотрим на выдачу. Сотрудница Анна нажимает «Смотреть» на странице эфира. Портал проверяет её по своему списку: состоит ли она в группе, на которую назначен эфир. Если да, он формирует токен и вкладывает его в адрес потока или в заголовок запроса плеера.

Что в этом токене должно быть? В описании токенов LiveKit хорошо видна общая логика такого документа: JWT содержит identity, разрешения и привязку к комнате, а подписывается серверным секретом API (LiveKit: токены и права). Для HLS-эфира через MediaMTX состав другой, но принцип тот же: кто, что может и к чему это относится. В MediaMTX права описываются через mediamtx_permissions: действие и путь потока; а issuer и audience проверяются, если это включено в настройках (MediaMTX: аутентификация).

Переведём это на практику. Токен для Анны разумно собирать так:

  • в качестве субъекта — её корпоративный идентификатор, а не имя и не «guest»; тогда в журнале будет видно, кто смотрел;
  • право только на чтение, и только на путь потока этого эфира, а не на все пути сервера;
  • issuer и audience, настроенные на ваш портал и ваш медиасервер, чтобы токен, выпущенный для другого сервиса, сюда не подходил;
  • короткий срок жизни, соразмерный задаче, о которой ниже.

Здесь легко ошибиться в самой дорогой для поддержки сторону: сделать право слишком широким «чтобы не мучиться». Токен с правом на любой путь превращает утечку одной ссылки в доступ ко всем эфирам компании, включая те, что ещё не начались. Узкое право — это не педантизм, а ограничение радиуса поражения.

Что значит «срок токена» на самом деле

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

Поэтому держите в голове три разных вещи, которые часто смешивают:

  1. Срок токена — сколько времени им можно воспользоваться, чтобы начать.
  2. Серверная проверка — что сервер делает при каждом запросе: смотрит только подпись и срок или ещё и спрашивает ваш сервис.
  3. Уже полученные данные — то, что клиент успел скачать и что остаётся у него независимо от того, что вы решили после этого.

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

Ссылка пошла дальше: что видит сервер

Вернёмся к пересланной ссылке из начала. Допустим, Анна отправила коллеге адрес с токеном. Что произойдёт?

Если токен не привязан ни к чему, кроме срока и пути потока, медиасервер увидит валидную подпись, валидный срок и разрешённый путь. Он не знает, что в браузере теперь сидит не Анна. Для него токен — предъявитель: кто принёс, тот и вошёл. Это не дефект конкретного продукта, а свойство любых токенов-предъявителей.

Сделать с этим можно несколько вещей, и у каждой своя цена.

Способы ограничить пересылку ссылки и их цена
ПодходЧто даётЧего не даёт и что стоит
Короткий срок токенаПересланная ссылка быстро становится бесполезной для новых подключенийНе прерывает уже начатый просмотр; зрителю с обрывом связи придётся получать токен заново
Токен на одного человека с идентификатором в журналеВидно, чей токен использовался; можно разбирать подозрительные случаиНе мешает пересылке, только делает её заметной после факта
Внешний обработчик с учётом активных сессийМожно запретить второе одновременное использование того же токена или аккаунтаНужен свой сервис с состоянием и решение, что делать при сбое этого сервиса
Обмен ссылки на сессию после входа в порталАдрес сам по себе бесполезен без живой сессии пользователяУсложняет плеер и портал; нужна аккуратная работа с cookie и сроками сессии

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

Почему короткий токен не мешает живому просмотру

Возникает естественный вопрос: если токен живёт пять минут, не оборвётся ли эфир у честного зрителя на шестой? Это зависит от того, где именно проверяется токен. Если один раз при открытии потока, то нет. Если плеер каждые несколько секунд просит у сервера новый кусок, а сервер каждый раз проверяет токен, то да, придётся его обновлять.

Здесь полезно понимать, как устроен HLS. Media Playlist перечисляет сегменты, которые клиент получает по HTTP, а Master Playlist содержит варианты потока; клиент может выбирать вариант по доступной полосе (RFC 8216: HTTP Live Streaming). Живой плейлист обновляется по мере появления сегментов. То есть просмотр HLS — это не одно долгое соединение, а длинная череда обычных HTTP-запросов: плейлист, сегмент, плейлист, сегмент. Каждый такой запрос теоретически можно проверять.

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

Кстати, RFC 8216 опубликован в 2017 году и не является документом Internet Standards Track. Это не повод его избегать, спецификация широко описывает формат, но повод помнить, что реальные плееры и серверы могут вести себя по-разному в деталях, и проверять нужные вам клиенты.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации Россия, США, Франция и Великобритания. Оплата картой РФ и по СБП.

АРЕНДОВАТЬ СЕРВЕР

Отзыв при открытом плеере: сколько продлится «ещё немного»

Теперь самая неудобная сцена. Эфир идёт, сотрудник уволен, и его доступ нужно закрыть сейчас. Что произойдёт на его экране после того, как вы нажмёте «отозвать»?

Ответ зависит от того, на что вы нажали.

Вы убрали человека из списка на портале. Это самое частое действие и самое слабое. Портал больше не выдаст ему новых токенов. Но уже выданный токен, если медиасервер проверяет только подпись и срок, остаётся валидным. Плеер продолжит работать, пока токен нужен для обновления плейлиста, а дальше всё зависит от срока. Если срок токена 10 минут и плеер умеет получать новый токен у портала, то через 10 минут портал откажет, и плеер остановится. Окно отзыва равно сроку токена, не больше, но и не меньше.

Вы используете внешний обработчик. Тогда медиасервер спрашивает ваш сервис при подключении. Вы можете отвечать отказом сразу после отзыва. Но обратите внимание на слово «при подключении». Для протоколов с долгим соединением уже установленное соединение не обязательно перепроверяется. Для HLS, где клиент снова и снова обращается за файлами, возможностей больше, но они зависят от того, проверяет ли сервер каждый запрос; это нужно уточнять у конкретной настройки.

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

Теперь про то, что отозвать нельзя совсем. Сегменты, которые плеер уже скачал в буфер, остаются у него. Если сегмент длится несколько секунд и плеер держит запас в несколько сегментов, то после отзыва зритель может досмотреть то, что уже лежит в буфере. Это секунды, не часы, но «мгновенно» — неверное слово. И любой, кто решит сохранять сегменты намеренно, сохранит их за те секунды или минуты, пока у него есть доступ.

Как честно описать отзыв заказчику эфира

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

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

Прямой эфир и запись — это разные права

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

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

Практические следствия такие:

  • Если запись хранится как набор файлов в общем каталоге, доступ к ним нужно описывать отдельно, теми же средствами: токен на конкретную запись, срок, привязка к человеку. Тот факт, что эфир был закрытым, ничего не говорит о защищённости файлов на диске.
  • Если после эфира запись превращается в обычное видеофайл на внутреннем хранилище, права определяются хранилищем, а не медиасервером. Нужно решить, кто и как попадает туда.
  • Токен эфира не должен автоматически открывать запись. Для этого в токене не должно быть пути, совпадающего с каталогом записей, а проверка пути на сервере должна его различать.
  • Отзыв доступа к эфиру сам по себе не отзывает уже скачанные записи. Если запись выдавалась как файл на скачивание, то после скачивания контроль над ним принадлежит получателю.

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

Где всё это живёт: ресурсы под закрытый эфир

Теперь о том, где запускать. Медиасервер, сервис выдачи токенов и, возможно, обработчик проверки — это три небольших компонента, и для небольшой аудитории они могут жить на одном VPS. Самым требовательным местом обычно оказывается не проверка прав (она лёгкая), а раздача видео и, если нужно, перекодирование. Именно они определяют, хватит ли процессора и канала.

На VPS MAATRIX доступны тарифы от Ba (1 vCPU, 2 ГБ RAM, 40 ГБ NVMe) до Djed (16 vCPU, 32 ГБ, 320 ГБ), также есть Uab, Heka и Maat между ними. Ресурсы тарифов — отправная точка для пробного запуска, а не обещание ёмкости: сколько зрителей выдержит конкретная схема, покажет тестовый эфир с реальным битрейтом и реальным числом подключений. Если эфиры записываются, смотрите ещё и на диск: запись быстро занимает место, а NVMe в предложении хорош для частой записи и отдачи сегментов. Root-доступ позволяет поставить нужный медиасервер и обработчик самостоятельно, а выбор локации из UK, US, RU и FR стоит делать с учётом того, где находятся зрители, и ваших внутренних требований. Подробнее о VPS можно узнать на странице аренды VPS MAATRIX.

Если сервис выдачи токенов и медиасервер стоят на разных машинах, добавьте к плану синхронизацию ключей: медиасервер должен получать актуальные публичные ключи для проверки подписи (в схеме с JWKS), а подписывающий секрет остаётся только на стороне портала. Секрет подписи, оказавшийся в плеере или в репозитории фронтенда, обесценивает всю схему: тот, кто его нашёл, выпустит себе токен на любой путь.

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

Сначала граница приватности, потом способ выдачи ссылок

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

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

  1. Кого мы готовы пустить: всех сотрудников, отдел, список имён?
  2. Допустимо ли, что ссылка, пересланная коллеге из того же круга, сработает? Или важно именно, чтобы каждый смотрел под своим именем?
  3. Сколько секунд или минут после отзыва доступа мы готовы терпеть чужой просмотр? Для кого-то это приемлемо, для кого-то нет.
  4. Должна ли запись иметь те же права, что эфир, или другие?
  5. Принимаем ли мы, что человек с доступом может снять экран, и что на это отвечает регламент, а не технология?

Если ответы такие: «всем сотрудникам, пересылка внутри круга не страшна, окно отзыва в несколько минут допустимо, запись общая» — вам хватит короткоживущих JWT с узкими правами и привязкой к идентификатору. Если ответы строже: «только названные люди, отзыв должен вступать в силу на следующем запросе, запись отдельно» — нужен внешний обработчик со своим учётом сессий и отдельные права на хранилище записей. А если вы читаете ответы и понимаете, что допустимо ровно ничего, что могло бы утечь, то вопрос выходит за пределы настройки медиасервера и касается того, стоит ли показывать это видео вообще.

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