ASCrookes

ASCrookes

Phoenix Limit Sockets per user

Hello,

I have recently been working with Phoenix Channels. The whole process has been incredibly straightforward so far! The one thing I have not been able to find has been the security implications when using Channels/Sockets.

I would imagine in a production app with authentication one would want to limit both the number of sockets a single user can have open at once and the number of channels connected.

Currently we limit the number of sessions already so we could tie each user socket’s id to the access token and force disconnect when a session is closed, but that still wouldn’t stop a user from opening multiple sockets per active session.

If anyone can point me in the right direction or if my thinking is wrong about security here let me know!

First Post!

wmnnd

wmnnd

I think there are two pretty straightforward ways for doing this:

1: Use Phoenix.Presence. This will allow you to automatically track how often a specific user is currently connected and limit those numbers accordingly.
2: Store a per-user counter in your database or create your own OTP application for holding this kind of state (e. g. using GenServer).

Most Liked

chrismccord

chrismccord

Creator of Phoenix

You can intercept presence_diff in your channel and drop the message:

intercept ["presence_diff"]

def handle_out("presence_diff", _, socket), do: {:noreply, socket}
chrismccord

chrismccord

Creator of Phoenix

You can rewrite the topic yourself fwiw by intercepting, which is probably exactly what you’re doing :slight_smile: It’s not something I’m likely to support in Presence because we would have to track the event per subscriber which would add complexity.

Mazyod

Mazyod

Great question, and I’ve recently when through the exercise myself.

First, you have to understand that blocking multiple sockets at the user_socket level is nasty, since all you can do is return :error. The client socket then gets terminated, and has no clue if it is was an authorization error or multiple sockets error, or even perhaps some other logic you have to block the connection (in my case, client update required!).

With that being said, you might not care about returning the exact error to the user, or maybe you do:

  1. If you do: You need to allow the user to connect to a socket, and then make it obligatory that all active users connect to some global channel (in my case it is global:[USER_ID]). Once you accept the socket, and the user attempts to join this global channel, it becomes trivial to detect multiple sockets using Presence, :global.where_is, or Elixir v1.4 pid Registry.
    I personally tried presence, but it ends up adding extra baggage like pushing presence state down to the client, which I don’t want. I was using :global.where_is because I am still stuck at Elixir v1.3, but it worked fine.

  2. If you don’t: Just use :global.where_is or Registry to register the user socket under their user id, then check if a process exists when another socket connection comes in.


I’ll tell you this though, at the end, I scrapped it. The reason I wanted it in the first place was because a user would end up in a game room with themselves (given they connect on two different sockets). The best solution I found and implemented was to add the checks in the room channel and game channel level not at the socket level. If the user wants to connect on multiple devices, sure why not! The real problem is elsewhere and should be solved on a different level.

Last Post!

ASCrookes

ASCrookes

Hm thats a great insight re: blocking at the socket level.
For now I’m going to add limits to the number of channels that can be joined.

Thanks for the feedback!

Where Next?

Popular in Questions Top

JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New

Other popular topics Top

electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 49266 226
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New

We're in Beta

About us Mission Statement