Insecure SSL

ID

swift.insecure_ssl

Severity

critical

Resource

Misconfiguration

Language

Swift

Tags

CWE:295, CWE:757, MASWE:0047, NIST.SP.800-53, OWASP:2021:A2, OWASP:2021:A7, PCI-DSS:6.5.4

Description

Insecure SSL refers to the usage of insecure configurations with SSL/TLS protocols that could compromise data confidentiality, integrity, or authenticity while in transit.

Developers might inadvertently create SSL/TLS connections without enforcing adequate security measures, risking man-in-the-middle (MITM) attacks.

Rationale

The danger of insecure SSL configurations generally stem from mistakes such as using outdated SSL/TLS protocols, disabling certificate validation, or failing to verify hostnames. Code snippets that disable these validations are useful for quick testing. However, leaving them in production can create serious security vulnerabilities.

SSL/TLS security is undermined by:

  1. Trusting all certificates, effectively ignoring trust chain verification.

  2. Allowing all hostnames to be valid, circumventing checks for URL domain validity and authenticity.

  3. Disabling Certificate Revocation List (CRL) or Online Certificate Status Protocol (OCSP) checks for certificate revocation.

  4. Using insecure protocols like SSLv3 and TLS 1.0 / 1.1.

In Swift, TLS/SSL security is primarily configured via URLSessionConfiguration. Weak TLS protocol versions (TLS 1.0, TLS 1.1) and disabled certificate validation significantly reduce security by allowing attackers to intercept or manipulate encrypted communications.

A rather trivial example of vulnerable configuration looks like this:

import Foundation

func createInsecureURLSession() -> URLSession {
    let config = URLSessionConfiguration.default

    // FLAW: Using insecure TLS 1.0 protocol
    config.tlsMinimumSupportedProtocolVersion = .TLSv10

    return URLSession(configuration: config)
}

In this code, the minimum supported TLS version is explicitly set to TLS 1.0, a deprecated protocol with known vulnerabilities. This allows man-in-the-middle attacks and protocol downgrade attacks.

Another common vulnerability is setting the maximum supported version to a weak protocol:

import Foundation

func createWeakTLSSession() -> URLSession {
    let config = URLSessionConfiguration.default

    // FLAW: Limiting maximum TLS version to TLS 1.1
    config.tlsMaximumSupportedProtocolVersion = .TLSv11

    return URLSession(configuration: config)
}

This configuration prevents the use of modern, secure protocols like TLS 1.2 and TLS 1.3, exposing the application to known attacks against older protocol versions.

Remediation

To remediate issues related to insecure SSL configurations:

  1. Use a Trust Store: Always configure the software to use a well-maintained trust store with up-to-date certificates. Avoid using custom trust managers that disable certificate validation.

  2. Enforce Hostname Verification: Ensure that hostname verification is enabled so that the TLS clients can match the server’s hostname against its certificate’s naming information.

  3. Keep Protocols and Libraries Up-to-date: Regularly update the runtime environment and any third-party libraries to ensure compatibility with the latest secure protocols (e.g., TLS 1.2 or 1.3), avoiding outdated versions like SSLv3.

  4. Review Libraries for Vulnerabilities: Regularly audit the libraries and dependencies used in your software projects for known vulnerabilities.

In Swift, the default system configuration for URLSession already uses secure TLS settings. The recommended approach is to either:

  1. Use system defaults (preferred):

    import Foundation
    
    func createSecureURLSession() -> URLSession {
        // FIX: Use default configuration (secure by default)
        let config = URLSessionConfiguration.default
        // No need to set TLS version - defaults are secure
        return URLSession(configuration: config)
    }
  2. Explicitly set modern TLS versions:

    import Foundation
    
    func createExplicitlySecureURLSession() -> URLSession {
        let config = URLSessionConfiguration.default
    
        // FIX: Explicitly require TLS 1.2 or higher
        config.tlsMinimumSupportedProtocolVersion = .TLSv12
    
        // Optionally, enforce TLS 1.3
        // config.tlsMinimumSupportedProtocolVersion = .TLSv13
    
        return URLSession(configuration: config)
    }

Available TLS Protocol Versions

Swift provides the following TLS protocol version constants via tls_protocol_version_t:

  • .TLSv10 - TLS 1.0 (insecure, deprecated)

  • .TLSv11 - TLS 1.1 (insecure, deprecated)

  • .TLSv12 - TLS 1.2 (secure, minimum recommended)

  • .TLSv13 - TLS 1.3 (most secure, recommended)

Certificate Validation

Never disable certificate validation in production code. The default URLSession configuration performs proper certificate validation. If you need custom certificate handling, implement proper validation logic:

import Foundation

class SecureURLSessionDelegate: NSObject, URLSessionDelegate {
    func urlSession(_ session: URLSession,
                    didReceive challenge: URLAuthenticationChallenge,
                    completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {

        // FIX: Proper certificate validation
        guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
              let serverTrust = challenge.protectionSpace.serverTrust else {
            completionHandler(.cancelAuthenticationChallenge, nil)
            return
        }

        // Perform additional validation if needed
        // Default validation is already performed by the system
        completionHandler(.performDefaultHandling, nil)
    }
}

Never accept all certificates unconditionally:

// VULNERABLE: DO NOT DO THIS
func urlSession(_ session: URLSession,
                didReceive challenge: URLAuthenticationChallenge,
                completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    // FLAW: Accepts any certificate
    if let serverTrust = challenge.protectionSpace.serverTrust {
        let credential = URLCredential(trust: serverTrust)
        completionHandler(.useCredential, credential)  // INSECURE
    }
}

Configuration

This detector does not need any configuration.

References