Checker UnsafeConnection

belongs to group Basic
Identify potentially vulnerable android connections

Frameworks supported by this checker

  • android up to API level 28

Warnings generated by this checker

  • AllowAllHostnameVerifierWarning: an unsafe method is used for verifying a hostname [ CWE287 ]
  • AllowAllTrustVerifierWarning: an unsafe method is used for verifying a certificate [ CWE295 ]
  • BadHostnameVerifierWarning: a method intended for hostname verification always returns true [ CWE287 ]
  • BadTrustVerifierWarning: an unsafe method is used for verifying a certificate [ CWE295 ]
  • HostnameNotVerifiedWarning: a hostname is never verified [ CWE295 ]
  • InsecureSocketFactoryWarning: an insecure socket factory is used [ CWE295 ]
  • NotRecommendedHardwareIdFromFieldWarning: a field containing a hardware identifier is used [ CWE200 ]
  • NotRecommendedHardwareIdFromParameterWarning: a method that returns a hardware identifier is invoked [ CWE200 ]
  • NotRecommendedHardwareIdWarning: a method that returns a hardware identifier is invoked [ CWE200 ]

Options accepted by this checker

  • none

Annotations understood by this checker

  • @com.juliasoft.julia.checkers.unsafeConnection.ChecksPrincipalTrust
  • @com.juliasoft.julia.checkers.unsafeConnection.VerifiesHostname
  • @com.juliasoft.julia.checkers.unsafeConnection.YieldsInsecureSSLSocketFactory
  • @com.juliasoft.julia.checkers.unsafeConnection.YieldsNotRecommendedHardwareId


Description

This checker searches mostly for troubles in SSL/TLS connections, since this could lead to security breaches. It also checks that hardware identifiers are only used when strictly necessary.

Action: Always use host verifiers and trust managers that actually perform some verification. Always verify a hostname if the socket creation process does not do that. Use only secure SSL socket factories. Prefer advertising or analytics device IDs to hardware IDs.

Examples

Consider the following classes:

package com.juliasoft.julia.tests.checks.unsafeConnection;

import com.google.android.gms.common.GooglePlayServicesNotAvailableException;

import android.os.Build;
import android.telephony.TelephonyManager;
import android.provider.Settings;

public class HardwareIDs {
	public void hardwareIds() {
		System.out.println(Build.SERIAL); 
		TelephonyManager.getDefault().getDeviceId();
		Settings.Secure.getString(null, "ANDROID_ID");
	}
	
	public void problemsInsideExceptionHandler() {
		try {
			TelephonyManager.getDefault().getDeviceId(); 
		} catch (GooglePlayServicesNotAvailableException e) {
			TelephonyManager.getDefault().getDeviceId(); 
		}
	}
} 
package com.juliasoft.julia.tests.checks.unsafeConnection;

import java.io.IOException;
import java.net.InetAddress;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.SocketFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.X509TrustManager;

import android.net.SSLCertificateSocketFactory;
import android.net.SSLSessionCache;

public class AuthenticationVerification {
	public static void verifier(String hostname, SSLSession session) {
		new HostnameVerifier() {
			@Override
			public boolean verify(String hostname, SSLSession session) { 
				return true; 
			}
		}.verify(hostname, session); 
	}
	
	public static void manager(X509Certificate[] serverChain, X509Certificate[] clientChain, String authType) throws CertificateException {
		new X509TrustManager() {
			@Override
			public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
				 
			}

			@Override
			public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
				 
			}

			@Override
			public X509Certificate[] getAcceptedIssuers() {
				return new X509Certificate[0];
			}
		}.checkServerTrusted(serverChain, authType); 
	}
	
	public static void sockets(SSLSessionCache cache) throws IOException {
		SocketFactory factory = SSLCertificateSocketFactory.getInsecure(100, cache);
		InetAddress addr = InetAddress.getByName("www.juliasoft.com");
		factory.createSocket(addr, 100); 
	}
} 

This checker issues the following warnings:

HardwareIDs.java:11: [UnsafeConnection: NotRecommendedHardwareIdFromFieldWarning] Using this device identifier is not recommended: you should rely on other identifiers
HardwareIDs.java:12: [UnsafeConnection: NotRecommendedHardwareIdWarning] This call to method "getDeviceId" retieves a device identifier that is not recommended: you should rely on other identifiers
HardwareIDs.java:13: [UnsafeConnection: NotRecommendedHardwareIdFromParameterWarning] Providing 'ANDROID_ID' to method "getString" as actual parameter "name" causes the retrieval of a device identifier that is not recommended: you should rely on other identifiers
HardwareIDs.java:18: [UnsafeConnection: NotRecommendedHardwareIdWarning] This call to method "getDeviceId" retieves a device identifier that is not recommended: you should rely on other identifiers
AuthenticationVerification.java:21: [UnsafeConnection: BadHostnameVerifierWarning] This implementation of hostname verifier always returns true and therefore is not safe for hostname verification
AuthenticationVerification.java:23: [UnsafeConnection: AllowAllHostnameVerifierWarning] Method "verify" always returns true and therefore is not safe for hostname verification
AuthenticationVerification.java:30: [UnsafeConnection: BadTrustVerifierWarning] This implementation of trust manager never throws a CertificateException: this will result in trusting all certificates
AuthenticationVerification.java:35: [UnsafeConnection: BadTrustVerifierWarning] This implementation of trust manager never throws a CertificateException: this will result in trusting all certificates
AuthenticationVerification.java:42: [UnsafeConnection: AllowAllTrustVerifierWarning] Method "checkServerTrusted" never throws a CertificateException: this will result in trusting all certificates
AuthenticationVerification.java:46: [UnsafeConnection: InsecureSocketFactoryWarning] This call yields a socket factory with SSL/TLS checks disabled: use SSLCertificateSocketFactory.getDefault() instead
AuthenticationVerification.java:48: [UnsafeConnection: HostnameNotVerifiedWarning] Method "createSocket" does not verify the hostname provided as actual parameter "addr": you should verify it by other means before using it

The first four warnings are all relative to the usage of a device identifier that should not be used other than for high value fraud prevention and advanced telephony use-cases. If this is not the case, you should rely on other identifiers, like AdvertisingIdClient.Info.getId() for advertisement or InstanceId.getId() for analytics. Note that these types of warnings are switched off inside exception handlers that catch a GooglePlayServicesNotAvailableException, since a device identifier could be needed to handle this exception (e.g., for giving feedback to the developer).

Warnings in AuthenticationVerification class are instead due to wrong verification of the principals involved in a network communication. This checker will warn on implementations of HostnameVerifier and X509TrustManager that do not perform any check (the former always returns true, while the latter never throws a CertificateException), as well as when one of such implementations is used. Moreover, it will warn also on insecure socket creation: when an insecure socket factory is retrieved, an InsecureSocketFactoryWarning is raised; besides, a HostnameNotVerifiedWarning is raised if a createSocket() method that receives an InetAddress as first parameter is invoked without an explicit verification of such address, since the hostname verification process is not executed during the socket creation.