Use of an insecure channel - useSslProtocol() - Python

Use of an insecure channel - useSslProtocol() - Python

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.

References