{"record":{"id":"e364fa1c817abc9a","repo":"Tencent/VasSonic","slug":"cannot-verify-hostname","errorCode":null,"errorMessage":"Cannot verify hostname: ","messagePattern":"Cannot verify hostname: ","errorType":"exception","errorClass":"SSLPeerUnverifiedException","httpStatus":null,"severity":"error","filePath":"sonic-android/sdk/src/main/java/com/tencent/sonic/sdk/SonicSniSSLSocketFactory.java","lineNumber":192,"sourceCode":"     */\n    public static void verifyHostname(Socket socket, String hostname) throws IOException {\n        if (!(socket instanceof SSLSocket)) {\n            throw new IllegalArgumentException(\"Attempt to verify non-SSL socket\");\n        }\n\n        // The code at the start of OpenSSLSocketImpl.startHandshake()\n        // ensures that the call is idempotent, so we can safely call it.\n        SSLSocket ssl = (SSLSocket) socket;\n        ssl.startHandshake();\n\n        SSLSession session = ssl.getSession();\n        if (session == null) {\n            throw new SSLException(\"Cannot verify SSL socket without session\");\n        }\n\n        if (!HttpsURLConnection.getDefaultHostnameVerifier().verify(hostname, session)) {\n            SonicUtils.log(TAG, Log.ERROR, \"sonic SSL error:Cannot verify hostname\" + hostname + \")!\");\n            throw new SSLPeerUnverifiedException(\"Cannot verify hostname: \" + hostname);\n        }\n    }\n}\n","sourceCodeStart":174,"sourceCodeEnd":196,"githubUrl":"https://github.com/Tencent/VasSonic/blob/59936beff656d4b5718ff6444d6c5e001a2c5231/sonic-android/sdk/src/main/java/com/tencent/sonic/sdk/SonicSniSSLSocketFactory.java#L174-L196","documentation":"After obtaining the SSLSession, verifyHostname() runs the default HttpsURLConnection hostname verifier against it. If verification fails (certificate CN/SAN doesn't match the requested hostname), it throws SSLPeerUnverifiedException — protecting against MITM and hostname mismatches.","triggerScenarios":"The server presents a valid certificate that does not match the hostname used in the request — connecting by IP address, a hostname not in the cert's SAN, an internal hostname fronted by a generic cert, or DNS pointing to a different server.","commonSituations":"Hitting a server via its IP or an alias not listed in the certificate; expired/reissued certs missing the old SAN entries; proxies/gateways serving the wrong cert; testing against a staging server using production certs.","solutions":["Access the server using a hostname that exactly matches a SAN entry in its certificate","Fix the server certificate to include the hostname (add SAN entries) and redeploy","Remove IP-based URLs or custom host mappings that bypass proper hostname matching","If intentional (e.g. test environments), install a custom HostnameVerifier — but never disable verification in production"],"exampleFix":"// before\nURL url = new URL(\"https://10.0.0.5/api\"); // cert has no IP SAN -> throws\n// after\nURL url = new URL(\"https://api.example.com/api\"); // matches cert SAN","handlingStrategy":"try-catch","validationCode":"Certificate[] certs = ssl.getSession().getPeerCertificates();\n// check that host matches a SAN entry before connecting\n// e.g. hostname must equal one of the dNSName SANs in certs[0]","typeGuard":null,"tryCatchPattern":"try {\n  SonicSniSSLSocketFactory.verifyHostname(socket, host);\n} catch (SSLPeerUnverifiedException e) {\n  // hostname mismatch: do NOT proceed; alert or use the cert-matching hostname\n}","preventionTips":["Never connect by raw IP address for HTTPS unless the cert has an IP SAN","Keep server certificates' SAN entries in sync with all hostnames/aliases used","Test staging environments with certs matching the hostnames actually used"],"tags":["ssl","hostname-verification","certificate"],"backgroundTag":"certificate-hostname-mismatch","analyzedSha":"59936beff656d4b5718ff6444d6c5e001a2c5231","analyzedAt":"2026-09-08T10:27:05.448Z","contentChangedAt":"2026-09-08T10:27:05.448Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}