PHP + socket.io(сеанс, авторизация и проблемы с безопасностью)

У меня есть рабочее приложение php, в котором я хочу добавить поддержку в режиме реального времени. Я хотел бы использовать nodejs/socket.io, чтобы добавить такую ​​функциональность.

Первая проблема, которую я обнаружил, - это то, как правильно разрешить пользователю на стороне nodejs (пользователь уже аутентифицирован на php-сервере через сеанс PHP). Используя socket.handshake.header.cookie на стороне nodejs, я могу проанализировать и получить идентификатор сеанса PHP, с которым я могу пройти аутентификацию через redis/memcache/database (в зависимости от того, что я использовал для сохранения информации о сеансе).
Все выглядит здорово, когда пользователь открывает только одну вкладку/окно сайта - при наличии большего количества и использования session_regenerate_id(), в nodejs пользователь аутентифицируется с помощью другого ключа sessionid, поэтому я не могу различить две вкладки ничем иным, кроме идентификатора сокета, с которым они связаны. Когда пользователь выходит из системы, он не должен получать какие-либо сообщения на какой-либо вкладке (потому что он уже вышел из каждой вкладки/окна из этого браузера). Поэтому при выводе сообщения (отправленного из браузера непосредственно перед выходом из PHP файлов) я должен удалить все соединения сокетов, подключенные к авторизованному идентификатору пользователя. Но что делать, если пользователь входит в систему на двух устройствах (например, браузер pc и ipad safaris). После выхода на одно устройство он не должен получать сообщения на устройстве, которое он выходил, а не на каждом устройстве. Как я могу отличить соединения от разных устройств/браузеров в socket.io? Конечно, использование здесь session_regenerate_id() было бы эффективным, но что я могу сделать, если я действительно хочу использовать эту функцию?

Еще одна проблема, которую я имею, - это проблема безопасности (или даже вопрос). Предположим, что авторизованный пользователь в приложении может видеть страницу example.com/user1 (которая является новостной лентой для пользователя1) и не может видеть example.com/user2 (fe. He не имеет прав на это). Я хочу, чтобы socket.io отправлял сообщения об обновлениях в браузер, когда пользователь находится на example.com/user1, и, конечно же, не отправлять, когда пользователь находится на example.com/user2 сайт. На стороне socket.io я могу прочитать адрес рефератора (поэтому, предположительно, когда пользователь находится на сайте user2, он не получает никакого соединения socket.io). Возникает вопрос: следует ли сравнивать адрес реферата с правами аутентифицированного пользователя на стороне node.js? Или, может быть, значение реферера безопасно на стороне node.js? Добавление другой проверки db на стороне node.js замедлит ее работу (потому что почти каждый запрос должен иметь такую ​​же проверку базы данных с двух сторон - PHP и node.js).

Или, может быть, вся концепция приложения socket.io + PHP, работающего так, как я представил, ошибочна?

UPDATE

Я думаю, что нашел способ опустить проблемы с первым вопросом - в основном я просто добавляю еще один cookie (кроме PHPSESSID) fe. с именем NODESESSID, который я генерирую (например, с помощью uniqid()), когда пользователь авторизован. Теперь авторизация на стороне node.js сравнивает PHPSESSID и NODESESSID (оба должны совпадать). Теперь, когда пользователь выходит из системы, он отправляет сообщение в socket.io и socket.io отключает все сокеты с помощью NODESESSID. Это похоже на использование преимуществ восстановления идентификатора сеанса и не восстановления идентификатора сеанса (но не уязвим для фиксации сеанса, не так ли?).

Ответ 1

Для ваших вторых вопросов:

Референт не защищен, как указано в комментариях.

У меня есть аналогичная проблема в моем приложении, и вот как это работает для меня.

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

in nodejs onConnect Я запрашиваю бэкэнд, если пользователь аутентифицирован, а затем сохранит идентификатор пользователя в объекте сокета (socket.data), а также запустил хэш-карту для поиска сокетов непосредственно из пользовательских элементов.

второй, я использую Redis и подписываюсь на redis-список из nodejs (см. redis pub/sub). php backend посылает сообщения в этом списке с идентификатором пользователя, чтобы адресовать сообщение. nodejs принимает это сообщение (например, новый элемент новостей), просматривает идентификатор пользователя в указанном хэш файле и отправляет его клиенту. поэтому пользователь получает только то, за что ему разрешено. клиент затем решает, что делать с сообщением. если пользователь находится на странице своего канала, он может добавить элемент. если пользователь находится на каком-то элементе elses, он может просто добавить уведомление в другое место на странице. он также может отказаться от него.

на веб-сайте php, эти сообщения отправляются на redis каждый раз, когда происходит событие, которое должно отображаться в реальном времени на каком-то подключенном клиенте. если пользователь1 размещает в канале user2, новый элемент хранится в базе данных и в то же время отправляется как сообщение в очередь redis.

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

Ответ 2

На самом деле вы можете избежать использования node.js и использовать phpdaemon, его написать с php и работать очень хорошо.