Skip to content

Commit a183b00

Browse files
committed
Query to detect main method in servlets
1 parent 649bd03 commit a183b00

File tree

10 files changed

+272
-0
lines changed

10 files changed

+272
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
public class ServletMain 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 web application therefore should never make into production. There is no reason to have a main method in a web application. Having a main method in a web 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="ServletMain.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: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* @name Main Method in Servlet
3+
* @description Jave EE web applications with a main method.
4+
* @kind problem
5+
* @id java/main-method-in-servlet
6+
* @tags security
7+
* external/cwe-489
8+
*/
9+
10+
import java
11+
import semmle.code.java.frameworks.Servlets
12+
13+
/** The java type `javax.servlet.Filter` */
14+
class ServletFilterClass extends Class {
15+
ServletFilterClass() { this.getASupertype*().hasQualifiedName("javax.servlet", "Filter") }
16+
}
17+
18+
/** Listener class in the package `javax.servlet` and `javax.servlet.http` */
19+
class ServletListenerClass extends Class {
20+
// Various listener classes of Java EE such as ServletContextListener. They all have a name ending with the word "Listener".
21+
ServletListenerClass() {
22+
this.getASupertype*()
23+
.getQualifiedName()
24+
.regexpMatch([
25+
"javax\\.servlet\\.[a-zA-Z]+Listener", "javax\\.servlet\\.http\\.[a-zA-Z]+Listener"
26+
])
27+
}
28+
}
29+
30+
/** The `main` method in `Servlet`. */
31+
class ServletMainMethod extends Method {
32+
ServletMainMethod() {
33+
(
34+
this.getDeclaringType() instanceof ServletClass or
35+
this.getDeclaringType() instanceof ServletFilterClass or
36+
this.getDeclaringType() instanceof ServletListenerClass
37+
) and
38+
this.hasName("main") and
39+
this.isStatic() and
40+
this.getReturnType() instanceof VoidType and
41+
this.isPublic() and
42+
this.getNumberOfParameters() = 1 and
43+
this.getParameter(0).getType() instanceof Array and
44+
not this.getDeclaringType().getName().matches("%Test%") // Simple check to exclude test classes to reduce FPs
45+
}
46+
}
47+
48+
from ServletMainMethod sm
49+
select sm, "Web application has a main method."
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import javax.servlet.ServletContextEvent;
2+
import javax.servlet.ServletContextListener;
3+
import java.net.URL;
4+
5+
public class ServletContextListenerMain implements ServletContextListener {
6+
@Override
7+
public void contextInitialized(ServletContextEvent sce) {
8+
System.out.println("listener starts to work!");
9+
}
10+
11+
@Override
12+
public void contextDestroyed(ServletContextEvent sce) {
13+
System.out.println("listener stopped!");
14+
}
15+
16+
// BAD - Implement a main method in servlet listener.
17+
public static void main(String[] args) {
18+
try {
19+
URL url = new URL("https://www.example.com");
20+
url.openConnection();
21+
} catch (Exception e) {
22+
e.printStackTrace();
23+
}
24+
}
25+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| ServletContextListenerMain.java:17:21:17:24 | main | Web application has a main method. |
2+
| ServletMain.java:28:21:28:24 | main | Web application has a main method. |
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import javax.servlet.Servlet;
2+
import javax.servlet.ServletRequest;
3+
import javax.servlet.ServletResponse;
4+
import javax.servlet.ServletException;
5+
import javax.servlet.ServletConfig;
6+
import java.io.IOException;
7+
import java.net.URL;
8+
9+
public class ServletMain implements Servlet {
10+
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
11+
}
12+
13+
public void init(ServletConfig servletConfig) throws ServletException {
14+
}
15+
16+
public ServletConfig getServletConfig() {
17+
return null;
18+
}
19+
20+
public String getServletInfo() {
21+
return null;
22+
}
23+
24+
public void destroy() {
25+
}
26+
27+
// BAD - Implement a main method in servlet.
28+
public static void main(String[] args) throws Exception {
29+
// Connect to my server
30+
URL url = new URL("https://www.example.com");
31+
url.openConnection();
32+
}
33+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
experimental/Security/CWE/CWE-489/ServletMain.ql
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright 2004 The Apache Software Foundation
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package javax.servlet;
19+
20+
/**
21+
* This is the event class for notifications about changes to
22+
* the servlet context of a web application.
23+
* @see ServletContextListener
24+
*
25+
* @since Servlet 2.3
26+
*/
27+
28+
public class ServletContextEvent extends java.util.EventObject {
29+
30+
/** Construct a ServletContextEvent from the given context.
31+
*
32+
* @param source - the ServletContext that is sending the event.
33+
*/
34+
public ServletContextEvent(ServletContext source) {
35+
super(source);
36+
}
37+
38+
/**
39+
* Return the ServletContext that changed.
40+
*
41+
* @return the ServletContext that sent the event.
42+
*/
43+
public ServletContext getServletContext () {
44+
return null;
45+
}
46+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright 2004 The Apache Software Foundation
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package javax.servlet;
19+
20+
import java.util.EventListener;
21+
22+
/**
23+
* Interface for receiving notification events about ServletContext
24+
* lifecycle changes.
25+
*
26+
* <p>In order to receive these notification events, the implementation
27+
* class must be either declared in the deployment descriptor of the web
28+
* application, annotated with {@link javax.servlet.annotation.WebListener},
29+
* or registered via one of the addListener methods defined on
30+
* {@link ServletContext}.
31+
*
32+
* <p>Implementations of this interface are invoked at their
33+
* {@link #contextInitialized} method in the order in which they have been
34+
* declared, and at their {@link #contextDestroyed} method in reverse
35+
* order.
36+
*
37+
* @see ServletContextEvent
38+
*
39+
* @since Servlet 2.3
40+
*/
41+
public interface ServletContextListener extends EventListener {
42+
43+
/**
44+
* Receives notification that the web application initialization
45+
* process is starting.
46+
*
47+
* <p>All ServletContextListeners are notified of context
48+
* initialization before any filters or servlets in the web
49+
* application are initialized.
50+
*
51+
* @param sce the ServletContextEvent containing the ServletContext
52+
* that is being initialized
53+
*
54+
* @implSpec
55+
* The default implementation takes no action.
56+
*/
57+
default public void contextInitialized(ServletContextEvent sce) {}
58+
59+
/**
60+
* Receives notification that the ServletContext is about to be
61+
* shut down.
62+
*
63+
* <p>All servlets and filters will have been destroyed before any
64+
* ServletContextListeners are notified of context
65+
* destruction.
66+
*
67+
* @param sce the ServletContextEvent containing the ServletContext
68+
* that is being destroyed
69+
*
70+
* @implSpec
71+
* The default implementation takes no action.
72+
*/
73+
default public void contextDestroyed(ServletContextEvent sce) {}
74+
}

0 commit comments

Comments
 (0)