Skip to content

Commit 6c24f36

Browse files
committed
Java: CWE-297 insecure JavaMail SSL configuration
1 parent 8d41ce1 commit 6c24f36

File tree

4 files changed

+220
-0
lines changed

4 files changed

+220
-0
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>JavaMail is commonly used in Java applications to send emails. There are popular third-party libraries like Apache Commons Email which are built on JavaMail and facilitate integration. Authenticated mail sessions require user credentials and mail sessions can require SSL/TLS authentication. It is a common security vulnerability that host-specific certificate data is not validated or is incorrectly validated. Failing to validate the certificate makes the SSL session susceptible to a man-in-the-middle attack.</p>
8+
<p>This query checks whether SSL certificate is validated when username/password is sent in authenticator and when SSL is enabled.</p>
9+
<p>The query has code for both plain JavaMail invocation and mailing through Apache SimpleMail to make it more comprehensive.</p>
10+
</overview>
11+
12+
<recommendation>
13+
<p>Validate SSL certificate when sensitive information is sent in email communications.</p>
14+
</recommendation>
15+
16+
<example>
17+
<p>The following two examples show two ways of configuring secure emails through JavaMail or Apache SimpleMail. In the 'BAD' case,
18+
credentials are sent in an SSL session without certificate validation. In the 'GOOD' case, the certificate is validated.</p>
19+
<sample src="JavaMail.java" />
20+
<sample src="SimpleMail.java" />
21+
</example>
22+
23+
<references>
24+
<li>
25+
<a href="https://cwe.mitre.org/data/definitions/297.html">CWE-297</a>
26+
<a href="https://issues.apache.org/jira/browse/LOG4J2-2819">Add support for specifying an SSL configuration for SmtpAppender (CVE-2020-9488)</a>
27+
<a href="https://rules.sonarsource.com/java/tag/owasp/RSPEC-4499">SMTP SSL connection should check server identity</a>
28+
</li>
29+
</references>
30+
</qhelp>
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/**
2+
* @id java/insecure-smtp-ssl
3+
* @name Insecure JavaMail SSL Configuration
4+
* @description Java application configured to use authenticated mail session over SSL does not validate the SSL certificate to properly ensure that it is actually associated with that host.
5+
* @kind problem
6+
* @tags security
7+
* external/cwe-297
8+
*/
9+
10+
import java
11+
12+
/**
13+
* The method to set Java properties
14+
*/
15+
class SetPropertyMethod extends Method {
16+
SetPropertyMethod() {
17+
this.hasName("setProperty") and
18+
this.getDeclaringType().hasQualifiedName("java.util", "Properties")
19+
or
20+
this.hasName("put") and
21+
this.getDeclaringType().getASourceSupertype*().hasQualifiedName("java.util", "Dictionary")
22+
}
23+
}
24+
25+
/**
26+
* The insecure way to set Java properties in mail sessions.
27+
* 1. Set the mail.smtp.auth property to provide the SMTP Transport with a username and password when connecting to the SMTP server or
28+
* set the mail.smtp.ssl.socketFactory/mail.smtp.ssl.socketFactory.class property to create an SMTP SSL socket.
29+
* 2. No mail.smtp.ssl.checkserveridentity property is enabled.
30+
*/
31+
predicate isInsecureMailPropertyConfig(VarAccess propertiesVarAccess) {
32+
exists(MethodAccess ma |
33+
ma.getMethod() instanceof SetPropertyMethod and
34+
ma.getQualifier() = propertiesVarAccess.getVariable().getAnAccess() and
35+
(
36+
getStringValue(ma.getArgument(0)).indexOf(".auth") != -1 and //mail.smtp.auth
37+
getStringValue(ma.getArgument(1)) = "true"
38+
or
39+
getStringValue(ma.getArgument(0)).indexOf(".socketFactory") != -1 //mail.smtp.socketFactory or mail.smtp.socketFactory.class
40+
)
41+
) and
42+
not exists(MethodAccess ma |
43+
ma.getMethod() instanceof SetPropertyMethod and
44+
ma.getQualifier() = propertiesVarAccess.getVariable().getAnAccess() and
45+
(
46+
getStringValue(ma.getArgument(0)).indexOf(".ssl.checkserveridentity") != -1 and //mail.smtp.ssl.checkserveridentity
47+
getStringValue(ma.getArgument(1)) = "true"
48+
)
49+
)
50+
}
51+
52+
/**
53+
* Helper method to get string value of an argument
54+
*/
55+
string getStringValue(Expr expr) {
56+
result = expr.(StringLiteral).getRepresentedString()
57+
or
58+
exists(Variable v | expr = v.getAnAccess() |
59+
result = getStringValue(v.getInitializer().(CompileTimeConstantExpr))
60+
)
61+
or
62+
result = getStringValue(expr.(AddExpr).getLeftOperand())
63+
or
64+
result = getStringValue(expr.(AddExpr).getRightOperand())
65+
}
66+
67+
/**
68+
* The JavaMail session class `javax.mail.Session`
69+
*/
70+
class MailSession extends RefType {
71+
MailSession() { this.getQualifiedName() = "javax.mail.Session" }
72+
}
73+
74+
/**
75+
* The class of Apache SimpleMail
76+
*/
77+
class SimpleMail extends RefType {
78+
SimpleMail() { this.getQualifiedName() = "org.apache.commons.mail.SimpleEmail" }
79+
}
80+
81+
/**
82+
* Has TLS/SSL enabled with SimpleMail
83+
*/
84+
predicate enableTLSWithSimpleMail(MethodAccess ma) {
85+
ma.getMethod().hasName("setSSLOnConnect") and
86+
ma.getArgument(0).(BooleanLiteral).getBooleanValue() = true
87+
}
88+
89+
/**
90+
* Has no certificate check
91+
*/
92+
predicate hasNoCertCheckWithSimpleMail(VarAccess va) {
93+
not exists(MethodAccess ma |
94+
ma.getQualifier() = va.getVariable().getAnAccess() and
95+
ma.getMethod().hasName("setSSLCheckServerIdentity") and
96+
ma.getArgument(0).(BooleanLiteral).getBooleanValue() = true
97+
)
98+
}
99+
100+
from MethodAccess ma
101+
where
102+
ma.getMethod().getDeclaringType() instanceof MailSession and
103+
ma.getMethod().getName() = "getInstance" and
104+
isInsecureMailPropertyConfig(ma.getArgument(0).(VarAccess))
105+
or
106+
enableTLSWithSimpleMail(ma) and hasNoCertCheckWithSimpleMail(ma.getQualifier().(VarAccess))
107+
select ma, "Java mailing has insecure SSL configuration"
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import java.util.Properties;
2+
3+
import javax.activation.DataSource;
4+
import javax.mail.Authenticator;
5+
import javax.mail.Message;
6+
import javax.mail.MessagingException;
7+
import javax.mail.PasswordAuthentication;
8+
import javax.mail.Session;
9+
10+
import org.apache.logging.log4j.util.PropertiesUtil;
11+
12+
class JavaMail {
13+
public static void main(String[] args) {
14+
// BAD: Don't have server certificate check
15+
{
16+
final Properties properties = PropertiesUtil.getSystemProperties();
17+
properties.put("mail.transport.protocol", "protocol");
18+
properties.put("mail.smtp.host", "hostname");
19+
properties.put("mail.smtp.socketFactory.class", "classname");
20+
21+
final Authenticator authenticator = buildAuthenticator("username", "password");
22+
if (null != authenticator) {
23+
properties.put("mail.smtp.auth", "true");
24+
}
25+
final Session session = Session.getInstance(properties, authenticator);
26+
}
27+
28+
// GOOD: Have server certificate check
29+
{
30+
final Properties properties = PropertiesUtil.getSystemProperties();
31+
properties.put("mail.transport.protocol", "protocol");
32+
properties.put("mail.smtp.host", "hostname");
33+
properties.put("mail.smtp.socketFactory.class", "classname");
34+
35+
final Authenticator authenticator = buildAuthenticator("username", "password");
36+
if (null != authenticator) {
37+
properties.put("mail.smtp.auth", "true");
38+
properties.put("mail.smtp.ssl.checkserveridentity", "true");
39+
}
40+
final Session session = Session.getInstance(properties, authenticator);
41+
}
42+
}
43+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import org.apache.commons.mail.DefaultAuthenticator;
2+
import org.apache.commons.mail.Email;
3+
import org.apache.commons.mail.EmailException;
4+
import org.apache.commons.mail.SimpleEmail;
5+
6+
class SimpleMail {
7+
public static void main(String[] args) throws EmailException {
8+
// BAD: Don't have setSSLCheckServerIdentity set or set as false
9+
{
10+
Email email = new SimpleEmail();
11+
email.setHostName("hostName");
12+
email.setSmtpPort(25);
13+
email.setAuthenticator(new DefaultAuthenticator("username", "password"));
14+
email.setSSLOnConnect(true);
15+
16+
//email.setSSLCheckServerIdentity(false);
17+
email.setFrom("fromAddress");
18+
email.setSubject("subject");
19+
email.setMsg("body");
20+
email.addTo("toAddress");
21+
email.send();
22+
}
23+
24+
// GOOD: Have setSSLCheckServerIdentity set to true
25+
{
26+
Email email = new SimpleEmail();
27+
email.setHostName("hostName");
28+
email.setSmtpPort(25);
29+
email.setAuthenticator(new DefaultAuthenticator("username", "password"));
30+
email.setSSLOnConnect(true);
31+
32+
email.setSSLCheckServerIdentity(true);
33+
email.setFrom("fromAddress");
34+
email.setSubject("subject");
35+
email.setMsg("body");
36+
email.addTo("toAddress");
37+
email.send();
38+
}
39+
}
40+
}

0 commit comments

Comments
 (0)