Skip to content

Commit 4edd1dc

Browse files
petyaslavovaManelCoutinhoSensei
authored andcommitted
Changing the default value for ssl_check_hostname to True, to ensure security validations are not skipped by default (redis#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 a02fa71 commit 4edd1dc

File tree

10 files changed

+67
-15
lines changed

10 files changed

+67
-15
lines changed

docs/examples/ssl_connection_examples.ipynb

Lines changed: 11 additions & 8 deletions
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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ def __init__(
242242
ssl_cert_reqs: Union[str, VerifyMode] = "required",
243243
ssl_ca_certs: Optional[str] = None,
244244
ssl_ca_data: Optional[str] = None,
245-
ssl_check_hostname: bool = False,
245+
ssl_check_hostname: bool = True,
246246
ssl_min_version: Optional[TLSVersion] = None,
247247
ssl_ciphers: Optional[str] = None,
248248
max_connections: Optional[int] = None,

redis/asyncio/cluster.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ def __init__(
281281
ssl_ca_data: Optional[str] = None,
282282
ssl_cert_reqs: Union[str, VerifyMode] = "required",
283283
ssl_certfile: Optional[str] = None,
284-
ssl_check_hostname: bool = False,
284+
ssl_check_hostname: bool = True,
285285
ssl_keyfile: Optional[str] = None,
286286
ssl_min_version: Optional[TLSVersion] = None,
287287
ssl_ciphers: Optional[str] = None,

redis/asyncio/connection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,7 @@ def __init__(
824824
ssl_cert_reqs: Union[str, ssl.VerifyMode] = "required",
825825
ssl_ca_certs: Optional[str] = None,
826826
ssl_ca_data: Optional[str] = None,
827-
ssl_check_hostname: bool = False,
827+
ssl_check_hostname: bool = True,
828828
ssl_min_version: Optional[TLSVersion] = None,
829829
ssl_ciphers: Optional[str] = None,
830830
**kwargs,

redis/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ def __init__(
224224
ssl_ca_certs: Optional[str] = None,
225225
ssl_ca_path: Optional[str] = None,
226226
ssl_ca_data: Optional[str] = None,
227-
ssl_check_hostname: bool = False,
227+
ssl_check_hostname: bool = True,
228228
ssl_password: Optional[str] = None,
229229
ssl_validate_ocsp: bool = False,
230230
ssl_validate_ocsp_stapled: bool = False,

redis/connection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1050,7 +1050,7 @@ def __init__(
10501050
ssl_cert_reqs="required",
10511051
ssl_ca_certs=None,
10521052
ssl_ca_data=None,
1053-
ssl_check_hostname=False,
1053+
ssl_check_hostname=True,
10541054
ssl_ca_path=None,
10551055
ssl_password=None,
10561056
ssl_validate_ocsp=False,

tests/test_asyncio/test_cluster.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3124,7 +3124,9 @@ async def test_ssl_with_invalid_cert(
31243124
async def test_ssl_connection(
31253125
self, create_client: Callable[..., Awaitable[RedisCluster]]
31263126
) -> None:
3127-
async with await create_client(ssl=True, ssl_cert_reqs="none") as rc:
3127+
async with await create_client(
3128+
ssl=True, ssl_check_hostname=False, ssl_cert_reqs="none"
3129+
) as rc:
31283130
assert await rc.ping()
31293131

31303132
@pytest.mark.parametrize(
@@ -3140,6 +3142,7 @@ async def test_ssl_connection_tls12_custom_ciphers(
31403142
) -> None:
31413143
async with await create_client(
31423144
ssl=True,
3145+
ssl_check_hostname=False,
31433146
ssl_cert_reqs="none",
31443147
ssl_min_version=ssl.TLSVersion.TLSv1_2,
31453148
ssl_ciphers=ssl_ciphers,
@@ -3151,6 +3154,7 @@ async def test_ssl_connection_tls12_custom_ciphers_invalid(
31513154
) -> None:
31523155
async with await create_client(
31533156
ssl=True,
3157+
ssl_check_hostname=False,
31543158
ssl_cert_reqs="none",
31553159
ssl_min_version=ssl.TLSVersion.TLSv1_2,
31563160
ssl_ciphers="foo:bar",
@@ -3172,6 +3176,7 @@ async def test_ssl_connection_tls13_custom_ciphers(
31723176
# TLSv1.3 does not support changing the ciphers
31733177
async with await create_client(
31743178
ssl=True,
3179+
ssl_check_hostname=False,
31753180
ssl_cert_reqs="none",
31763181
ssl_min_version=ssl.TLSVersion.TLSv1_2,
31773182
ssl_ciphers=ssl_ciphers,
@@ -3183,12 +3188,20 @@ async def test_ssl_connection_tls13_custom_ciphers(
31833188
async def test_validating_self_signed_certificate(
31843189
self, create_client: Callable[..., Awaitable[RedisCluster]]
31853190
) -> None:
3191+
# ssl_check_hostname=False is used to avoid hostname verification
3192+
# in the test environment, where the server certificate is self-signed
3193+
# and does not match the hostname that is extracted for the cluster.
3194+
# Cert hostname is 'localhost' in the cluster initialization when using
3195+
# 'localhost' it gets transformed into 127.0.0.1
3196+
# In production code, ssl_check_hostname should be set to True
3197+
# to ensure proper hostname verification.
31863198
async with await create_client(
31873199
ssl=True,
31883200
ssl_ca_certs=self.ca_cert,
31893201
ssl_cert_reqs="required",
31903202
ssl_certfile=self.client_cert,
31913203
ssl_keyfile=self.client_key,
3204+
ssl_check_hostname=False,
31923205
) as rc:
31933206
assert await rc.ping()
31943207

@@ -3198,10 +3211,18 @@ async def test_validating_self_signed_string_certificate(
31983211
with open(self.ca_cert) as f:
31993212
cert_data = f.read()
32003213

3214+
# ssl_check_hostname=False is used to avoid hostname verification
3215+
# in the test environment, where the server certificate is self-signed
3216+
# and does not match the hostname that is extracted for the cluster.
3217+
# Cert hostname is 'localhost' in the cluster initialization when using
3218+
# 'localhost' it gets transformed into 127.0.0.1
3219+
# In production code, ssl_check_hostname should be set to True
3220+
# to ensure proper hostname verification.
32013221
async with await create_client(
32023222
ssl=True,
32033223
ssl_ca_data=cert_data,
32043224
ssl_cert_reqs="required",
3225+
ssl_check_hostname=False,
32053226
ssl_certfile=self.client_cert,
32063227
ssl_keyfile=self.client_key,
32073228
) as rc:

tests/test_asyncio/test_connect.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ async def test_uds_connect(uds_address, check_server_ready):
8080
async def test_tcp_ssl_tls12_custom_ciphers(tcp_address, ssl_ciphers):
8181
host, port = tcp_address
8282

83+
# in order to have working hostname verification, we need to use "localhost"
84+
# as redis host as the server certificate is self-signed and only valid for "localhost"
85+
host = "localhost"
86+
8387
server_certs = get_tls_certificates(cert_type=CertificateType.server)
8488

8589
conn = SSLConnection(
@@ -116,6 +120,10 @@ async def test_tcp_ssl_tls12_custom_ciphers(tcp_address, ssl_ciphers):
116120
async def test_tcp_ssl_connect(tcp_address, ssl_min_version, check_server_ready):
117121
host, port = tcp_address
118122

123+
# in order to have working hostname verification, we need to use "localhost"
124+
# as redis host as the server certificate is self-signed and only valid for "localhost"
125+
host = "localhost"
126+
119127
server_certs = get_tls_certificates(cert_type=CertificateType.server)
120128

121129
conn = SSLConnection(

tests/test_connect.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,16 @@ def test_uds_connect(uds_address, check_server_ready):
8282
)
8383
def test_tcp_ssl_connect(tcp_address, ssl_min_version, check_server_ready):
8484
host, port = tcp_address
85+
86+
# in order to have working hostname verification, we need to use "localhost"
87+
# as redis host as the server certificate is self-signed and only valid for "localhost"
88+
host = "localhost"
8589
server_certs = get_tls_certificates(cert_type=CertificateType.server)
90+
8691
conn = SSLConnection(
8792
host=host,
8893
port=port,
94+
ssl_check_hostname=True,
8995
client_name=_CLIENT_NAME,
9096
ssl_ca_certs=server_certs.ca_certfile,
9197
socket_timeout=10,
@@ -113,6 +119,10 @@ def test_tcp_ssl_connect(tcp_address, ssl_min_version, check_server_ready):
113119
def test_tcp_ssl_tls12_custom_ciphers(tcp_address, ssl_ciphers):
114120
host, port = tcp_address
115121

122+
# in order to have working hostname verification, we need to use "localhost"
123+
# as redis host as the server certificate is self-signed and only valid for "localhost"
124+
host = "localhost"
125+
116126
server_certs = get_tls_certificates(cert_type=CertificateType.server)
117127

118128
conn = SSLConnection(

tests/test_ssl.py

Lines changed: 11 additions & 1 deletion
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

@@ -105,6 +112,7 @@ def test_ssl_connection_tls12_custom_ciphers(self, request, ssl_ciphers):
105112
host=p[0],
106113
port=p[1],
107114
ssl=True,
115+
ssl_check_hostname=False,
108116
ssl_cert_reqs="none",
109117
ssl_min_version=ssl.TLSVersion.TLSv1_3,
110118
ssl_ciphers=ssl_ciphers,
@@ -119,6 +127,7 @@ def test_ssl_connection_tls12_custom_ciphers_invalid(self, request):
119127
host=p[0],
120128
port=p[1],
121129
ssl=True,
130+
ssl_check_hostname=False,
122131
ssl_cert_reqs="none",
123132
ssl_min_version=ssl.TLSVersion.TLSv1_2,
124133
ssl_ciphers="foo:bar",
@@ -143,6 +152,7 @@ def test_ssl_connection_tls13_custom_ciphers(self, request, ssl_ciphers):
143152
host=p[0],
144153
port=p[1],
145154
ssl=True,
155+
ssl_check_hostname=False,
146156
ssl_cert_reqs="none",
147157
ssl_min_version=ssl.TLSVersion.TLSv1_2,
148158
ssl_ciphers=ssl_ciphers,

0 commit comments

Comments
 (0)