Skip to content

Commit 120517f

Browse files
authored
Changing the default value for ssl_check_hostname to True, to ensure security validations are not skipped by default (#3626)
* Changing the default value for ssl_check_hostname to True, to ensure security validations are not skipped by default * Applying review comments * Removing unused operation in tests. * Removing unneeded comment from tests.
1 parent 8faac60 commit 120517f

File tree

10 files changed

+71
-16
lines changed

10 files changed

+71
-16
lines changed

docs/examples/ssl_connection_examples.ipynb

+11-8
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@
3434
"import redis\n",
3535
"\n",
3636
"r = redis.Redis(\n",
37-
" host='localhost', \n",
38-
" port=6666, \n",
39-
" ssl=True, \n",
37+
" host='localhost',\n",
38+
" port=6666,\n",
39+
" ssl=True,\n",
40+
" ssl_check_hostname=False,\n",
4041
" ssl_cert_reqs=\"none\",\n",
4142
")\n",
4243
"r.ping()"
@@ -68,7 +69,7 @@
6869
"source": [
6970
"import redis\n",
7071
"\n",
71-
"r = redis.from_url(\"rediss://localhost:6666?ssl_cert_reqs=none&decode_responses=True&health_check_interval=2\")\n",
72+
"r = redis.from_url(\"rediss://localhost:6666?ssl_cert_reqs=none&ssl_check_hostname=False&decode_responses=True&health_check_interval=2\")\n",
7273
"r.ping()"
7374
]
7475
},
@@ -99,13 +100,14 @@
99100
"import redis\n",
100101
"\n",
101102
"redis_pool = redis.ConnectionPool(\n",
102-
" host=\"localhost\", \n",
103-
" port=6666, \n",
104-
" connection_class=redis.SSLConnection, \n",
103+
" host=\"localhost\",\n",
104+
" port=6666,\n",
105+
" connection_class=redis.SSLConnection,\n",
106+
" ssl_check_hostname=False,\n",
105107
" ssl_cert_reqs=\"none\",\n",
106108
")\n",
107109
"\n",
108-
"r = redis.StrictRedis(connection_pool=redis_pool) \n",
110+
"r = redis.StrictRedis(connection_pool=redis_pool)\n",
109111
"r.ping()"
110112
]
111113
},
@@ -141,6 +143,7 @@
141143
" port=6666,\n",
142144
" ssl=True,\n",
143145
" ssl_min_version=ssl.TLSVersion.TLSv1_3,\n",
146+
" ssl_check_hostname=False,\n",
144147
" ssl_cert_reqs=\"none\",\n",
145148
")\n",
146149
"r.ping()"

