The following sample code demonstrates how to connect to a badssl server that delivers a certificate with a wrong or invalid hostname using SSLSocket, which inherently doesn't perform any hostname validation checks.
Note: The connection succeeds even if the app has a fully secure Network Security Configuration (NSC) in place because SSLSocket is not affected by it.
packageorg.owasp.mastestappimportandroid.content.Contextimportjava.io.BufferedReaderimportjava.io.InputStreamReaderimportjavax.net.ssl.SSLSocketimportjavax.net.ssl.SSLSocketFactoryclassMastgTest(privatevalcontext:Context){funmastgTest():String{varsocket:SSLSocket? =nullreturntry{// Use the default SSLSocketFactoryvalsslSocketFactory=SSLSocketFactory.getDefault()asSSLSocketFactory// Connect to the server using SSLSocketvalhost="wrong.host.badssl.com"valport=443socket=sslSocketFactory.createSocket(host,port)asSSLSocket// Start the handshakesocket.startHandshake()// Send an HTTP GET requestvalrequest="GET / HTTP/1.1\r\nHost: $host\r\nConnection: close\r\n\r\n"valout=socket.outputStreamout.write(request.toByteArray())out.flush()// Read the response (this will read until the server closes)valreader=BufferedReader(InputStreamReader(socket.inputStream))valresponse=reader.readText()"Connection Successful: ${response.substring(0,minOf(200,response.length))}"}catch(e:Exception){e.printStackTrace()"Connection Failed: ${e::class.simpleName} - ${e.message}"}finally{// Clean up: close the socketsocket?.let{try{it.close()}catch(_:Exception){}}}}}
packageorg.owasp.mastestapp;importandroid.content.Context;importandroidx.compose.runtime.ComposerKt;importjava.io.BufferedReader;importjava.io.InputStreamReader;importjava.io.OutputStream;importjava.net.Socket;importjavax.net.SocketFactory;importjavax.net.ssl.SSLSocket;importjavax.net.ssl.SSLSocketFactory;importkotlin.Metadata;importkotlin.io.TextStreamsKt;importkotlin.jvm.internal.Intrinsics;importkotlin.jvm.internal.Reflection;importkotlin.text.Charsets;/* compiled from: MastgTest.kt */@Metadata(d1={"\u0000\u0018\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0000\b\u0007\u0018\u00002\u00020\u0001B\r\u0012\u0006\u0010\u0002\u001a\u00020\u0003¢\u0006\u0002\u0010\u0004J\u0006\u0010\u0005\u001a\u00020\u0006R\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006\u0007"},d2={"Lorg/owasp/mastestapp/MastgTest;","","context","Landroid/content/Context;","(Landroid/content/Context;)V","mastgTest","","app_debug"},k=1,mv={1,9,0},xi=48)/* loaded from: classes4.dex */publicfinalclassMastgTest{publicstaticfinalint$stable=8;privatefinalContextcontext;publicMastgTest(Contextcontext){Intrinsics.checkNotNullParameter(context,"context");this.context=context;}publicfinalStringmastgTest(){Stringstr;SSLSocketsocket=null;try{try{SocketFactorysocketFactory=SSLSocketFactory.getDefault();Intrinsics.checkNotNull(socketFactory,"null cannot be cast to non-null type javax.net.ssl.SSLSocketFactory");SSLSocketFactorysslSocketFactory=(SSLSocketFactory)socketFactory;SocketcreateSocket=sslSocketFactory.createSocket("wrong.host.badssl.com",443);Intrinsics.checkNotNull(createSocket,"null cannot be cast to non-null type javax.net.ssl.SSLSocket");socket=(SSLSocket)createSocket;socket.startHandshake();Stringrequest="GET / HTTP/1.1\r\nHost: wrong.host.badssl.com\r\nConnection: close\r\n\r\n";OutputStreamout=socket.getOutputStream();byte[]bytes=request.getBytes(Charsets.UTF_8);Intrinsics.checkNotNullExpressionValue(bytes,"this as java.lang.String).getBytes(charset)");out.write(bytes);out.flush();BufferedReaderreader=newBufferedReader(newInputStreamReader(socket.getInputStream()));Stringresponse=TextStreamsKt.readText(reader);StringBuilderappend=newStringBuilder().append("Connection Successful: ");Stringsubstring=response.substring(0,Math.min(ComposerKt.invocationKey,response.length()));Intrinsics.checkNotNullExpressionValue(substring,"this as java.lang.String…ing(startIndex, endIndex)");str=append.append(substring).toString();try{socket.close();}catch(Exceptione){}}catch(Exceptione2){e2.printStackTrace();str="Connection Failed: "+Reflection.getOrCreateKotlinClass(e2.getClass()).getSimpleName()+" - "+e2.getMessage();if(socket!=null){SSLSocketit=socket;try{it.close();}catch(Exceptione3){}}}returnstr;}catch(Throwableth){if(socket!=null){SSLSocketit2=socket;try{it2.close();}catch(Exceptione4){}}throwth;}}}
rules:-id:mastg-android-ssl-socket-hostnameverifierseverity:WARNINGlanguages:-javametadata:summary:ThisrulesscansfortheusageofSSLSocketAPIwithaHostnameVerifier.message:"Detected usage of SSLSocket API with or without a HostnameVerifier"match:any:-pattern:SSLSocketFactory.getDefault()-pattern:(SSLSocketFactory)$_-pattern:$SF.createSocket(...)-pattern:HttpsURLConnection.getDefaultHostnameVerifier()-pattern:$HNV.verify($_,$_)
The test case fails due to the missing HostnameVerifier.
Note: If the app were to use a HostnameVerifier, the connection would abort with an exception like the following, which can be read in the logcat output:
javax.net.ssl.SSLException: Hostname verification failed for host: wrong.host.badssl.com