-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Java: An experimental query for ignored hostname verification #6443
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Java: An experimental query for ignored hostname verification #6443
Conversation
Wouldn't it make sense to filter out cases where the "ignored" value is returned from/inside another |
java/ql/src/experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.qhelp
Outdated
Show resolved
Hide resolved
java/ql/src/experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.qhelp
Outdated
Show resolved
Hide resolved
java/ql/src/experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.qhelp
Outdated
Show resolved
Hide resolved
java/ql/src/experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.ql
Outdated
Show resolved
Hide resolved
@artem-smotrakov: there are currently quite a few false positives because the |
5978475
to
60a0021
Compare
I've addressed your comments @Marcono1234 . Thank you! |
@intrigus-lgtm Makes sense to me. I've updated the query to ignore calls wrapped by another hostname verifier. Thank you for the suggestion! |
@kevinbackhouse I've addressed @intrigus-lgtm's comment above, and that fixes the false-positive in |
Thank you all for the review, and sorry for the delay in addressing your comments! |
@artem-smotrakov: I'm sorry for not looking at this until now. The number of false positives has gone down, but I'm still seeing a lot of similar results to before. For example: https://lgtm.com/query/6043668221389765828/ The vast majority of the false positives involve https://lgtm.com/query/6215280566352377624/ |
@kevinbackhouse No problem. I am also replying pretty slow, unfurtunately.
Those are alerts in tests. I suppose the database should have been built without the test code. Do you think it makes sense to make the query aware of testing/mocking frameworks?
That is a good one. I've fixed it. I am looking into this one. |
- Added IgnoredHostnameVerification.ql - Added a qhelp file with examples - Added tests
- Added IgnoredHostnameVerification.ql - Added a qhelp file with examples - Added tests
84b5c47
to
825fe17
Compare
@kevinbackhouse I've fixed this one. I am still now sure that it is right to make the query aware of |
@artem-smotrakov: I'm afraid there's still a very large number of results, all of which look like false positives to me. I think it might be better to change this query so that it only warns when the |
Hi @kevinbackhouse Sure, we can trade off TPs for FPs. Let me see what I can do. If you could share those results that you think might be FPs, that would be great. |
…Verifier.verify()
@kevinbackhouse I've updated the query to check if the result of hostname verification is used in a general expression, if-statement and a method call. Technically, the result may be used in other statement like while (!result) {
throw new Exception("Failed");
} but they look pretty exotic, so I am not sure if we want to cover them. Please let me know what you think. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added some inline comments, but otherwise LGTM.
@@ -0,0 +1,8 @@ | |||
SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(host, port); | |||
socket.startHandshake(); | |||
boolean successful = verifier.verify(host, socket.getSession()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would make sense to clarify what verifier
is. Like adding a line that at least makes clear it's a HostnameVerifier
object. Likewise in IgnoredHostnameVerification.java
.
java/ql/src/experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.qhelp
Outdated
Show resolved
Hide resolved
|
||
/** The `HostnameVerifier.verify()` method. */ | ||
private class HostnameVerifierVerifyMethod extends Method { | ||
HostnameVerifierVerifyMethod() { | ||
this.getDeclaringType().getASupertype*().hasQualifiedName("javax.net.ssl", "HostnameVerifier") and | ||
this.hasStringSignature("verify(String, SSLSession)") | ||
} | ||
} | ||
|
||
/** Defines `HostnameVerifier.verity()` calls that is not wrapped in another `HostnameVerifier`. */ | ||
private class HostnameVerificationCall extends MethodAccess { | ||
HostnameVerificationCall() { | ||
this.getMethod() instanceof HostnameVerifierVerifyMethod and | ||
not this.getCaller() instanceof HostnameVerifierVerifyMethod | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's reuse already defined types.
/** The `HostnameVerifier.verify()` method. */ | |
private class HostnameVerifierVerifyMethod extends Method { | |
HostnameVerifierVerifyMethod() { | |
this.getDeclaringType().getASupertype*().hasQualifiedName("javax.net.ssl", "HostnameVerifier") and | |
this.hasStringSignature("verify(String, SSLSession)") | |
} | |
} | |
/** Defines `HostnameVerifier.verity()` calls that is not wrapped in another `HostnameVerifier`. */ | |
private class HostnameVerificationCall extends MethodAccess { | |
HostnameVerificationCall() { | |
this.getMethod() instanceof HostnameVerifierVerifyMethod and | |
not this.getCaller() instanceof HostnameVerifierVerifyMethod | |
} | |
import semmle.code.java.security.Encryption | |
/** Defines `HostnameVerifier.verity()` calls that is not wrapped in another `HostnameVerifier`. */ | |
private class HostnameVerificationCall extends MethodAccess { | |
HostnameVerificationCall() { | |
this.getMethod() instanceof HostnameVerifierVerify and | |
not this.getCaller() instanceof HostnameVerifierVerify | |
} |
java/ql/src/experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.qhelp
Outdated
Show resolved
Hide resolved
java/ql/src/experimental/Security/CWE/CWE-297/IgnoredHostnameVerification.ql
Outdated
Show resolved
Hide resolved
|
||
/** Holds if the result of the call is not used. */ | ||
predicate isIgnored() { | ||
not exists(Expr expr, IfStmt ifStmt, MethodAccess ma | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is relying on the CodeQL optimiser not to compute the product of all Exprs, IfStmts and MethodAccesses because there are disjuncts where each of them are in scope but unused.
Instead, do something like
not exists(Expr e | this = e.getAChildExpr()) and
not exists(IfStmt ifStmt | ...
However you can also determine if a method call is unused like this by checking whether it's the direct child of an ExprStmt--
this = any(ExprStmt es).getExpr()
All other kinds of use (assignment, passing to a method call, direct use in a conditional...) will be nested within some other statement or expression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestions!
Co-authored-by: Tony Torralba <atorralba@users.noreply.github.com> Co-authored-by: Chris Smowton <smowton@github.com>
@atorralba @smowton Thanks for the review. I've applied your suggestions. |
I've removed the redundant conditions from |
Thanks! |
The method
HostnameVerifier.verify()
checks that the hostname from the server's certificate matches the server hostname after an HTTPS connection is established. The method returns true if the hostname is acceptable and false otherwise. The contract of the method does not require it to throw an exception if the verification failed. Therefore, a caller has to check the result and drop the connection if the hostname verification failed.I'd like to add an experimental query that checks whether the result of hostname verification is checked or not. Currently, the query requires en exception to be thrown based on the result of
HostnameVerifier.verify()
. This makes the query pretty strict. It may result in false positives when an application checks the result of hostname verification but reports a failure without throwing an exception right away. The requirement may be softened. For example, the query can only check that the returned value is evaluated in an if-block. Looking forward to your feedback.The query detects CVE-2019-11777 in the Eclipse Paho Java client library version 1.2.0.