diff roundup/rest.py @ 5726:e199d0ae4a25

issue2551033: prevent reverse engineering hidden data by using etags as an oracle to identify when the right data has been guessed. Identified by Joseph Myers who also suggested remediation methods. Implemented John Rouillard.
author John Rouillard <rouilj@ieee.org>
date Thu, 23 May 2019 18:56:57 -0400
parents d9a3f6957731
children 8b5171f353eb
line wrap: on
line diff
--- a/roundup/rest.py	Wed May 22 20:56:59 2019 -0400
+++ b/roundup/rest.py	Thu May 23 18:56:57 2019 -0400
@@ -37,7 +37,7 @@
 from roundup.exceptions import *
 from roundup.cgi.exceptions import *
 
-from hashlib import md5
+import hmac
 
 # Py3 compatible basestring
 try:
@@ -118,7 +118,7 @@
         return result
     return format_object
 
-def calculate_etag (node, classname="Missing", id="0"):
+def calculate_etag (node, key, classname="Missing", id="0"):
     '''given a hyperdb node generate a hashed representation of it to be
     used as an etag.
 
@@ -142,13 +142,13 @@
     '''
 
     items = node.items(protected=True) # include every item
-    etag = md5(bs2b(repr(sorted(items)))).hexdigest()
+    etag = hmac.new(bs2b(repr(sorted(items)))).hexdigest()
     logger.debug("object=%s%s; tag=%s; repr=%s", classname, id,
                  etag, repr(node.items(protected=True)))
     # Quotes are part of ETag spec, normal headers don't have quotes
     return '"%s"' % etag
 
-def check_etag (node, etags, classname="Missing", id="0"):
+def check_etag (node, key, etags, classname="Missing", id="0"):
     '''Take a list of etags and compare to the etag for the given node.
 
     Iterate over all supplied etags,
@@ -159,7 +159,7 @@
     '''
     have_etag_match=False
 
-    node_etag = calculate_etag(node, classname, id)
+    node_etag = calculate_etag(node, key, classname, id)
 
     for etag in etags:
         if etag is not None:
@@ -511,6 +511,7 @@
     def raise_if_no_etag(self, class_name, item_id, input):
         class_obj = self.db.getclass(class_name)
         if not check_etag(class_obj.getnode(item_id),
+                self.db.config.WEB_SECRET_KEY,
                 obtain_etags(self.client.request.headers, input),
                 class_name,
                 item_id):
@@ -787,7 +788,8 @@
             )
 
         node = class_obj.getnode(itemid)
-        etag = calculate_etag(node, class_name, itemid)
+        etag = calculate_etag(node, self.db.config.WEB_SECRET_KEY,
+                              class_name, itemid)
         props = None
         protected=False
         verbose=1
@@ -868,7 +870,8 @@
 
         class_obj = self.db.getclass(class_name)
         node = class_obj.getnode(item_id)
-        etag = calculate_etag(node, class_name, item_id)
+        etag = calculate_etag(node, self.db.config.WEB_SECRET_KEY,
+                              class_name, item_id)
         data = node.__getattr__(attr_name)
         result = {
             'id': item_id,

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