diff --git a/Check-the-HTTP-Referer-header-on-all-requests.patch b/Check-the-HTTP-Referer-header-on-all-requests.patch new file mode 100644 index 0000000000000000000000000000000000000000..9d051cd2f9c1afa8e27dc1f973fb670f5da1f93f --- /dev/null +++ b/Check-the-HTTP-Referer-header-on-all-requests.patch @@ -0,0 +1,119 @@ +From 9b1a65fe3936c4d3fe237775e54f0249b740f23e Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Jan 10 2024 09:30:38 +0000 +Subject: Check the HTTP Referer header on all requests + + +The referer was only checked in WSGIExecutioner classes: + + - jsonserver + - KerberosWSGIExecutioner + - xmlserver + - jsonserver_kerb + +This left /i18n_messages, /session/login_kerberos, +/session/login_x509, /session/login_password, +/session/change_password and /session/sync_token unprotected +against CSRF attacks. + +CVE-2023-5455 + +Signed-off-by: Rob Crittenden + +--- + +diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py +index 4e8a08b..3555014 100644 +--- a/ipaserver/rpcserver.py ++++ b/ipaserver/rpcserver.py +@@ -156,6 +156,19 @@ _success_template = """ + """ + + class HTTP_Status(plugable.Plugin): ++ def check_referer(self, environ): ++ if "HTTP_REFERER" not in environ: ++ logger.error("Rejecting request with missing Referer") ++ return False ++ if (not environ["HTTP_REFERER"].startswith( ++ "https://%s/ipa" % self.api.env.host) ++ and not self.env.in_tree): ++ logger.error("Rejecting request with bad Referer %s", ++ environ["HTTP_REFERER"]) ++ return False ++ logger.debug("Valid Referer %s", environ["HTTP_REFERER"]) ++ return True ++ + def not_found(self, environ, start_response, url, message): + """ + Return a 404 Not Found error. +@@ -331,9 +344,6 @@ class wsgi_dispatch(Executioner, HTTP_Status): + self.__apps[key] = app + + +- +- +- + class WSGIExecutioner(Executioner): + """ + Base class for execution backends with a WSGI application interface. +@@ -897,6 +907,9 @@ class jsonserver_session(jsonserver, KerberosSession): + + logger.debug('WSGI jsonserver_session.__call__:') + ++ if not self.check_referer(environ): ++ return self.bad_request(environ, start_response, 'denied') ++ + # Redirect to login if no Kerberos credentials + ccache_name = self.get_environ_creds(environ) + if ccache_name is None: +@@ -949,6 +962,9 @@ class KerberosLogin(Backend, KerberosSession): + def __call__(self, environ, start_response): + logger.debug('WSGI KerberosLogin.__call__:') + ++ if not self.check_referer(environ): ++ return self.bad_request(environ, start_response, 'denied') ++ + # Redirect to login if no Kerberos credentials + user_ccache_name = self.get_environ_creds(environ) + if user_ccache_name is None: +@@ -967,6 +983,9 @@ class login_x509(KerberosLogin): + def __call__(self, environ, start_response): + logger.debug('WSGI login_x509.__call__:') + ++ if not self.check_referer(environ): ++ return self.bad_request(environ, start_response, 'denied') ++ + if 'KRB5CCNAME' not in environ: + return self.unauthorized( + environ, start_response, 'KRB5CCNAME not set', +@@ -1015,6 +1034,9 @@ class login_password(Backend, KerberosSession): + + logger.debug('WSGI login_password.__call__:') + ++ if not self.check_referer(environ): ++ return self.bad_request(environ, start_response, 'denied') ++ + # Get the user and password parameters from the request + content_type = environ.get('CONTENT_TYPE', '').lower() + if not content_type.startswith('application/x-www-form-urlencoded'): +@@ -1147,6 +1169,9 @@ class change_password(Backend, HTTP_Status): + def __call__(self, environ, start_response): + logger.info('WSGI change_password.__call__:') + ++ if not self.check_referer(environ): ++ return self.bad_request(environ, start_response, 'denied') ++ + # Get the user and password parameters from the request + content_type = environ.get('CONTENT_TYPE', '').lower() + if not content_type.startswith('application/x-www-form-urlencoded'): +@@ -1364,6 +1389,9 @@ class xmlserver_session(xmlserver, KerberosSession): + + logger.debug('WSGI xmlserver_session.__call__:') + ++ if not self.check_referer(environ): ++ return self.bad_request(environ, start_response, 'denied') ++ + ccache_name = environ.get('KRB5CCNAME') + + # Redirect to /ipa/xml if no Kerberos credentials + diff --git a/freeipa.spec b/freeipa.spec index 93a66a0131bd44ab6a2ef8bd6aa7e5d9ca91734c..e21d816e34fd6fa7028bdb4e47359b0f44be10c4 100644 --- a/freeipa.spec +++ b/freeipa.spec @@ -94,7 +94,7 @@ Name: %{package_name} Version: %{IPA_VERSION} -Release: 5 +Release: 6 Summary: The Identity, Policy and Audit system License: GPLv3+ @@ -104,7 +104,7 @@ Source1: openEuler-platform.tar.gz Patch0001: adapt-freeipa-to-openEuler.patch Patch0002: modify-the-utils-interface.patch - +Patch0003: Check-the-HTTP-Referer-header-on-all-requests.patch # For the timestamp trick in patch application BuildRequires: diffstat @@ -1525,6 +1525,9 @@ fi %changelog +* Thu Apr 25 2024 lilong - 4.9.3-6 +- backport fix CVE-2023-5455 + * Wed Mar 08 2023 jiangxinyu - 4.9.3-5 - Modify the utils interface