Files
codeql/java/ql/test/query-tests/security/CWE-297/UnsafeHostnameVerification.java

120 lines
5.2 KiB
Java

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import java.security.cert.Certificate;
public class UnsafeHostnameVerification {
private static final boolean DISABLE_VERIFICATION = true;
/**
* Test the implementation of trusting all hostnames as an anonymous class
*/
public void testTrustAllHostnameOfAnonymousClass() {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { // $
@Override
public boolean verify(String hostname, SSLSession session) {
return true; // BAD, always returns true
}
}); // $ Alert[java/unsafe-hostname-verification]
}
/**
* Test the implementation of trusting all hostnames as a lambda.
*/
public void testTrustAllHostnameLambda() {
HttpsURLConnection.setDefaultHostnameVerifier((name, s) -> true); // $ Alert[java/unsafe-hostname-verification] // BAD, always returns true
}
/**
* Test an all-trusting hostname verifier that is guarded by a flag
*/
public void testGuardedByFlagTrustAllHostname() {
if (DISABLE_VERIFICATION) {
HttpsURLConnection.setDefaultHostnameVerifier(ALLOW_ALL_HOSTNAME_VERIFIER); // GOOD: The all-trusting
// hostname verifier is guarded
// by a feature flag
}
}
public void testGuardedByFlagAccrossCalls() {
if (DISABLE_VERIFICATION) {
functionThatActuallyDisablesVerification();
}
}
private void functionThatActuallyDisablesVerification() {
HttpsURLConnection.setDefaultHostnameVerifier((name, s) -> true); // $ Alert[java/unsafe-hostname-verification] // GOOD [but detected as BAD], because we only
// check guards inside a function
// and not across function calls. This is considerer GOOD because the call to
// `functionThatActuallyDisablesVerification` is guarded by a feature flag in
// `testGuardedByFlagAccrossCalls`.
// Although this is not ideal as another function could directly call
// `functionThatActuallyDisablesVerification` WITHOUT checking the feature flag.
}
public void testTrustAllHostnameDependingOnDerivedValue() {
String enabled = System.getProperty("disableHostnameVerification");
if (Boolean.parseBoolean(enabled)) {
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true); // GOOD, because it depends on a
// feature
// flag.
}
}
public void testTrustAllHostnameWithExceptions() {
HostnameVerifier verifier = new HostnameVerifier() { // $
@Override
public boolean verify(String hostname, SSLSession session) {
try { verify(hostname, session.getPeerCertificates()); } catch (Exception e) { throw new RuntimeException(); }
return true; // GOOD [but detected as BAD]. The verification of the certificate is done in
// another method and
// in the case of a mismatch, an `Exception` is thrown so the `return true`
// statement never gets executed.
}
// Black-box method that properly verifies the certificate but throws an
// `Exception` in the case of a mismatch.
private void verify(String hostname, Certificate[] certs) {
}
}; // $ Source[java/unsafe-hostname-verification]
HttpsURLConnection.setDefaultHostnameVerifier(verifier); // $ Alert[java/unsafe-hostname-verification]
}
/**
* Test the implementation of trusting all hostnames as a variable
*/
public void testTrustAllHostnameOfVariable() {
HostnameVerifier verifier = new HostnameVerifier() { // $
@Override
public boolean verify(String hostname, SSLSession session) {
return true; // BAD, always returns true
}
}; // $ Source[java/unsafe-hostname-verification]
HttpsURLConnection.setDefaultHostnameVerifier(verifier); // $ Alert[java/unsafe-hostname-verification]
}
public static final HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true; // BAD, always returns true
}
};
private static class AlwaysTrueVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
return true; // BAD, always returns true
}
}
/**
* Same as testTrustAllHostnameOfAnonymousClass, but with a named class.
* This is for testing the diff-informed functionality of the query.
*/
public void testTrustAllHostnameOfNamedClass() {
HttpsURLConnection.setDefaultHostnameVerifier(new AlwaysTrueVerifier()); // $ Alert[java/unsafe-hostname-verification]
}
}