Подводные камни WebRTC

Всем привет!

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

Разбор будет происходить на основе вот этой статьи: modx.pro/components/16803
Давно уже видел этот топик, но был занят. Сейчас вот могу немного времени выделить, хоть и не спал уже сутки…

Лирика
Это можно не читать, если вам сразу нужны факты, они ниже в отдельном абзаце.

На самом деле если бы не комментарии в этом топике, я бы и не писал ничего. Но каждый комментарий все больше подчеркивает общую картину «Это крутой компонент! Дайте больше!». Уточню: я совсем не против того, чтобы кто-то давал много и круто, но конкретно это ситуация губительна по трем причинам:

1. Это действительно круто! Это и выглядит круто, и возможности заявляются впечатляющие, да еще и воображение дорисовывает перспективы. Это то, что вполне может заинтересовать многих. А значит много кто может попробовать потратить на это свои силы, время и деньги, и потом думать, что делать с недоделанным проектом, за который уже взята предоплата, и клиент ждет результата. Хотя все так просто выглядело в начале...

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

Недостатки технологии
технология определяет только общий стандарт передачи данных (видео и звука), но отдельные решения разных браузеров относительно адресации абонентов и прочих управляющих процессов не совместимы между собой. Поэтому даже звонки между парой различных браузеров представляют отдельную сложность.[9][10][11]
обеспечение групповых конференций требует дополнительных разработок поверх WebRTC.
Не удивительно, что в этих условиях конечный разработчик очень часто просто не в состоянии оценить все За и Против. В таких условиях наиболее оптимистичные люди могут просто на слово поверить автору компонента, что там все работает как надо, и что новые плюшки очень скоро и гарантированно появятся.

Хотите возразить и доказать что достаточно хорошо во всем этом разбираетесь? ОК, в комментах поведайте разницу между STUN и TURN серверами.

3. Недобросовестный автор. Не могу сказать наверняка что здесь присутствует, недобросовестность или искреннее заблуждение с незнанием (а может сразу и то и другое), но что-то из этого есть точно, потому как автор сильно скрывает имеющиеся подводные камни, хотя они просто огроменные. При этом своими ответами он еще больше вводит в заблуждение спрашивающих…

Забегая вперед, к слову, отмечу, что эти три условия не только конкретно в данной ситуации губительны, а в принципе, являются основой для любого мошенничества (1. если интерес, 2. не хватает знаний, 3. недобрый умысел). Исключите любое из этих трех условий, и шанс быть обманутым значительно снижается…

Долгожданные факты

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

1. Вот ТС пишет ответ:
Тут не используются сокеты для соединения пользователей, поэтому да, Node не нужен.
Вот это очень сомнительное преимущество…

Давайте сначала немного теорию разберем, как вообще работает WebRTC. Возьмем два браузера (сидят два разных пользователя друг от друга далеко в своих серых подсетях). Им надо друг с другом соединиться. Если рассматривать эти браузеры как самостоятельные компьютеры, (для простоты понимания), то если они сидят на публичных статических айпишниках, то им легко установить друг с другом связь. Вы же наверняка все слышали про белые (постоянные) и серые (в фейковых подсетях) айпишники. Белый айпишник нужен, чтобы, к примеру, указать его для своего домена, чтобы он вел на ваш сайт (сейчас еще и на большинстве хостингов платишь абонплату за такой айпишник). Так вот, если айпишник белый, то установить клиент-серверное соединение не составит труда, для этого и WebRTC не нужен. WebRTC был придуман как раз для того, чтобы обеспечить соединение браузеров (или компьютеров) как раз в фейковых подсетях, когда простые средства не работают. Проще говоря, если один браузер хочет что-то отправить другому браузеру, он должен знать полный путь до него. Вот WebRTC в этом и помогает, участвуя в создании соединения точка-точка. Происходит это примерно следующим образом:
Шаг 1. Браузер, готовый принимать соединения, устанавливает «общение» с обычным общедоступным сервером, налаживая общение в формате «я тебе, ты мне», то есть браузер не только отправляет запросы на этот сервер, но и ожидает от него сообщения с информацией, что с ним кто-то хочет установить связь.
Шаг 2. Другой браузер тоже выполняет шаг 1, только со своей стороны, и тоже готов поиграться со случайными связями.
Шаг 3. Сервер, как сводница, находит подходящую пару, опрашивает их и убеждается, что их намерения серьезные и они действительно хотят вместе общаться, указывает им их реальные пути, чтобы они могли уже найти друг друга и дальше общаться напрямую без участия посторонних свидетелей.
На самом деле существует несколько реализаций конечного общения, как с участием посторонних серверов, так и без них, напрямую браузер-браузер, но это не суть.

