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!

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.

Where Next?

Popular in Questions Top

New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
earth10
Hi, I’m just starting to build a side-project with Elixir and Phoenix and doing some basic test with Elixir alone. What strikes me is th...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29377 241
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39297 209
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement