Skip to main content

Insecure Network Communication

Fixing Certificate Validation

About Certificate Validation

What is Improper Certificate Validation?

Improper certificate validation refers to a security vulnerability where a system fails to properly verify the authenticity of a digital certificate presented by a remote party during a communication. This can lead to the acceptance of forged or malicious certificates, allowing attackers to perform various attacks such as man-in-the-middle attacks or impersonation attacks.

Proper certificate validation is crucial for maintaining the security of SSL/TLS encrypted communication and ensuring the confidentiality, integrity, and authenticity of data exchanged over the network.

Check out these videos for a high-level explanation:

  • Weak certificate validation

  • Improper certificate pinning

What is the impact of Improper Certificate Validation?

Improper certificate validation can lead to a range of security threats, including:

  • Man-in-the-middle attacks: Attackers can intercept communication between two parties and read or modify the data exchanged between them.
  • Data breaches: Attackers can gain unauthorized access to sensitive information or sensitive systems, leading to data breaches.
  • Malware distribution: Attackers can use fake digital certificates to distribute malicious software or infect systems with malware.

Overall, improper certificate validation can undermine the security of encrypted communication and compromise the confidentiality, integrity, and authenticity of data exchanged over the network.

How to prevent Improper Certificate Validation?

To prevent improper certificate validation, it is important to follow security best practices, such as:

  • Use trusted certificate authorities: Only trust digital certificates issued by well-known and trusted certificate authorities.
  • Verify certificate chains: Verify that the certificate presented by the remote party is valid and issued by a trusted certificate authority. Verify the entire certificate chain, including intermediate certificates.
  • Check certificate revocation status: Check the revocation status of the certificate presented by the remote party to ensure that it has not been revoked.
  • Use certificate pinning: Implement certificate pinning to ensure that the communication only occurs with the exact certificate or certificate authority specified.
  • Keep software up to date: Keep software and security protocols up to date, as new vulnerabilities and security patches are regularly released.

Overall, proper certificate validation is crucial for maintaining the security of encrypted communication, and following these best practices can help prevent improper certificate validation and mitigate related security risks.

References

Taxonomies

Explanation & Prevention

Training

Insecure certificate verification in SSL and TLS for libcurl

The rule detects the use of CURLOPT_SSL_VERIFYPEER option set to 0. This setting disables verification of the peer's SSL certificate, which poses a potential security risk by allowing for the possibility of a man-in-the-middle (MitM) attack. The attacker can present a false SSL certificate to the client, which would then be accepted if the peer's SSL certificate is not verified. This would allow him to intercept and modify data exchanged between the client and server, potentially compromising sensitive information or executing unauthorized actions.

It is recommended to set CURLOPT_SSL_VERIFYPEER to 1, and to properly configure the trusted Certificate Authority (CA) certificates for secure SSL/TLS connections.

Option A: Enabling CURLOPT_SSL_VERIFYPEER

  1. Go through the issues that GuardRails identified in the PR, for a pattern similar to the following:

    #include <curl/curl.h>

    CURL *curl;
    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");

    // Insecure example
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
  2. Set CURLOPT_SSL_VERIFYPEER to 1.

    #include <curl/curl.h>

    CURL *curl;
    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");

    // Secure example
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
  3. Test it

  4. Ship it 🚢 and relax 🌴

Insecure hostname verification in SSL and TLS for libcurl

Insufficient hostname verification may occur when CURLOPT_SSL_VERIFYHOST is not set to 2, which would result in the hostname verification being performed only against the Common Name (CN) field (when the value is 1), or not at all (when the value is 0). This leaves the system vulnerable to exploitation by attackers, who can present a valid SSL/TLS certificate with a different hostname to the client.

Failure to perform proper hostname verification against the SSL/TLS certificate in such cases would lead to a connection with the attacker, with the client under the impression that the attacker is the legitimate server. As a result, it is important to ensure that sufficient hostname verification is performed in SSL/TLS communication, which can be achieved by setting CURLOPT_SSL_VERIFYHOST to 2, in order to check the hostname against both the CN field and the Subject Alternative Name (SAN) fields in the peer's SSL/TLS certificate. Additionally, trusted Certificate Authority (CA) certificates should be configured to prevent accepting fraudulent certificates.

Option A: Setting CURLOPT_SSL_VERIFYPEER to 2

  1. Go through the issues that GuardRails identified in the PR, for a pattern similar to the following:

    #include <curl/curl.h>

    CURL *curl;
    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);

    // Insecure example
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);

    // This is also unsafe
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1L);
  2. Set the CURLOPT_SSL_VERIFYHOST to 2

    #include <curl/curl.h>

    CURL *curl;
    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);

    // Secure example
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
  3. Test it

  4. Ship it 🚢 and relax 🌴

Insecure certificate verification in SSL and TLS for OpenSSL

This rule detects the use of SSL_VERIFY_NONE and the override of the default verification function in verify_callback in OpenSSL. See the OpenSSL documentation for more details about the signature of the SSL_CTX_set_verify function, which is in charge of verifying certificate.

Setting SSL_VERIFY_NONE disables verification of the peer's SSL certificate, which poses a potential security risk by allowing for the possibility of a man-in-the-middle (MitM) attack. The attacker can present a false SSL certificate to the client, which would then be accepted if the peer's SSL certificate is not being verified. This would allow him to intercept and modify data exchanged between the client and server, potentially compromising sensitive information or executing unauthorized actions.

The use of custom certification function for SSL_CTX_set_verify is risky, and should only be done if the developer is very confident of the implementation. Flaws in the verification may lead to the same consequences as using SSL_VERIFY_NONE.

It is therefore recommended for developers to use the default built-in certificate validation function that OpenSSL provides.

Option A: Use built-in function from OpenSSL (use of SSL_VERIFY_NONE)

  1. Go through the issues that GuardRails identified in the PR, for a pattern similar to the following:

    #include <openssl/ssl.h>
    const SSL_METHOD *method = TLS_method();
    SSL_CTX *ctx = SSL_CTX_new(method);

    // Insecure example
    SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
    SSL *ssl = SSL_new(ctx);
    SSL_connect(ssl);
  2. Replace SSL_VERIFY_NONE with SSL_VERIFY_PEER

     #include <openssl/ssl.h>

    const SSL_METHOD *method = TLS_method();
    SSL_CTX *ctx = SSL_CTX_new(method);

    // Secure example
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
    SSL *ssl = SSL_new(ctx);
    SSL_connect(ssl);
  3. Test it

  4. Ship it 🚢 and relax 🌴

Option B: Use built-in function from OpenSSL (overriding verify_callback)

  1. Go through the issues that GuardRails identified in the PR, for a pattern similar to the following:

    #include <openssl/ssl.h>

    // Example of a bad certification function, this always
    // validate any certificate specified
    static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
    return 1;
    }

    const SSL_METHOD *method = TLS_method();
    SSL_CTX *ctx = SSL_CTX_new(method);

    // Insecure example
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
    SSL *ssl = SSL_new(ctx);
    SSL_connect(ssl);
  2. Replace the overriden function with NULL

     #include <openssl/ssl.h>

    const SSL_METHOD *method = TLS_method();
    SSL_CTX *ctx = SSL_CTX_new(method);

    // Secure example
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
    SSL *ssl = SSL_new(ctx);
    SSL_connect(ssl);
  3. Test it

  4. Ship it 🚢 and relax 🌴

Missing hostname verification in SSL and TLS for OpenSSL

The rule detects the miss of hostname verification in SSL/TLS for OpenSSL. One common mistake made by users of OpenSSL is to assume that OpenSSL will validate the hostname in the server's certificate. Versions prior to 1.0.2 did not perform hostname validation. Version 1.0.2 and up contain support for hostname validation, but they still require the user to call a few functions to set it up. Developers can use SSL_set1_host for this validation.

If the client fails to validate the hostname in the server's SSL/TLS certificate, it can lead to a man-in-the-middle (MitM) attack, where an attacker intercepts the connection and presents a forged SSL/TLS certificate with a different hostname. The client may establish the connection with the attacker under the impression that it is connecting to the legitimate server, thereby compromising the confidentiality and integrity of the transmitted data.

Option A: Explicitly specify the verification of hostnames

  1. Go through the issues that GuardRails identified in the PR, for a pattern similar to the following:

    #include <openssl/ssl.h>
    SSL_CTX *ctx = get_ctx();
    SSL *ssl = SSL_new(ctx);

    // By default hostname validation is disabled
    // Insecure example
    SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);

    SSL_connect(ssl);
  2. Include the verification of hostnames using SSL_set1_host

    #include <openssl/ssl.h>
    SSL_CTX *ctx = get_ctx();
    SSL *ssl = SSL_new(ctx);

    const char HOST_NAME[] = "www.example.com";

    // Secure example
    SSL_set1_host(ssl, HOST_NAME);
    SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);

    SSL_connect(ssl);
  3. Test it

  4. Ship it 🚢 and relax 🌴

Securing TLS configuration

About Insecure TLS Configuration

What is insecure TLS configuration?

Insecure TLS (Transport Layer Security) configuration refers to the use of weak or vulnerable cryptographic algorithms or protocols in the configuration of TLS on a system or application.

TLS is used to secure communication channels between clients and servers. Insecure TLS configuration can lead to a range of security vulnerabilities.

Check out these videos for a high-level explanation:

  • Weak Algorithms

  • Weak Cipher Suites

What is the impact of insecure TLS configuration?

Insecure TLS (Transport Layer Security) configuration can have significant impacts on the security and privacy of communication channels between clients and servers.

Here are some of the potential impacts:

  • Man-in-the-middle (MITM) attacks: Weak or outdated cryptographic algorithms can be exploited by attackers to intercept and modify data in transit between a client and server. This can enable attackers to steal sensitive data or manipulate communication channels to launch other attacks.
  • Information disclosure: Insecure TLS configuration can allow attackers to gain access to sensitive data, such as login credentials or personal information, transmitted between the client and server. This can lead to data breaches or compromise of sensitive information.

How to prevent insecure TLS configuration?

To prevent insecure TLS (Transport Layer Security) configuration, several measures can be taken, including:

  • Use strong cryptographic algorithms and protocols: Use strong cryptographic algorithms and protocols, such as TLS 1.2 or higher, and disable outdated or weak algorithms, such as SSLv2 and SSLv3. This can help prevent attackers from exploiting vulnerabilities in the encryption and authentication processes.
  • Use appropriate key sizes: Use appropriate key sizes to ensure that the cryptographic keys used in the TLS communication are strong enough to resist attacks. Key sizes of 2048 bits or higher are recommended.
  • Regularly update software and systems: Regularly update software and systems to ensure that the latest security patches are applied and known vulnerabilities are addressed.

References

Taxonomies

Explanation & Prevention

Training

Weak SSL/TLS protocol in libcurl

This rule detects the use of TLS versions 1.1 or lower. Using TLS versions 1.0 and 1.1 can potentially be insecure, especially if you are the client. There are multiple attacks against TLS versions 1.0, and 1.1.

There are mitigations against some of the exploits listed above, but it cannot be verified that both users on either side of the TLS connection have deployed such mitigations.

Due to the above, and due to the large number of vulnerabilities that target these TLS versions, it is highly recommended that you upgrade your connection to at least TLS 1.2. The use of SSLv2, and SSLv3 is strongly discouraged.

Note that, unless specified, libcurl will use CURL_SSLVERSION_DEFAULT for the default acceptable version, which accepts TLS 1.0 as the minimum acceptable version. Refer to the libcurl documentation for additional details.

Option A: Specify CURL_SSLVERSION_TLSv1_2 for CURLOPT_SSLVERSION (default case)

  1. Go through the issues that GuardRails identified in the PR, for a pattern similar to the following:

    #include <curl/curl.h>

    CURL *curl;
    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();

    // CURL_SSLVERSION_DEFAULT is the default option for CURLOPT_SSLVERSION
    // It means legacy versions of TLS, in particular, TLS 1.0 and TLS 1.1 are enabled

    // Insecure example
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");

    curl_easy_perform(curl);
  2. Specify the accepted version of TLS to 1.2 and above

    #include <curl/curl.h>

    CURL *curl;
    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");

    // Secure example
    curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);

    // Perform the request
    curl_easy_perform(curl);
  3. Test it

  4. Ship it 🚢 and relax 🌴

Option B: Specify CURL_SSLVERSION_TLSv1_2 for CURLOPT_SSLVERSION (non-default case)

  1. Go through the issues that GuardRails identified in the PR, for a pattern similar to the following:

    #include <curl/curl.h>

    CURL *curl;
    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();

    // Insecure example
    curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);

    curl_easy_perform(curl);
  2. Specify the accepted version of TLS to 1.2 and above

    #include <curl/curl.h>

    CURL *curl;
    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");

    // Secure example
    curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);

    // Perform the request
    curl_easy_perform(curl);
  3. Test it

  4. Ship it 🚢 and relax 🌴

Weak SSL/TLS protocol in OpenSSL

This rule detects the use/support of weak SSL/TLS protocols in OpenSSL. By default (refer to the documentation here), the version-flexible function TLS_method() supports SSLv3, TLSv1, TLSv1.1, TLSv1.2 and TLSv1.3. TLSv1.1, which many of these containing known vulnerabilities.

There are mitigations against some of the exploits listed above, but it cannot be verified that both users on either side of the TLS connection have deployed such mitigations.

Due to the above, and due to the large number of vulnerabilities that target these SSL/TLS versions (SSLv3, TLSv1, TLSv1.1), it is highly recommended that you upgrade your connection to at least TLS 1.2. Applications should typically use SSL_CTX_set_min_proto_version to set the minimum protocol to at least TLS1_2_VERSION.

Option A: Set the minimum protocol to TLSv1.2

  1. Go through the issues that GuardRails identified in the PR, for a pattern similar to the following:

    #include <openssl/ssl.h>

    // Insecure example
    // Legacy versions SSLv3, TLSv1 and TLSv1.1 are enabled
    const SSL_METHOD *method = TLS_method();
    SSL_CTX *ctx = SSL_CTX_new(method);

    SSL *ssl = SSL_new(ctx);
    SSL_connect(ssl);
  2. Specify the minimum protocol to be TLS1_2_VERSION using SSL_CTX_set_min_proto_version

    #include <openssl/ssl.h>

    const SSL_METHOD *method = TLS_method();

    SSL_CTX *ctx = SSL_CTX_new(method);

    // Secure example
    SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);

    SSL *ssl = SSL_new(ctx);
    SSL_connect(ssl);
  3. Test it

  4. Ship it 🚢 and relax 🌴