Все верно, в этой схеме обязательно должен быть третий сервер, как минимум один. И браузерам надо как-то с этим сервером общаться, периодически опрашивая его «Есть чо?» и пытаясь ничего не пропустить. Так как здесь в основном php-разработчики, я вас спрошу: «Много ли вы знаете способов организации постоянной двусторонней связи клиент-сервер с использованием php?» И это при том, что php создан, чтобы умирать. То есть как вы обеспечите процесс, чтобы один раз загрузить страницу браузера и она постоянно слушала сервер нет ли у него какой новый информации для него? На самом деле, если говорить о связке с php, то вариант почти единственный: это постоянные запросы на сервер с заданным интервалом, к примеру, через использование в js метода setInterval(), что ТС и сделал, при чем дважды, с существенным копированием кода для клиента и админа. Каждые 2 секунды браузер будет долбить сервер с постоянным вопросом «Есть чо?». Но проблема не только в количестве запросов. setInterval — очень нестабильная функция, особенно в хроме. Когда вкладка уходит в фон, через некоторое время интервал постепенно увеличивается, а не редко и вовсе перестает работать (были жалобы даже на прерывания в текущей вкладке). А в сафари вообще с этим беда, можете погуглить «javascript setinterval safari bug». То есть велика вероятность, что вы откроете вкладку, будете ждать клиента, и клиент придет и напишет, а вот у вас процесс остановился… Потерянный клиент…

Какая альтернатива? Как минимум socket.io. Да, понадобится работающий node-js процесс, но в наше время это не такая проблема, как кажется. Зато работать будет стабильней. И знаете, что интересно? Работа с сокетами в WebRTC предпочтительна и прописана во всех основных библиотеках. И да, основные библиотеки используются и в этом компоненте. К примеру, вот RTCMultiConnection. В нем socket упоминается 220 раз. А вот это WebRTC-adapter. В нем socket не упоминается, но поверьте, по большей части он работает как раз поверх сокет-соединений, через которые приходят сообщения ice-серверов и т.п. И что вы думаете, странные разработчики написал ненужных 12+ килострок когда с использованием сокетов и заменить часть этого механизма на простые Ajax-запросы JS-php будет работать без потерь? Уверяю, нет. Я это все проходил уже.

А к чему я вообще так много пишу в этом пункте? А к тому, что если ТС и выполнил свои «улучшения», то должен сказать, об этом, и какие с этим возможны проблемы в итоге. Это как раз и есть то, о чем я говорил (недобросовестность или недопонимание последствий).

2. Пользователь пишет
Вот бы расширить функционал до связи любого пользователя с любым пользователем. То есть чтобы любой из пользователей мог быть админом, и к нему в очередь записывались другие пользователи на видеоконсультацию например.
а ТС отвечает
По идеи, это можно сделать. У сниппета mwebrtcAdmin есть свойство group, которое определяет группу пользователей, которые будут иметь доступ к функционалу админа. Соответственно, если туда указать ту группу, в которую входят все пользователи, то любой пользователь сможет принимать звонки.
Вот это вообще дикость, и как раз этот ответ по большей степени и побудил к написанию этой статьи… Мой развернутый ответ на это:

В принципе, в текущий реализации примерно это возможно. Но только примерно. И в этом мало чего общего с WebRTC. От WebRTC здесь одно лишь название остается. В реальности же это обычный Ajax-чат, кои делали и 10 лет назад (то есть браузер с интервалом шлет на сервер запрос, получает новую информацию, перерисовывает где что надо и так далее в цикле). Честная же реализация WebRTC подразумевает установку RTC-соединений между конечными браузерами. Когда такие соединения устанавливаются между браузерами, Ajax-запросы (как здесь применяются), уже не нужны, и можно даже веб-сервер ваш отключать, он не нужен, браузеры смогут друг с другом дальше общаться.

