comparison 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
comparison
equal deleted inserted replaced
7154:f614176903d0 7155:89a59e46b3af
1277 if self.user == 'anonymous': 1277 if self.user == 'anonymous':
1278 if not self.db.security.hasPermission('Web Access', self.userid): 1278 if not self.db.security.hasPermission('Web Access', self.userid):
1279 raise Unauthorised(self._("Anonymous users are not " 1279 raise Unauthorised(self._("Anonymous users are not "
1280 "allowed to use the web interface")) 1280 "allowed to use the web interface"))
1281 1281
1282 def is_origin_header_ok(self, api=False): 1282 def is_origin_header_ok(self, api=False, credentials=False):
1283 """Determine if origin is valid for the context 1283 """Determine if origin is valid for the context
1284 1284
1285 Allow (return True) if ORIGIN is missing and it is a GET. 1285 Header is ok (return True) if ORIGIN is missing and it is a GET.
1286 Allow if ORIGIN matches the base url. 1286 Header is ok if ORIGIN matches the base url.
1287 If this is a API call: 1287 If this is a API call:
1288 Allow if ORIGIN matches an element of allowed_api_origins. 1288 Header is ok if ORIGIN matches an element of allowed_api_origins.
1289 Allow if allowed_api_origins includes '*' as first element.. 1289 Header is ok if allowed_api_origins includes '*' as first
1290 Otherwise disallow. 1290 element and credentials is False.
1291 Otherwise header is not ok.
1292
1293 In a credentials context, if we match * we will return
1294 header is not ok. All credentialed requests must be
1295 explicitly matched.
1291 """ 1296 """
1292 1297
1293 try: 1298 try:
1294 origin = self.env['HTTP_ORIGIN'] 1299 origin = self.env['HTTP_ORIGIN']
1295 except KeyError: 1300 except KeyError:
1310 allowed_origins = self.db.config['WEB_ALLOWED_API_ORIGINS'] 1315 allowed_origins = self.db.config['WEB_ALLOWED_API_ORIGINS']
1311 # find a match for other possible origins 1316 # find a match for other possible origins
1312 # Original spec says origin is case sensitive match. 1317 # Original spec says origin is case sensitive match.
1313 # Living spec doesn't address Origin value's case or 1318 # Living spec doesn't address Origin value's case or
1314 # how to compare it. So implement case sensitive.... 1319 # how to compare it. So implement case sensitive....
1315 if allowed_origins: 1320 if origin in allowed_origins:
1316 if allowed_origins[0] == '*' or origin in allowed_origins: 1321 return True
1317 return True 1322 # Block use of * when origin match is used for
1323 # allowing credentials. See:
1324 # https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
1325 # under Credentials Requests and Wildcards
1326 if ( allowed_origins and allowed_origins[0] == '*'
1327 and not credentials):
1328 return True
1318 1329
1319 return False 1330 return False
1320 1331
1321 def is_referer_header_ok(self, api=False): 1332 def is_referer_header_ok(self, api=False):
1322 referer = self.env['HTTP_REFERER'] 1333 referer = self.env['HTTP_REFERER']

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