# HG changeset patch # User Goffi # Date 1708691724 -3600 # Node ID 86c7a3a625d526f1ed3b4bc43e3790f677758891 # Parent c1c1d68d063e760243aed771a0559baf51df0bf7 server: always start a new session on connection: The session was kept when a user was connecting from service profile (but not from other profiles), this was leading to session fixation vulnerability (an attacker on the same machine could get service profile session cookie, and use it when a victim would log-in). This patch fixes it by always starting a new session on connection. fix 443 diff -r c1c1d68d063e -r 86c7a3a625d5 libervia/web/server/server.py --- a/libervia/web/server/server.py Sun Feb 11 21:32:53 2024 +0100 +++ b/libervia/web/server/server.py Fri Feb 23 13:35:24 2024 +0100 @@ -831,8 +831,7 @@ state = C.PROFILE_LOGGED_EXT_JID if register_with_ext_jid else C.PROFILE_LOGGED return state - @defer.inlineCallbacks - def connect(self, request, login, password): + async def connect(self, request, login, password): """log user in If an other user was already logged, it will be unlogged first @@ -854,7 +853,6 @@ @raise ValueError(C.PROFILE_AUTH_ERROR): invalid login and/or password @raise ValueError(C.XMPP_AUTH_ERROR): invalid XMPP account password """ - # XXX: all security checks must be done here, even if present in javascript if login.startswith("@"): raise failure.Failure(exceptions.DataError("No profile_key allowed")) @@ -872,7 +870,7 @@ raise failure.Failure(exceptions.DataError("No profile_key allowed")) # FIXME: should it be cached? - new_account_domain = yield self.bridge_call("account_domain_new_get") + new_account_domain = await self.bridge_call("account_domain_new_get") if login_jid.host == new_account_domain: # redirect "user@libervia.org" to the "user" profile @@ -882,7 +880,7 @@ login_jid = None try: - profile = yield self.bridge_call("profile_name_get", login) + profile = await self.bridge_call("profile_name_get", login) except Exception: # XXX: ProfileUnknownError wouldn't work, it's encapsulated # FIXME: find a better way to handle bridge errors if ( @@ -914,17 +912,19 @@ connect_method = "connect" - # we check if there is not already an active session + # we check the active session web_session = session_iface.IWebSession(request.getSession()) - if web_session.profile: - # yes, there is - if web_session.profile != profile: - # it's a different profile, we need to disconnect it + if web_session.profile != profile: + # It's a different profile, we need to disconnect it. + # We always purge session even if no user was logged, to avoid the re-use of + # cookie (i.e. to avoid session fixation). + if web_session.profile: + # no need to log a warning if the previous profile was the service profile log.warning(_( "{new_profile} requested login, but {old_profile} was already " "connected, disconnecting {old_profile}").format( old_profile=web_session.profile, new_profile=profile)) - self.purge_session(request) + self.purge_session(request) if self.waiting_profiles.get_request(profile): #  FIXME: check if and when this can happen @@ -932,7 +932,7 @@ self.waiting_profiles.set_request(request, profile, register_with_ext_jid) try: - connected = yield self.bridge_call(connect_method, profile, password) + connected = await self.bridge_call(connect_method, profile, password) except Exception as failure_: fault = getattr(failure_, 'classname', None) self.waiting_profiles.purge_request(profile) @@ -971,7 +971,7 @@ "profile [{profile}], this should not happen!") .format(session_profile=web_session.profile, profile=profile)) raise exceptions.InternalError("profile mismatch") - defer.returnValue(C.SESSION_ACTIVE) + return C.SESSION_ACTIVE log.info( _( "profile {profile} was already connected in backend".format( @@ -981,8 +981,8 @@ ) #  no, we have to create it - state = yield defer.ensureDeferred(self._logged(profile, request)) - defer.returnValue(state) + state = await self._logged(profile, request) + return state async def check_registration_id(self, request: server.Request) -> None: """Check if a valid registration ID is found in request data diff -r c1c1d68d063e -r 86c7a3a625d5 libervia/web/server/session_iface.py --- a/libervia/web/server/session_iface.py Sun Feb 11 21:32:53 2024 +0100 +++ b/libervia/web/server/session_iface.py Fri Feb 23 13:35:24 2024 +0100 @@ -38,7 +38,7 @@ class IWebSession(Interface): - profile = Attribute("Sat profile") + profile = Attribute("Libervia profile") jid = Attribute("JID associated with the profile") uuid = Attribute("uuid associated with the profile session") identities = Attribute("Identities of XMPP entities")