From b5b00e3a36e6fb34dc6d21330db42dee3078df19 Mon Sep 17 00:00:00 2001 From: Tim Abbott Date: Sat, 13 Aug 2016 19:16:39 -0700 Subject: [PATCH] subdomains: Enforce subdomain checks on every API endpoint. This ensures that everything is using the correct subdomain for requests. While it probably wouldn't be a real security problem for the wrong subdomain to work, this enforcement is essential to catching bugs in the product and users' API scripts. --- zerver/decorator.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/zerver/decorator.py b/zerver/decorator.py index 5b9b06205b..12e7e5e6fe 100644 --- a/zerver/decorator.py +++ b/zerver/decorator.py @@ -189,6 +189,15 @@ def validate_api_key(request, role, api_key, is_webhook=False): except AttributeError: # Deployment objects don't have realms pass + if (not check_subdomain(get_subdomain(request), profile.realm.subdomain) + # Allow access to localhost for Tornado + and not (settings.RUNNING_INSIDE_TORNADO and + request.META["SERVER_NAME"] == "127.0.0.1" and + request.META["REMOTE_ADDR"] == "127.0.0.1")): + logging.warning("User %s attempted to access API on wrong subdomain %s" % ( + profile.email, get_subdomain(request))) + raise JsonableError(_("Account is not associated with this subdomain")) + return profile # Use this for webhook views that don't get an email passed in. @@ -212,6 +221,10 @@ def api_key_only_webhook_view(client_name): raise JsonableError(_("Account not active")) if user_profile.realm.deactivated: raise JsonableError(_("Realm for account has been deactivated")) + if not check_subdomain(get_subdomain(request), user_profile.realm.subdomain): + logging.warning("User %s attempted to access webhook API on wrong subdomain %s" % ( + user_profile.email, get_subdomain(request))) + raise JsonableError(_("Account is not associated with this subdomain")) request.user = user_profile request._email = user_profile.email @@ -422,6 +435,15 @@ def authenticate_log_and_execute_json(request, view_func, *args, **kwargs): raise JsonableError(_("Realm for account has been deactivated")) if user_profile.is_incoming_webhook: raise JsonableError(_("Webhook bots can only access webhooks")) + if (not check_subdomain(get_subdomain(request), user_profile.realm.subdomain) and + # Exclude the SOCKET requests from this filter; they were + # checked when the original websocket request reached Tornado + not (request.method == "SOCKET" and + request.META['SERVER_NAME'] == "127.0.0.1")): + logging.warning("User %s attempted to access JSON API on wrong subdomain %s" % ( + user_profile.email, get_subdomain(request))) + raise JsonableError(_("Account is not associated with this subdomain")) + process_client(request, user_profile, True) request._email = user_profile.email return view_func(request, user_profile, *args, **kwargs)