Да, здесь светится вышеупомянутая библиотека RTCMultiConnection, но в данной реализации в постоянной связке с Ajax-запросами, это больше минус, чем плюс. Уточню: RTC кроме всего прочего требуется в основном для передачи файлов и видео/звука. Если вам не нужен видеочат, то RTC здесь больше мешает, чем помогает, ведь у вас уже есть какой-никакой чат на JS+PHP, и добавление еще стека технологий просто для наличия малоиспользуемой функциональности сильно усложняет систему и увеличивает риск ошибок, что в данном случае может быть неоправдано.

Для вас эти доводы неубедительны? Считаете видео/аудио и передача данных через RTC вам обязательно нужна, и тут вот есть готовый компонент и я только зря пугаю? Ну хорошо. Просто тогда скажите мне, какие ice-сервера вы планируете использовать в боевом режиме? Какие еще такие ice-сервера? Не было речи ни о каких ice-серверах! Так и есть, речи в вышеупомянутом топике об этом не было. А вообще-то упомянуть об этом надо было бы. Во всяком случае на странице используемой библиотеки RTCMultiConnection есть важная заметка.
For private TURN-servers
You can always set your own TURN-servers using connection.iceServers array object.

It means that…
Now RTCMultiConnection demos or android-apps or chrome-extensions will work only on the same network. Unless or until if you manually set your own TURN-URIs.

BTW, you can always setup your own TURN server using this tutorial.
Короткий вольный перевод:
Ранее используемые дефолтные сервера удалены из конфига. Для рабочего соединения вы должны указать свои TURN-сервера. Это означает в большинстве случаев у вас все будет работать только если все находятся в одной подсети.
Проще говоря, когда вы будете все это тестировать с кем-то, что сидит с вами за соседним компом в одной подсети, у вас все будет работать (хоть и не гарантировано). Но как только к вам будет стучать реальный пользователь из другой сети (я даже не говорю, что он в другом городе, он может даже в одной комнате сидеть, но на другом WiFi-роутере, к примеру), соединения вам скорее всего не видать. Вот такая вот фигня.

И напоследок вопрос: «Зачем человек берет 99% сторонние готовые компоненты, создаваемые годами, сильно их урезает, упаковывает за вечер во что-то сомнительное (для искушенного специалиста, но не для большинства пользователей), регается здесь, пишет топик, потом 3 коммента, и далее никакой активности?». Зря калории потратил? Ну бывает… А может не зря?.. Если кто заинтригован, вот пища для размышлений. Спойлер: речь про JS-инъекцию на множество серверов через стороннюю библиотеку. И вот здесь у меня, наверно, неприятный вопрос к @modstore. Виталий, Леонид, Василий, а кто вообще принимал этот компонент к публикации? Более всего интересует вопрос кто проверял его на безопасность? И по каким критериям? Выглядит безопасно? За что переживать, ведь на гитхабе даже исходники есть? ОК, давайте посмотрим исходники, действительно, раз плюнуть! Так, что мы имеем? adapter.js, 5100 строк кода… Хм. Ну ладно, за вечер прочитаю (не пойму, но прочитаю). Ладно, дальше едем. RTCMultiConnection.js 6435 строк кода… Ну ладно, с этим проще, ведь есть RTCMultiConnection.min.js, там всего одна строчка. Ну а дальше вообще не буду смотреть, там все мелкое, после предыдущих файлов не заслуживает внимания вообще…

Не кажется вам, что такой объем JS кода, да еще и устанавливаемого в админку, это дофига? Уверены, что там нет никакой заразы? К примеру, чтобы навесить события на поля ввода и в риалтайме передавать их злоумышленнику? Знаете в чем ирония? RTC-соединения как раз для этого лучше всего подходят :) Это вам не Ajax и даже не ws, вы их просто так не увидите в браузере во вкладке «Сеть». Если что-то полетит в сторону, вы и не заметите.

