From 743f9a80ee7c49b18f635ecdd2df2e8676069ad8 Mon Sep 17 00:00:00 2001 From: Csaba Ringhofer Date: Fri, 11 Sep 2026 17:37:09 +0200 Subject: [PATCH] Use verify_cert=True by default This is an intentional breaking change, by switching to safer default some users with self-signed certs may need to modify their code to pass ca_cert or verify_cert=True. Assisted-By: Claude Opus 4.8 --- CHANGELOG.md | 9 +++++++++ README.md | 15 +++++++++------ impala/_thrift_api.py | 2 +- impala/dbapi.py | 20 ++++++++++++-------- impala/hiveserver2.py | 2 +- impala/tests/test_dbapi_connect.py | 18 ++++++++++-------- 6 files changed, 42 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 761a05bb9..9966ec31c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ Changelog ========= +0.25 +------ +* **Breaking changes** + - SSL certificate verification is now on by default. `connect(use_ssl=True)` + now verifies the server's certificate against the system's CA certificates + (or against `ca_cert` if provided). Previously `verify_cert` defaulted to + False and the server was not verified unless `verify_cert=True` or `ca_cert` + was set. Pass `verify_cert=False` to restore the old, insecure behavior. + 0.24 ------ * **Breaking changes** diff --git a/README.md b/README.md index ca106ba7c..1e94fd070 100644 --- a/README.md +++ b/README.md @@ -164,15 +164,18 @@ df = as_pandas(cur) # carry df through scikit-learn, for example ``` -For secure connection set use_ssl=True in connect(). Warning: this doesn't verify the server -by default! To verify server set verify_cert or ca_cart perameter: +For a secure connection set use_ssl=True in connect(). Since 0.25.0 this verifies the +server's certificate against the system's CA certificates by default: ```python -# Verify server using system CA certificates: -conn = connect(host='my.host.com', use_ssl=True, verify_cert=True) +# Verify server using system CA certificates (the default): +conn = connect(host='my.host.com', use_ssl=True) -# Verify server using custom CA certificate: -conn = connect(host='my.host.com', use_ssl=True, ca_cart="/tmp/my_cert.pem") +# Verify server using a custom CA certificate: +conn = connect(host='my.host.com', use_ssl=True, ca_cert="/tmp/my_cert.pem") + +# Disable verification (insecure). Before 0.25.0 this was the default behavior. +conn = connect(host='my.host.com', use_ssl=True, verify_cert=False) ``` [pep249]: http://legacy.python.org/dev/peps/pep-0249/ diff --git a/impala/_thrift_api.py b/impala/_thrift_api.py index f605f36b3..14180ca1d 100644 --- a/impala/_thrift_api.py +++ b/impala/_thrift_api.py @@ -408,7 +408,7 @@ def get_http_transport(host, port, http_path, timeout=None, use_ssl=False, ca_cert=None, auth_mechanism='NOSASL', user=None, password=None, kerberos_host=None, kerberos_service_name=None, http_cookie_names=None, jwt=None, user_agent=None, - get_user_custom_headers_func=None, verify_cert=False): + get_user_custom_headers_func=None, verify_cert=True): host_url = "[%s]" % host if ":" in host else host # add brackets for ipv6 address # TODO: support timeout if timeout is not None: diff --git a/impala/dbapi.py b/impala/dbapi.py index 4e22ffa02..757826852 100644 --- a/impala/dbapi.py +++ b/impala/dbapi.py @@ -42,7 +42,7 @@ def connect(host='localhost', port=21050, database=None, timeout=None, protocol=None, krb_host=None, use_http_transport=False, http_path='', auth_cookie_names=None, http_cookie_names=None, retries=3, jwt=None, user_agent=None, - get_user_custom_headers_func=None, verify_cert=False): + get_user_custom_headers_func=None, verify_cert=True): """Get a connection to HiveServer2 (HS2). These options are largely compatible with the impala-shell command line @@ -64,8 +64,9 @@ def connect(host='localhost', port=21050, database=None, timeout=None, Enable SSL. ca_cert : str, optional Local path to the the third-party CA certificate. If set, the server certificate - will be verified using the provided CA cert. If SSL is enabled but - the certificate is not specified, see 'verify_cert' for behavior. + will be verified using the provided CA cert instead of the system's CA + certificates. If SSL is enabled but the certificate is not specified, see + 'verify_cert' for behavior. auth_mechanism : {'NOSASL', 'PLAIN', 'GSSAPI', 'LDAP', 'JWT'} Specify the authentication mechanism. `'NOSASL'` for unsecured Impala. `'PLAIN'` for unsecured Hive (because Hive requires the SASL @@ -108,11 +109,14 @@ def connect(host='localhost', port=21050, database=None, timeout=None, This is a function returning a list of tuples, each tuple contains a key-value pair. This allows duplicate headers to be set. verify_cert : bool, optional - Whether to verify the server's TLS certificate when using SSL using the systems's - CA certificates. Ignored if 'ca_cert' is provided, in which case the certificate - will be verified using the provided CA cert. - - .. deprecated:: 0.18.0 + Whether to verify the server's TLS certificate against the system's CA + certificates when using SSL. Defaults to True. Set to False to disable + verification. Ignored if 'ca_cert' is provided, in which case the certificate + is always verified using the provided CA cert. + + .. versionchanged:: 0.25.0 + The default changed from False to True, so SSL connections verify the + server certificate unless 'verify_cert=False' is passed. auth_cookie_names : list of str or str, optional Use `http_cookie_names` parameter instead. diff --git a/impala/hiveserver2.py b/impala/hiveserver2.py index 7704e7c2a..9b01e5516 100644 --- a/impala/hiveserver2.py +++ b/impala/hiveserver2.py @@ -916,7 +916,7 @@ def connect(host, port, timeout=None, use_ssl=False, ca_cert=None, user=None, password=None, kerberos_service_name='impala', auth_mechanism=None, krb_host=None, use_http_transport=False, http_path='', http_cookie_names=None, retries=3, jwt=None, - user_agent=None, get_user_custom_headers_func=None, verify_cert=False): + user_agent=None, get_user_custom_headers_func=None, verify_cert=True): log.debug('Connecting to HiveServer2 %s:%s with %s authentication ' 'mechanism', host, port, auth_mechanism) diff --git a/impala/tests/test_dbapi_connect.py b/impala/tests/test_dbapi_connect.py index 67c9be7fd..2dd1564ef 100644 --- a/impala/tests/test_dbapi_connect.py +++ b/impala/tests/test_dbapi_connect.py @@ -241,7 +241,8 @@ def test_jwt_auth_with_ldap_password(self): @pytest.mark.skipif(SSL_DISABLED, reason=SSL_DISABLED_ERROR) @pytest.mark.ssl def test_ssl_connection_no_cert(self): - self.connection = connect(ENV.host, ENV.port, timeout=TIMEOUT_S, use_ssl=True) + self.connection = connect( + ENV.host, ENV.port, timeout=TIMEOUT_S, use_ssl=True, verify_cert=False) self._execute_queries(self.connection) @@ -267,9 +268,9 @@ def test_ssl_connection_wrong_cert(self): @pytest.mark.ssl def test_ssl_connection_default_certs(self): try: - # With verify_cert=True, the system's CA certificates will be used to verify - # the server certificate. Since the server certificate is self-signed and not - # in the system CA store, verification should fail. + # verify_cert=True (also the default) uses the system's CA certificates to + # verify the server certificate. Since the server certificate is self-signed + # and not in the system CA store, verification should fail. # TODO: writing positive test would be nice but is more difficult connect( ENV.host, ENV.port, use_ssl=True, timeout=TIMEOUT_S, verify_cert=True) @@ -282,7 +283,8 @@ def test_ssl_connection_default_certs(self): @pytest.mark.ssl def test_https_connection_nocert(self): self.connection = connect(ENV.host, ENV.http_port, use_http_transport=True, - http_path="cliservice", use_ssl=True, timeout=TIMEOUT_S) + http_path="cliservice", use_ssl=True, timeout=TIMEOUT_S, + verify_cert=False) self._execute_queries(self.connection) @pytest.mark.skipif(SSL_DISABLED, reason=SSL_DISABLED_ERROR) @@ -310,9 +312,9 @@ def test_https_connection_wrong_cert(self): @pytest.mark.ssl def test_https_connection_default_certs(self): try: - # With verify_cert=True, the system's CA certificates will be used to verify - # the server certificate. Since the server certificate is self-signed and not - # in the system CA store, verification should fail. + # verify_cert=True (also the default) uses the system's CA certificates to + # verify the server certificate. Since the server certificate is self-signed + # and not in the system CA store, verification should fail. # TODO: writing positive test would be nice but is more difficult connection = connect(ENV.host, ENV.http_port, use_http_transport=True, http_path="cliservice", use_ssl=True, timeout=TIMEOUT_S,