Use of an insecure channel - useSslProtocol()
Need
Secure communication channel for production environment
Context
- Usage of Python 3 for developing applications and scripts
- Usage of SSL for secure communication and data encryption
- Usage of Socket for real-time communication and event-based messaging
Description
Non compliant code
import ssl, socket
def insecure_connection():
context = ssl._create_unverified_context()
with socket.create_connection(('localhost', 8443)) as sock:
with context.wrap_socket(sock, server_hostname='localhost') as ssock:
print(ssock.version())
insecure_connection()
In the code above, the function insecure_connection()
is used to create an SSL connection to a server. However, it uses the method ssl._create_unverified_context()
, which creates a SSL context that does not verify the server certificate.
This means that the client will accept any server certificate without checking if it's signed by a trusted Certificate Authority (CA), which makes it vulnerable to man-in-the-middle attacks. An attacker could intercept the connection and present their own certificate, and the client would accept it without any verification.
This is especially dangerous in a production environment where sensitive data might be transmitted over the connection. The use of SSL is intended to provide a secure, encrypted channel for data transmission, but by not verifying server certificates, this security measure is effectively bypassed.
In a Django backend application, this could potentially expose user data or other sensitive information to attackers. Therefore, it's recommended to always verify server certificates when using SSL.
Steps
- Replace the '_create_unverified_context()' function with the 'ssl.create_default_context()' function. This will create a secure SSL context with sensible default settings.
- Set the 'check_hostname' attribute of the SSL context to True. This will enable hostname verification.
- Use the 'load_default_certs()' function on the SSL context to load the system’s default CA certificates. If necessary, use the 'load_cert_chain()' function to load the client-side certificate and private key.
- Finally, use the 'wrap_socket()' function with the secure SSL context to establish a secure connection.
Compliant code
import ssl, socket
def secure_connection():
# Create a secure SSL context with sensible default settings
context = ssl.create_default_context()
# Enable hostname verification
context.check_hostname = True
# Load the system’s default CA certificates
context.load_default_certs()
# If necessary, load the client-side certificate and private key
# context.load_cert_chain(certfile='path_to_certfile', keyfile='path_to_keyfile')
with socket.create_connection(('localhost', 8443)) as sock:
with context.wrap_socket(sock, server_hostname='localhost') as ssock:
print(ssock.version())
secure_connection()
The updated code now uses the ssl.create_default_context()
function to create a secure SSL context with sensible default settings. This function is recommended over the ssl._create_unverified_context()
function, which creates an insecure SSL context that does not verify server certificates.
The check_hostname
attribute of the SSL context is set to True
to enable hostname verification. This is an important security feature that helps protect against man-in-the-middle attacks by ensuring that the server's certificate is valid for the server's hostname.
The load_default_certs()
function is used to load the system’s default CA certificates. This allows the SSL context to verify the authenticity of the server's certificate.
If necessary, the load_cert_chain()
function can be used to load the client-side certificate and private key. This is commented out in the code, but can be uncommented and filled in with the appropriate file paths if client-side authentication is required.
Finally, the wrap_socket()
function is used with the secure SSL context to establish a secure connection to the server. This function wraps the existing socket in an SSL context, enabling secure communication over the socket.