diff roundup/cgi/client.py @ 7155:89a59e46b3af

improve REST interface security When using REST, we reflect the client's origin. If the wildcard '*' is used in allowed_api_origins all origins are allowed. When this is done, it also added an 'Access-Control-Allow-Credentials: true' header. This Credentials header should not be added if the site is matched only by '*'. This header should be provided only for explicit origins (e.g. https://example.org) not for the wildcard. This is now fixed for CORS preflight OPTIONS request as well as normal GET, PUT, DELETE, POST, PATCH and OPTIONS requests. A missing Access-Control-Allow-Credentials will prevent the tracker from being accessed using credentials. This prevents an unauthorized third party web site from using a user's credentials to access information in the tracker that is not publicly available. Added test for this specific case. In addition, allowed_api_origins can include explicit origins in addition to '*'. '*' must be first in the list. Also adapted numerous tests to work with these changes. Doc updates.
author John Rouillard <rouilj@ieee.org>
date Thu, 23 Feb 2023 12:01:33 -0500
parents 1181157d7cec
children 765222ef4cec
line wrap: on
line diff
--- a/roundup/cgi/client.py	Tue Feb 21 23:06:15 2023 -0500
+++ b/roundup/cgi/client.py	Thu Feb 23 12:01:33 2023 -0500
@@ -1279,15 +1279,20 @@
                 raise Unauthorised(self._("Anonymous users are not "
                                           "allowed to use the web interface"))
 
-    def is_origin_header_ok(self, api=False):
+    def is_origin_header_ok(self, api=False, credentials=False):
         """Determine if origin is valid for the context
 
-           Allow (return True) if ORIGIN is missing and it is a GET.
-           Allow if ORIGIN matches the base url.
+           Header is ok (return True) if ORIGIN is missing and it is a GET.
+           Header is ok if ORIGIN matches the base url.
            If this is a API call:
-             Allow if ORIGIN matches an element of allowed_api_origins.
-             Allow if allowed_api_origins includes '*' as first element..
-           Otherwise disallow.
+             Header is ok if ORIGIN matches an element of allowed_api_origins.
+             Header is ok if allowed_api_origins includes '*' as first
+               element and credentials is False.
+           Otherwise header is not ok.
+
+           In a credentials context, if we match * we will return
+           header is not ok. All credentialed requests must be
+           explicitly matched.
         """
 
         try:
@@ -1312,9 +1317,15 @@
         # Original spec says origin is case sensitive match.
         # Living spec doesn't address Origin value's case or
         # how to compare it. So implement case sensitive....
-        if allowed_origins:
-            if allowed_origins[0] == '*' or origin in allowed_origins:
-                return True
+        if origin in allowed_origins:
+             return True
+        # Block use of * when origin match is used for
+        # allowing credentials. See:
+        # https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
+        # under Credentials Requests and Wildcards
+        if ( allowed_origins and allowed_origins[0] == '*'
+             and not credentials):
+            return True
 
         return False
 

Roundup Issue Tracker: http://roundup-tracker.org/