redis/asyncio/client.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ def __init__(
241241
ssl_cert_reqs: Union[str, VerifyMode] = "required",
242242
ssl_ca_certs: Optional[str] = None,
243243
ssl_ca_data: Optional[str] = None,
244-
ssl_check_hostname: bool = False,
244+
ssl_check_hostname: bool = True,
245245
ssl_min_version: Optional[TLSVersion] = None,
246246
ssl_ciphers: Optional[str] = None,
247247
max_connections: Optional[int] = None,

redis/asyncio/cluster.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ def __init__(
280280
ssl_ca_data: Optional[str] = None,
281281
ssl_cert_reqs: Union[str, VerifyMode] = "required",
282282
ssl_certfile: Optional[str] = None,
283-
ssl_check_hostname: bool = False,
283+
ssl_check_hostname: bool = True,
284284
ssl_keyfile: Optional[str] = None,
285285
ssl_min_version: Optional[TLSVersion] = None,
286286
ssl_ciphers: Optional[str] = None,

redis/asyncio/connection.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,7 @@ def __init__(
794794
ssl_cert_reqs: Union[str, ssl.VerifyMode] = "required",
795795
ssl_ca_certs: Optional[str] = None,
796796
ssl_ca_data: Optional[str] = None,
797-
ssl_check_hostname: bool = False,
797+
ssl_check_hostname: bool = True,
798798
ssl_min_version: Optional[TLSVersion] = None,
799799
ssl_ciphers: Optional[str] = None,
800800
**kwargs,

redis/client.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ def __init__(
223223
ssl_ca_certs: Optional[str] = None,
224224
ssl_ca_path: Optional[str] = None,
225225
ssl_ca_data: Optional[str] = None,
226-
ssl_check_hostname: bool = False,
226+
ssl_check_hostname: bool = True,
227227
ssl_password: Optional[str] = None,
228228
ssl_validate_ocsp: bool = False,
229229
ssl_validate_ocsp_stapled: bool = False,

redis/connection.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,7 @@ def __init__(
10281028
ssl_cert_reqs="required",
10291029
ssl_ca_certs=None,
10301030
ssl_ca_data=None,
1031-
ssl_check_hostname=False,
1031+
ssl_check_hostname=True,
10321032
ssl_ca_path=None,
10331033
ssl_password=None,
10341034
ssl_validate_ocsp=False,

tests/test_asyncio/test_cluster.py

+22-1
Original file line numberDiff line numberDiff line change
@@ -3118,7 +3118,9 @@ async def test_ssl_with_invalid_cert(
31183118
async def test_ssl_connection(
31193119
self, create_client: Callable[..., Awaitable[RedisCluster]]
31203120
) -> None:
3121-
async with await create_client(ssl=True, ssl_cert_reqs="none") as rc:
3121+
async with await create_client(
3122+
ssl=True, ssl_check_hostname=False, ssl_cert_reqs="none"
3123+
) as rc:
31223124
assert await rc.ping()
31233125

31243126
@pytest.mark.parametrize(
@@ -3134,6 +3136,7 @@ async def test_ssl_connection_tls12_custom_ciphers(
31343136
) -> None:
31353137
async with await create_client(
31363138
ssl=True,
3139+
ssl_check_hostname=False,
31373140
ssl_cert_reqs="none",
31383141
ssl_min_version=ssl.TLSVersion.TLSv1_2,
31393142
ssl_ciphers=ssl_ciphers,
@@ -3145,6 +3148,7 @@ async def test_ssl_connection_tls12_custom_ciphers_invalid(
31453148
) -> None:
31463149
async with await create_client(
31473150
ssl=True,
3151+
ssl_check_hostname=False,
31483152
ssl_cert_reqs="none",
31493153
ssl_min_version=ssl.TLSVersion.TLSv1_2,
31503154
ssl_ciphers="foo:bar",
@@ -3166,6 +3170,7 @@ async def test_ssl_connection_tls13_custom_ciphers(
31663170
# TLSv1.3 does not support changing the ciphers
31673171
async with await create_client(
31683172
ssl=True,
3173+
ssl_check_hostname=False,
31693174
ssl_cert_reqs="none",
31703175
ssl_min_version=ssl.TLSVersion.TLSv1_2,
31713176
ssl_ciphers=ssl_ciphers,
@@ -3177,12 +3182,20 @@ async def test_ssl_connection_tls13_custom_ciphers(
31773182
async def test_validating_self_signed_certificate(
31783183
self, create_client: Callable[..., Awaitable[RedisCluster]]
31793184
) -> None:
3185+
# ssl_check_hostname=False is used to avoid hostname verification
3186+
# in the test environment, where the server certificate is self-signed
3187+
# and does not match the hostname that is extracted for the cluster.
3188+
# Cert hostname is 'localhost' in the cluster initialization when using
3189+
# 'localhost' it gets transformed into 127.0.0.1
3190+
# In production code, ssl_check_hostname should be set to True
3191+
# to ensure proper hostname verification.
31803192
async with await create_client(
31813193
ssl=True,
31823194
ssl_ca_certs=self.ca_cert,
31833195
ssl_cert_reqs="required",
31843196
ssl_certfile=self.client_cert,
31853197
ssl_keyfile=self.client_key,
3198+
ssl_check_hostname=False,
31863199
) as rc:
31873200
assert await rc.ping()
31883201

@@ -3192,10 +3205,18 @@ async def test_validating_self_signed_string_certificate(
31923205
with open(self.ca_cert) as f:
31933206
cert_data = f.read()
31943207

3208+
# ssl_check_hostname=False is used to avoid hostname verification
3209+
# in the test environment, where the server certificate is self-signed
3210+
# and does not match the hostname that is extracted for the cluster.
3211+
# Cert hostname is 'localhost' in the cluster initialization when using
3212+
# 'localhost' it gets transformed into 127.0.0.1
3213+
# In production code, ssl_check_hostname should be set to True
3214+
# to ensure proper hostname verification.
31953215
async with await create_client(
31963216
ssl=True,
31973217
ssl_ca_data=cert_data,
31983218
ssl_cert_reqs="required",
3219+
ssl_check_hostname=False,
31993220
ssl_certfile=self.client_cert,
32003221
ssl_keyfile=self.client_key,
32013222
) as rc:

tests/test_asyncio/test_connect.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ async def test_uds_connect(uds_address):
5858
async def test_tcp_ssl_tls12_custom_ciphers(tcp_address, ssl_ciphers):
5959
host, port = tcp_address
6060

61+
# in order to have working hostname verification, we need to use "localhost"
62+
# as redis host as the server certificate is self-signed and only valid for "localhost"
63+
host = "localhost"
64+
6165
server_certs = get_tls_certificates(cert_type=CertificateType.server)
6266

6367
conn = SSLConnection(
@@ -89,6 +93,10 @@ async def test_tcp_ssl_tls12_custom_ciphers(tcp_address, ssl_ciphers):
8993
async def test_tcp_ssl_connect(tcp_address, ssl_min_version):
9094
host, port = tcp_address
9195

96+
# in order to have working hostname verification, we need to use "localhost"
97+
# as redis host as the server certificate is self-signed and only valid for "localhost"
98+
host = "localhost"
99+
92100
server_certs = get_tls_certificates(cert_type=CertificateType.server)
93101

94102
conn = SSLConnection(
@@ -100,7 +108,10 @@ async def test_tcp_ssl_connect(tcp_address, ssl_min_version):
100108
ssl_min_version=ssl_min_version,
101109
)
102110
await _assert_connect(
103-
conn, tcp_address, certfile=server_certs.certfile, keyfile=server_certs.keyfile
111+
conn,
112+
tcp_address,
113+
certfile=server_certs.certfile,
114+
keyfile=server_certs.keyfile,
104115
)
105116
await conn.disconnect()
106117

tests/test_connect.py

+10
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,16 @@ def test_uds_connect(uds_address):
5454
)
5555
def test_tcp_ssl_connect(tcp_address, ssl_min_version):
5656
host, port = tcp_address
57+
58+
# in order to have working hostname verification, we need to use "localhost"
59+
# as redis host as the server certificate is self-signed and only valid for "localhost"
60+
host = "localhost"
5761
server_certs = get_tls_certificates(cert_type=CertificateType.server)
62+
5863
conn = SSLConnection(
5964
host=host,
6065
port=port,
66+
ssl_check_hostname=True,
6167
client_name=_CLIENT_NAME,
6268
ssl_ca_certs=server_certs.ca_certfile,
6369
socket_timeout=10,
@@ -80,6 +86,10 @@ def test_tcp_ssl_connect(tcp_address, ssl_min_version):
8086
def test_tcp_ssl_tls12_custom_ciphers(tcp_address, ssl_ciphers):
8187
host, port = tcp_address
8288

89+
# in order to have working hostname verification, we need to use "localhost"
90+
# as redis host as the server certificate is self-signed and only valid for "localhost"
91+
host = "localhost"
92+
8393
server_certs = get_tls_certificates(cert_type=CertificateType.server)
8494

8595
conn = SSLConnection(

tests/test_ssl.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,14 @@ def test_ssl_with_invalid_cert(self, request):
3737
def test_ssl_connection(self, request):
3838
ssl_url = request.config.option.redis_ssl_url
3939
p = urlparse(ssl_url)[1].split(":")
40-
r = redis.Redis(host=p[0], port=p[1], ssl=True, ssl_cert_reqs="none")
40+
41+
r = redis.Redis(
42+
host=p[0],
43+
port=p[1],
44+
ssl=True,
45+
ssl_check_hostname=False,
46+
ssl_cert_reqs="none",
47+
)
4148
assert r.ping()
4249
r.close()
4350

@@ -98,6 +105,7 @@ def test_ssl_connection_tls12_custom_ciphers(self, request, ssl_ciphers):
98105
host=p[0],
99106
port=p[1],
100107
ssl=True,
108+
ssl_check_hostname=False,
101109
ssl_cert_reqs="none",
102110
ssl_min_version=ssl.TLSVersion.TLSv1_3,
103111
ssl_ciphers=ssl_ciphers,
@@ -112,6 +120,7 @@ def test_ssl_connection_tls12_custom_ciphers_invalid(self, request):
112120
host=p[0],
113121
port=p[1],
114122
ssl=True,
123+
ssl_check_hostname=False,
115124
ssl_cert_reqs="none",
116125
ssl_min_version=ssl.TLSVersion.TLSv1_2,
117126
ssl_ciphers="foo:bar",
@@ -136,6 +145,7 @@ def test_ssl_connection_tls13_custom_ciphers(self, request, ssl_ciphers):
136145
host=p[0],
137146
port=p[1],
138147
ssl=True,
148+
ssl_check_hostname=False,
139149
ssl_cert_reqs="none",
140150
ssl_min_version=ssl.TLSVersion.TLSv1_2,
141151
ssl_ciphers=ssl_ciphers,

0 commit comments

Comments
 (0)