Concurrent sessions - PHP

Concurrent sessions - PHP

Need

Enforce session management and limit concurrent user sessions

Context

  • Usage of PHP 7.0 for server-side scripting and web development
  • Usage of Request for making HTTP requests
  • Usage of Auth for user authentication and authorization

Description

Non compliant code

        public function login(Request $request)
{
    $credentials = $request->only('email', 'password');

    if (Auth::attempt($credentials)) {
        // Authentication passed...
        return redirect()->intended('dashboard');
    }
}
        
        

The above code is a typical Laravel authentication function. It takes a Request object as an input, which contains the user's login credentials, and then attempts to authenticate the user with these credentials using Laravel's Auth::attempt method.

The vulnerability in this code lies in the fact that it does not limit the number of active sessions a user can have at any given time. This means that a user can log in multiple times from different locations without any restrictions or notifications.

The Auth::attempt method simply checks if the provided credentials are valid, and if they are, it logs the user in and redirects them to the dashboard. It does not check if the user is already logged in elsewhere, nor does it notify the user if a new session is initiated from a different location.

This can lead to potential security risks, such as session hijacking or unauthorized access, as a malicious user could potentially use the same credentials to log in from a different location without the legitimate user's knowledge.

Steps

  • Implement a mechanism to track the number of active sessions per user. This could be done by storing session information in a database or in-memory data structure.
  • During the login process, check if the user already has an active session. If so, decide on the policy to follow: either deny the new login attempt or invalidate the previous session.
  • If the policy is to deny the new login attempt, return an error message to the user indicating that they are already logged in from another location.
  • If the policy is to invalidate the previous session, ensure that the previous session is properly terminated before allowing the new login attempt.
  • Implement a notification system to alert the user when a new session is initiated from a different location. This could be done via email or an in-app notification.

Compliant code

        public function login(Request $request)
{
    $credentials = $request->only('email', 'password');

    if (Auth::attempt($credentials)) {
        // Check if the user already has an active session
        $activeSessions = Session::where('user_id', Auth::user()->id)->get();

        if(count($activeSessions) > 0){
            // If the user has an active session, invalidate the previous session
            foreach($activeSessions as $session){
                $session->delete();
            }
            // Notify the user about the new session
            $user = Auth::user();
            Mail::to($user->email)->send(new NewSessionNotification($user));
        }

        // Create a new session record
        $newSession = new Session();
        $newSession->user_id = Auth::user()->id;
        $newSession->save();

        // Authentication passed...
        return redirect()->intended('dashboard');
    }
}
        
        

The updated code now includes a mechanism to track the number of active sessions per user. This is done by querying the Session model for any active sessions associated with the user's ID. If any active sessions are found, they are invalidated by deleting them from the database.

After invalidating any previous sessions, the code sends a notification to the user to inform them that a new session has been initiated. This is done using Laravel's built-in Mail facade to send an email to the user. The NewSessionNotification mail class should be created to format the email.

Finally, a new session record is created and saved to the database. This record is associated with the user's ID, allowing it to be queried in future login attempts.

This approach ensures that each user can only have one active session at a time, and that they are notified whenever a new session is initiated. This helps to prevent unauthorized access and provides the user with more control over their account security.

References