Skip to content

Commit 505d04b

Browse files
authored
Merge pull request #5102 from luchua-bc/java/main-method-in-servlet
Java: CWE-489 Query to detect main() method in servlets
2 parents 81b2931 + e34a203 commit 505d04b

36 files changed

+2538
-0
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
public class EJBMain implements SessionBean {
2+
/**
3+
* Create the session bean (empty implementation)
4+
*/
5+
public void ejbCreate() throws javax.ejb.CreateException {
6+
System.out.println("EJBMain:ejbCreate()");
7+
}
8+
9+
public void ejbActivate() throws javax.ejb.EJBException, java.rmi.RemoteException {
10+
}
11+
12+
public void ejbPassivate() throws javax.ejb.EJBException, java.rmi.RemoteException {
13+
}
14+
15+
public void ejbRemove() throws javax.ejb.EJBException, java.rmi.RemoteException {
16+
}
17+
18+
public void setSessionContext(SessionContext parm1) throws javax.ejb.EJBException, java.rmi.RemoteException {
19+
}
20+
21+
public String doService() {
22+
return null;
23+
}
24+
25+
// BAD - Implement a main method in session bean.
26+
public static void main(String[] args) throws Exception {
27+
EJBMain b = new EJBMain();
28+
b.doService();
29+
}
30+
31+
// GOOD - Not to have a main method in session bean.
32+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
2+
<qhelp>
3+
4+
<overview>
5+
<p>Debug code can create unintended entry points in a deployed Java EE web application therefore should never make into production. There is no reason to have a main method in a Java EE web application. Having a main method in the Java EE application increases the attack surface that an attacker can exploit to attack the application logic.</p>
6+
</overview>
7+
8+
<recommendation>
9+
<p>Remove the main method from enterprise beans.</p>
10+
</recommendation>
11+
12+
<example>
13+
<p>The following example shows two ways of implementing enterprise beans. In the 'BAD' case, a main method is implemented. In the 'GOOD' case, no main method is implemented.</p>
14+
<sample src="EJBMain.java" />
15+
</example>
16+
17+
<references>
18+
<li>
19+
SonarSource:
20+
<a href="https://rules.sonarsource.com/java/tag/owasp/RSPEC-2653">Web applications should not have a "main" method</a>
21+
</li>
22+
<li>
23+
Carnegie Mellon University:
24+
<a href="https://wiki.sei.cmu.edu/confluence/display/java/ENV06-J.+Production+code+must+not+contain+debugging+entry+points">ENV06-J. Production code must not contain debugging entry points</a>
25+
</li>
26+
</references>
27+
</qhelp>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* @name Main Method in Enterprise Java Bean
3+
* @description Java EE applications with a main method.
4+
* @kind problem
5+
* @id java/main-method-in-enterprise-bean
6+
* @tags security
7+
* external/cwe-489
8+
*/
9+
10+
import java
11+
import semmle.code.java.J2EE
12+
import MainLib
13+
14+
/** The `main` method in an Enterprise Java Bean. */
15+
class EnterpriseBeanMainMethod extends Method {
16+
EnterpriseBeanMainMethod() {
17+
this.getDeclaringType() instanceof EnterpriseBean and
18+
isMainMethod(this) and
19+
not isTestMethod(this)
20+
}
21+
}
22+
23+
from EnterpriseBeanMainMethod sm
24+
select sm, "Java EE application has a main method."
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/** Definitions related to the main method in a test program. */
2+
3+
import java
4+
5+
/** Holds if `m` is the main method of a Java class with the signature `public static void main(String[] args)`. */
6+
predicate isMainMethod(Method m) {
7+
m.hasName("main") and
8+
m.isStatic() and
9+
m.getReturnType() instanceof VoidType and
10+
m.isPublic() and
11+
m.getNumberOfParameters() = 1 and
12+
m.getParameter(0).getType() instanceof Array
13+
}
14+
15+
/**
16+
* Holds if `m` is a test method indicated by:
17+
* a) in a test directory such as `src/test/java`
18+
* b) in a test package whose name has the word `test`
19+
* c) in a test class whose name has the word `test`
20+
* d) in a test class implementing a test framework such as JUnit or TestNG
21+
*/
22+
predicate isTestMethod(Method m) {
23+
m.getDeclaringType().getName().toLowerCase().matches("%test%") or // Simple check to exclude test classes to reduce FPs
24+
m.getDeclaringType().getPackage().getName().toLowerCase().matches("%test%") or // Simple check to exclude classes in test packages to reduce FPs
25+
exists(m.getLocation().getFile().getAbsolutePath().indexOf("/src/test/java")) or // Match test directory structure of build tools like maven
26+
m instanceof TestMethod // Test method of a test case implementing a test framework such as JUnit or TestNG
27+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
public class WebComponentMain implements Servlet {
2+
// BAD - Implement a main method in servlet.
3+
public static void main(String[] args) throws Exception {
4+
// Connect to my server
5+
URL url = new URL("https://www.example.com");
6+
url.openConnection();
7+
}
8+
9+
// GOOD - Not to have a main method in servlet.
10+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
2+
<qhelp>
3+
4+
<overview>
5+
<p>Debug code can create unintended entry points in a deployed Java EE web application therefore should never make into production. There is no reason to have a main method in a Java EE web application. Having a main method in the Java EE application increases the attack surface that an attacker can exploit to attack the application logic.</p>
6+
</overview>
7+
8+
<recommendation>
9+
<p>Remove the main method from web components including servlets, filters, and listeners.</p>
10+
</recommendation>
11+
12+
<example>
13+
<p>The following example shows two ways of implementing web components. In the 'BAD' case, a main method is implemented. In the 'GOOD' case, no main method is implemented.</p>
14+
<sample src="WebComponentMain.java" />
15+
</example>
16+
17+
<references>
18+
<li>
19+
Fortify:
20+
<a href="https://vulncat.fortify.com/en/detail?id=desc.structural.java.j2ee_badpractices_leftover_debug_code">J2EE Bad Practices: Leftover Debug Code</a>
21+
</li>
22+
<li>
23+
SonarSource:
24+
<a href="https://rules.sonarsource.com/java/tag/owasp/RSPEC-2653">Web applications should not have a "main" method</a>
25+
</li>
26+
<li>
27+
Carnegie Mellon University:
28+
<a href="https://wiki.sei.cmu.edu/confluence/display/java/ENV06-J.+Production+code+must+not+contain+debugging+entry+points">ENV06-J. Production code must not contain debugging entry points</a>
29+
</li>
30+
</references>
31+
</qhelp>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* @name Main Method in Java EE Web Components
3+
* @description Java EE web applications with a main method.
4+
* @kind problem
5+
* @id java/main-method-in-web-components
6+
* @tags security
7+
* external/cwe-489
8+
*/
9+
10+
import java
11+
import semmle.code.java.frameworks.Servlets
12+
import MainLib
13+
14+
/** The java type `javax.servlet.Filter`. */
15+
class ServletFilterClass extends Class {
16+
ServletFilterClass() { this.getASupertype*().hasQualifiedName("javax.servlet", "Filter") }
17+
}
18+
19+
/** Listener class in the package `javax.servlet` and `javax.servlet.http` */
20+
class ServletListenerClass extends Class {
21+
// Various listener classes of Java EE such as ServletContextListener. They all have a name ending with the word "Listener".
22+
ServletListenerClass() {
23+
this.getASupertype*()
24+
.getQualifiedName()
25+
.regexpMatch([
26+
"javax\\.servlet\\.[a-zA-Z]+Listener", "javax\\.servlet\\.http\\.[a-zA-Z]+Listener"
27+
])
28+
}
29+
}
30+
31+
/** The `main` method in `Servlet` and `Action` of the Spring and Struts framework. */
32+
class WebComponentMainMethod extends Method {
33+
WebComponentMainMethod() {
34+
(
35+
this.getDeclaringType() instanceof ServletClass or
36+
this.getDeclaringType() instanceof ServletFilterClass or
37+
this.getDeclaringType() instanceof ServletListenerClass or
38+
this.getDeclaringType()
39+
.getASupertype*()
40+
.hasQualifiedName("org.apache.struts.action", "Action") or // Struts actions
41+
this.getDeclaringType()
42+
.getASupertype+()
43+
.hasQualifiedName("com.opensymphony.xwork2", "ActionSupport") or // Struts 2 actions
44+
this.getDeclaringType()
45+
.getASupertype+()
46+
.hasQualifiedName("org.springframework.web.struts", "ActionSupport") or // Spring/Struts 2 actions
47+
this.getDeclaringType()
48+
.getASupertype+()
49+
.hasQualifiedName("org.springframework.webflow.execution", "Action") // Spring actions
50+
) and
51+
isMainMethod(this) and
52+
not isTestMethod(this)
53+
}
54+
}
55+
56+
from WebComponentMainMethod sm
57+
select sm, "Web application has a main method."
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| ServiceBean.java:55:24:55:27 | main | Java EE application has a main method. |
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import javax.ejb.SessionBean;
2+
import javax.ejb.EJBException;
3+
import java.rmi.RemoteException;
4+
import javax.ejb.SessionContext;
5+
import javax.naming.Context;
6+
import javax.naming.InitialContext;
7+
8+
public class ServiceBean implements SessionBean {
9+
10+
protected SessionContext ctx;
11+
12+
private String _serviceName;
13+
14+
/**
15+
* Create the session bean (empty implementation)
16+
*/
17+
public void ejbCreate() throws javax.ejb.CreateException {
18+
System.out.println("ServiceBean:ejbCreate()");
19+
}
20+
21+
public void ejbActivate() throws javax.ejb.EJBException, java.rmi.RemoteException {
22+
}
23+
24+
public void ejbPassivate() throws javax.ejb.EJBException, java.rmi.RemoteException {
25+
}
26+
27+
public void ejbRemove() throws javax.ejb.EJBException, java.rmi.RemoteException {
28+
}
29+
30+
public void setSessionContext(SessionContext parm1) throws javax.ejb.EJBException, java.rmi.RemoteException {
31+
}
32+
33+
/**
34+
* Get service name
35+
* @return service name
36+
*/
37+
public String getServiceName() {
38+
return _serviceName;
39+
}
40+
41+
/**
42+
* Set service name
43+
* @param serviceName the service name
44+
*/
45+
public void setServiceName(String serviceName) {
46+
_serviceName = serviceName;
47+
}
48+
49+
/** Do service (no implementation) */
50+
public String doService() {
51+
return null;
52+
}
53+
54+
/** Local unit testing code */
55+
public static void main(String[] args) throws Exception {
56+
ServiceBean b = new ServiceBean();
57+
b.doService();
58+
}
59+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
experimental/Security/CWE/CWE-489/EJBMain.ql

0 commit comments

Comments
 (0)