Ok, so I am developing a Laravel 5.5 app that needs to interface with an existing phpBB forum. Specifically, if you log into the phpBB forum, you must also be logged into the Laravel app. Otherwise, users will have to log into both separately, and I feel that would be terrible user experience for my site. The forums exist already and have a database of users as well as extensive functionality for user creation, logging in, administration, roles & permissions, etc, so rather than build all that, I’d like phpBB to handle most of the heavy lifting.
That’s why I implemented this hacky custom session handler in Laravel (which works):
class PhpbbSessionHandler implements SessionHandlerInterface { private function getPhpbbSessionId() { $ key = config('session.phpbb_cookie'); return isset($ _COOKIE[$ key]) ? $ _COOKIE[$ key] : null; } protected function getLaravelSessionQuery($ id) { return DB::table( config('session.table') )->where('laravel_session_id', $ id); } protected function getBBSessionQuery() { return DB::table( config('session.table') ) ->where( 'session_id', $ this->getPhpbbSessionId() ) ->where( 'session_user_id', '!=', config('session.phpbb_anonymous') ); } // Needed for interface public function open($ savePath, $ sessionName) {} public function close() {} /** * Look for existing session in Laravel, then phpBB */ public function read($ sessionId) { $ session = $ this->getLaravelSessionQuery($ sessionId)->first(); if($ session) { // We are logged in, set the authenticated user $ user = User::find($ session->session_user_id); Auth::setUser($ user); return ($ session->payload) ? base64_decode($ session->payload) : null; } else { // The forum is logged in, but Laravel is not. Let's log them in. $ bb_user_id = $ this->getBBSessionQuery()->value('session_user_id'); if($ bb_user_id) { Auth::loginUsingId($ bb_user_id); } return; } } /** * Update session data */ public function write($ sessionId, $ data) { $ update['payload'] = base64_encode($ data); if( $ this->getLaravelSessionQuery($ sessionId)->exists() ) { return $ this->getLaravelSessionQuery($ sessionId)->update($ update); } else { $ update['laravel_session_id'] = $ sessionId; return $ this->getBBSessionQuery()->update($ update); } } public function destroy($ sessionId) { return $ this->getLaravelSessionQuery($ sessionId)->delete(); } /** * Clear out expired session records */ public function gc($ lifetime) { return DB::table( config('session.table') )->where('session_time', '<', $ lifetime)->delete(); } }
The part I’d really like feedback on is the read
method. It definitely is vulnerable to session hijacking, but without messing around deep in the lowest levels of phpBB source code, or implementing encryption that both apps can handle exactly the same, I’m not sure what to do. This is already deeper into Laravel than I usually go, so any constructive feedback would be appreciated.