Хотите больше жути? У меня ее есть. Загуглите «webrtc hide ip». Это очень интересная «фишка». WebRTC, как раз за счет своей способности обходить НАТы и формировать полный путь до конечной точки, позволяет другой стороне получить ваш реальный конечный IP. То есть если вы сидите в офисе, в котором один только внешний IP, за которым через три подсети сидят сотня сотрудников за кучей девайсов, эта технология позволяет при заходе пользователя на веб-страницу получить его самый конечный адрес. Подробней читайте здесь, если интересно.

И последний вопрос, на который можно не отвечать вообще, но лучше хотя бы как-то ответить: вы с ним какой-то договор заключили? У вас есть его паспортные данные или типа того? Мне они не нужны. Мне просто интересно, есть ли у вас что-то на него кроме его компонента, честного слова и девочки на аватарке? Знаете, я думаю что нет. Возможно как раз для этого он бесплатно и разместился. Если бесплатно, то можно и документы не брать. Но я надеюсь, что вы все-таки получили документы и как-то даже его проверили.

Конечно, может я и преувеличиваю, и человек действительно старался и поделился замечательным компонентом. Но я все равно считаю, что к этим вопросам надо относиться внимательней.

Во-первых, если приходит компонент в котором много кода, который вы физически не можете проверить, его нельзя принимать. Зачем там вот все эти JS-ы? Это сторонние публичные библиотеки. Вот оригинальные RTCMultiConnection и adapter. Пусть ссылку на CDN дает или инструкцию как подключить официальную библиотеку, а лучше мелкий проект с зависимостями, сборка его и релиз в npm.

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

В-третьих, больше критики. Критика никому не нравится, но без нее же порой вообще никуда.
Fi1osof
07 января 2019, 10:12
3
471
+11

Комментарии: 10

Дмитрий
07 января 2019, 18:46
+4
Большое спасибо, Николай, за вашу большую критику моего компонента

На самом деле, выкладывая его, я ждал именно такого разгрома, т.к. являюсь новичком и mWebRTC был моим первым проектом на MODX и PHP, в целом. То, что до этого его так хвалили для меня было шоком, потому что я понимал, что в нём много дыр. Но каких, я не знал и хотел, чтобы мне указали.

Тут не используются сокеты для соединения пользователей, поэтому да, Node не нужен.
Я не выставлял это, как преимущество, и сам считал, что это большой недостаток, что не используются сокеты. Но у меня тогда не было возможности поставить node на сервер, на котором я тестировал компонент. Понимаю, как это глупо может звучать, но все действительно так и было, у меня были очень ограниченные права. Поэтому, я не нашел ничего, кроме как проводить соединение через постоянные запросы. Хотя ещё до этого, я пытался попробовать SSE вариант от RTCMultiConnection, но он соединял лишь где-то в 50% случаях (как будто для этого использовалась функция рандома). При этом, я пытался сделать компонент таким, чтобы его можно было довольно просто изменить или улучшить, т.е. можно было бы поменять функционал сигнального сервера или заменить его своим (тем же socket.io).

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

Во-первых, если приходит компонент в котором много кода, который вы физически не можете проверить, его нельзя принимать. Зачем там вот все эти JS-ы? Это сторонние публичные библиотеки. Вот оригинальные RTCMultiConnection и adapter. Пусть ссылку на CDN дает или инструкцию как подключить официальную библиотеку, а лучше мелкий проект с зависимостями, сборка его и релиз в npm.
Это было сделано по 2 причинам, которые мне казались логичными. 1. новые версии этих js-файлов могли не работать нормально с компонентом, по причине каких-нибудь изменений в новых версиях, поэтому я положил туда те версии файлов, в которых я был уверен, что они будут делать то, что мне нужно. 2. Подключать файл со стороннего сервера не выглядел привлекательным по причине того, что тот сервер банально может в один прекрасный момент перестать работать и файл, в итоге, не будет подключен.

Опять же спасибо за вашу критику. А теория про злоумышленника мне показалась забавной и интересной, хоть и понимаю, что небезпочвенна.
    Fi1osof
    07 января 2019, 18:57
    0
    Дмитрий, не за что!
    Рад, что был услышан и адекватно воспринят. Вас я тоже услышал.
