From 785fc87f38b4811bc4ce43a0a9b2267ee7d500b4 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Thu, 1 Oct 2015 13:30:13 +0200 Subject: etcdstore: prevent path traversal attacks A new internal method _absolute_key() is used to join key name and name space. etcd treats the key space like a file system so the method checks the key for '//', '.', and '..' to prevent invalid paths and path traversal attacks. Signed-off-by: Christian Heimes Signed-off-by: Simo Sorce --- custodia/store/etcdstore.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/custodia/store/etcdstore.py b/custodia/store/etcdstore.py index 9a9e535..f7e55f4 100644 --- a/custodia/store/etcdstore.py +++ b/custodia/store/etcdstore.py @@ -2,7 +2,6 @@ from __future__ import print_function -import os import sys import etcd @@ -33,16 +32,25 @@ class EtcdStore(CSStore): repr(err))) raise CSStoreError('Error occurred while trying to init db') + def _absolute_key(self, key): + """Get absolute path to key and validate key""" + if '//' in key: + raise ValueError("Invalid empty components in key '%s'" % key) + parts = key.split('/') + if set(parts).intersection({'.', '..'}): + raise ValueError("Invalid relative components in key '%s'" % key) + return '/'.join([self.namespace] + parts).replace('//', '/') + def get(self, key): try: - result = self.etcd.get(os.path.join(self.namespace, key)) + result = self.etcd.get(self._absolute_key(key)) except etcd.EtcdException as err: log_error("Error fetching key %s: [%r]" % (key, repr(err))) raise CSStoreError('Error occurred while trying to get key') return result.value def set(self, key, value, replace=False): - path = os.path.join(self.namespace, key) + path = self._absolute_key(key) try: self.etcd.write(path, value, prevExist=replace) except etcd.EtcdAlreadyExist as err: @@ -52,7 +60,7 @@ class EtcdStore(CSStore): raise CSStoreError('Error occurred while trying to store key') def span(self, key): - path = os.path.join(self.namespace, key) + path = self._absolute_key(key) try: self.etcd.write(path, None, dir=True, prevExist=False) except etcd.EtcdAlreadyExist as err: @@ -62,7 +70,7 @@ class EtcdStore(CSStore): raise CSStoreError('Error occurred while trying to store key') def list(self, keyfilter='/'): - path = os.path.join(self.namespace, keyfilter) + path = self._absolute_key(keyfilter) if path != '/': path = path.rstrip('/') try: @@ -85,7 +93,7 @@ class EtcdStore(CSStore): def cut(self, key): try: - self.etcd.delete(os.path.join(self.namespace, key)) + self.etcd.delete(self._absolute_key(key)) except etcd.EtcdKeyNotFound: return False except etcd.EtcdException as err: -- cgit