Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Limit simultaneously logged on user devices count

Tags:

java

security

php

Question.

How do sites, for example Netflix, implement features such as "only 2 devices is allowed to log on at the same time"?

My understanding.

User table in the database would have a "logon_count" column. Session table records session id, username, last action and so on.

multiple layers of checks to match session cookie or logon count or clean out idled session will be performed based on what user can provide upon access the URL.

But.

Say a user wants to beat the validation mechanism. Login as normal, somehow record the valid cookie and distribute/replicate it on multiple devices. Free Netflix for everyone.

When source ip is not reliable and HTTP headers can be forged, how can the server side code tell whether each session is from a unique device and thus enforce the concurrent logon restriction?

Cheers, Ralph

like image 635
Ralf Zhang Avatar asked Sep 23 '16 02:09

Ralf Zhang


Video Answer


1 Answers

Regardless of how Netflix implements this solution, let's consider the general solution to such a problem more abstractly.

First, you need to be able to separate between what you call a session, which is primarily just used to retain user-application state, and the mechanism that authenticates the user when they are playing a video. Of course, if the server just correlates the session cookie that's supplied by the client directly to a device this entire solution falls apart, because as you deduced we could just easily copy the cookie to another client.

There are two requirements to solve this problem in a more general way.

  1. When a video is being played the server must have a way to authenticate the client
  2. The authentication mechanism must not be re-usable by any other client

Logging into Netflix itself is moot, because that's an application state. It's an entirely different problem to solve. You already know how to solve that problem, clearly. The authentication of the user when they actually request to play a video is the other problem you're asking about.

This requires something that cannot be reusable by multiple clients, as such it could be implemented as a nonce. This is a cryptographic token that can only be used once.

Imagine the user downloads the video in chunks (30 second buffers). With each request to the server to download one chunk of the video, the server expects a token from the client (this is the nonce that cannot be re-used), and verifies it on the server-side. If it checks out, it sends the client back the chunk of video along with a new token. This can continue to happen throughout the duration of the video. Such that if another client were to copy this token and attempt sending it to the server, the server will not accept any future requests with that same token and in theory this prevents multiple devices from accessing multiple videos (from the same account) at the same time.

A practical, but contrived example

To demonstrate, let's imagine the user logs into your application like so.

session_start();
if ($user->authenticate($username, $passwrod)) {
    $_SESSION['user_id'] = $user->id;
}

This gives your application a way to retain the client's state between HTTP requests, which is fine. However, when the user asks to play a video, something else must happen to generate the nonce.

$nonce = base64_encode(random_bytes(128));
$_SESSION["nonce"][$nonce] = false;
echo json_encode(["buffer" => $videoBufferData, "token" => $nonce]);

Let's just imagine for a second, that this code sends some API response that provides the user with the 30 second video buffer as a payload and the token in a JSON response. When the user requests the next 30 second buffer, it must match the token stored in the session.

if (empty($_SESSION["nonce"][$_POST["token"]])) {
    $_SESSION["nonce"][$_POST["token"]] = true; // invalidate the current nonce
    // generate a new nonce
    $nonce = base64_encode(random_bytes(128));
    $_SESSION["nonce"][$nonce] = false;
}

Now each time we accept a nonce that hasn't yet been used, we also generate a new nonce for the next play load. Even if the user copies the session cookie to another client, they will never be able to play videos concurrently this way. Because once one device uses a token, the other device with the same session still cannot re-use that same token on the next request and it wouldn't be able to receive the new token for continuing to play the video. So they will impede upon one another.

like image 111
Sherif Avatar answered Oct 24 '22 15:10

Sherif