Igor Ivanov
08 января 2019, 08:32
0
Николай, спасибо! Ты, как всегда. на высоте. Интерестно, задорно, познавательно. Рад. что ты вернулся в сообщество, пусть и частично, твои комментарии по самым разным вопросам всегда интерестно читать. Успехов тебе в Новом году!
    Fi1osof
    08 января 2019, 09:38
    0
    Не за что!
    Я сейчас не мало пишу у нас в modxcllub.ru. Сейчас еще и чат новый обкатываем. Но и здесь тоже буду иногда, пока не выгонят)) (по JS больше топиков появляется).
    Тоже всего наилучшего!
Виталий Дощенко
08 января 2019, 17:48
+2
Коля, привет! Идея про более тщательную проверку дополнений от новых авторов принята!
    Fi1osof
    08 января 2019, 17:55
    0
    Круто! :)
Илья Уткин
08 января 2019, 21:39
+2
Не кажется вам, что такой объем JS кода, да еще и устанавливаемого в админку, это дофига? Уверены, что там нет никакой заразы?
Насколько я знаю, в админке у компонента нет своей страницы и в админку эти скрипты не подключаются. Только на фронтенде при вызове сниппета.

Но, конечно во фронтенде тоже есть, что украсть.

Вы с ним какой-то договор заключили? У вас есть его паспортные данные или типа того?
Злоумышленнику выгоднее разместить компонент в официальном репозитории MODX — там охват больше. Ну и никаких паспортных данных никто не спросит. Компонент никто даже на работоспособность не проверит.

Но за ликбез спасибо, конечно эту тему необходимо поднимать и обращать внимание сообщества на потенциальные уязвимости.
    Илья Уткин
    08 января 2019, 21:45
    +2
    А как, кстати, можно решить проблему? Никто не будет выделять по 8 часов работы на проверку дополнения, которое не принесёт ни копейки. Требовать паспортные данные и пересылку бумажного договора по почте для размещения дополнения в репозитории? Тоже не выход — в таком случае никто связываться не будет…
      Fi1osof
      08 января 2019, 23:01
      +1
      Совсем решить ее не получится. Но надо об этом как минимум думать. Я выше описал варианты. В данной ситуации достаточно было компонент собрать правильно через тот же вебпак или галп (гульп/gulp, кому как больше нравится). В зависимостях сослаться на публичные компоненты и оставить только свой код. Было бы меньше что проверять.
    Fi1osof
    08 января 2019, 22:58
    +1
    Насколько я знаю, в админке у компонента нет своей страницы и в админку эти скрипты не подключаются. Только на фронтенде при вызове сниппета.
    Вот я в этой ситуации вообще не уверен. Объясню. Здесь используется Service Worker. Ты знаешь что это за зверь? Даже я еще с этим на Вы. Вот небольшая выдержка из одной публикации:
    Для тех, кто вообще не в курсе о чем речь, то очень вкратце — service worker это скрипт, который выполняется браузером в фоне, отдельно от веб-страницы и способен выполнять функции для которых не требуется взаимодействие со страницей или пользователем.

    На практике Service Worker API позволяет делать такую магическую вещь, как кеширование файлов онлайн веб-приложения на локальное устройство пользователя и затем работать полностью в оффлайне, если нужно.

    В будущем планируется добавить такие классные вещи как синхронизация кеша в фоне, то есть даже если пользователь не находится сейчас на вашем сайте, сервис-воркер все равно сможет запуститься и скачать обновления например. А также доступ к PushApi из фона опять же (то есть при получении обновления отправить вам пуш-уведомление).

    Service worker устанавливается, активируется и начинает в фоне что-то делать. Например “слушать” события ‘fetch’ и при необходимости их изменять или отменять совсем
    Звучит интригующе, не правда ли? Хотелось бы, чтобы с фронта шел запрос на какой-нибудь MODX-процессор и запрос «немного изменился в фоне»? Например.

    Этот зверь вообще дикий. Вот смотри какой ответ от сервера приходит:


    То есть документ (обрати внимание, не JS, не CSS, а именно HTML-документ) взят даже не из кеша, а из какого-то там ServiceWorker.

    А вот смотри как одна и да же страница в исходниках выглядит в обычной вкладке и приватной (в приватной просто воркер еще не зарегистрирован).


    И это даже на тех страницах, на которые я ранее не заходил.

    Как тебе такая магия? Уверен, что хочешь себе на страничке что-то подобное регистрировать?