Skip to content

Commit 645e896

Browse files
committed
add-jdbc-connection-pool-to-survive-scanner-load
The lab was crashing when a vulnerability scanner hit it because every servlet leaks its DB connection (no close), and DBConnect opens a fresh DriverManager connection per request. Under load the JVM accumulated leaked connections until it OOMed and MySQL hit max_connections=151. Fix at the pool layer so no servlet/controller code changes (all deliberate vulnerabilities preserved): - Declare a tomcat-jdbc DataSource at jdbc/jvl in META-INF/context.xml with maxActive=50 and removeAbandoned=true (60s) so leaked connections are auto-reaped. - Add resource-ref in web.xml. - Make DBConnect.connect look up the pool via JNDI, with the original DriverManager path retained as a fallback. - Copy mysql-connector-java into Tomcat's shared lib/ so the pool's container classloader can load the driver. - Bump CATALINA_OPTS to -Xms256m -Xmx1024m. - Set MySQL max_connections=500 and shorter wait_timeout/interactive_timeout. - Add .dockerignore (mysql-data/, .git/, target/) and .gitignore. Verified: 200 concurrent SQLi requests cap MySQL Threads_connected at 50 with Aborted_connects=0; SQLi auth bypass on /LoginValidator still works.
1 parent affe17b commit 645e896

7 files changed

Lines changed: 100 additions & 35 deletions

File tree

.dockerignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
mysql-data/
2+
.git/
3+
target/

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
mysql-data/
2+
target/
3+
*.war
4+
*.class
5+
.idea/
6+
*.iml
7+
.vscode/
8+
.DS_Store

Dockerfile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,23 @@ COPY . .
99
# Install Maven and JDK, then build the project
1010
RUN apt-get update && \
1111
apt-get install -y maven && \
12-
mvn clean package
12+
mvn clean package && \
13+
mvn dependency:copy-dependencies -DincludeArtifactIds=mysql-connector-java -DoutputDirectory=/app/shared-libs
1314

1415
# Stage 2: Runtime Stage
1516
FROM tomcat:7.0.82
1617

1718
# Copy the WAR file built in the previous stage
1819
COPY --from=build /app/target/*.war /usr/local/tomcat/webapps/
1920

21+
# Copy the JDBC driver into Tomcat's shared lib so the pool DataSource (declared
22+
# in META-INF/context.xml and loaded by the container classloader) can find it.
23+
COPY --from=build /app/shared-libs/*.jar /usr/local/tomcat/lib/
24+
2025
# Copy the pre-prepared tomcat-users.xml to set up user roles
2126
COPY default-tomcat.xml /usr/local/tomcat/conf/tomcat-users.xml
2227

28+
ENV CATALINA_OPTS="-Xms256m -Xmx1024m"
29+
2330
# CMD to start Tomcat
2431
CMD ["catalina.sh", "run"]

docker-compose.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,8 @@ services:
1818
MYSQL_DATABASE: abc
1919
command:
2020
- "--default-authentication-plugin=mysql_native_password"
21+
- "--max_connections=500"
22+
- "--wait_timeout=120"
23+
- "--interactive_timeout=120"
24+
volumes:
25+
- ./mysql-data:/var/lib/mysql
Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,59 @@
1-
/*
2-
* To change this license header, choose License Headers in Project Properties.
3-
* To change this template file, choose Tools | Templates
4-
* and open the template in the editor.
5-
*/
6-
71
package org.cysecurity.cspf.jvl.model;
82

9-
103
import java.io.FileInputStream;
114
import java.io.IOException;
12-
import java.io.InputStream;
135
import java.sql.Connection;
146
import java.sql.DriverManager;
157
import java.sql.SQLException;
168
import java.util.Properties;
9+
import javax.naming.Context;
10+
import javax.naming.InitialContext;
11+
import javax.naming.NamingException;
12+
import javax.sql.DataSource;
1713

18-
/**
19-
*
20-
* @author breakthesec
21-
*/
2214
public class DBConnect {
23-
public Connection connect(String path) throws IOException,ClassNotFoundException,SQLException
24-
{
25-
Properties properties=new Properties();
26-
properties.load(new FileInputStream(path));
27-
String dbuser=properties.getProperty("dbuser");
28-
String dbpass = properties.getProperty("dbpass");
29-
String dbfullurl = properties.getProperty("dburl")+properties.getProperty("dbname");
30-
String jdbcdriver = properties.getProperty("jdbcdriver");
31-
Connection con=null;
32-
try
33-
{
34-
Class.forName(jdbcdriver);
35-
con= DriverManager.getConnection(dbfullurl,dbuser,dbpass);
36-
return con;
37-
}
38-
finally
39-
{
40-
41-
}
15+
16+
private static volatile DataSource pooledDataSource;
17+
18+
public Connection connect(String path) throws IOException, ClassNotFoundException, SQLException {
19+
DataSource ds = lookupPool();
20+
if (ds != null) {
21+
return ds.getConnection();
22+
}
23+
return legacyConnect(path);
24+
}
25+
26+
private static DataSource lookupPool() {
27+
DataSource ds = pooledDataSource;
28+
if (ds != null) {
29+
return ds;
30+
}
31+
synchronized (DBConnect.class) {
32+
if (pooledDataSource == null) {
33+
try {
34+
Context envCtx = (Context) new InitialContext().lookup("java:comp/env");
35+
pooledDataSource = (DataSource) envCtx.lookup("jdbc/jvl");
36+
} catch (NamingException e) {
37+
return null;
38+
}
39+
}
40+
return pooledDataSource;
41+
}
42+
}
43+
44+
private static Connection legacyConnect(String path) throws IOException, ClassNotFoundException, SQLException {
45+
Properties properties = new Properties();
46+
FileInputStream in = new FileInputStream(path);
47+
try {
48+
properties.load(in);
49+
} finally {
50+
in.close();
51+
}
52+
String dbuser = properties.getProperty("dbuser");
53+
String dbpass = properties.getProperty("dbpass");
54+
String dbfullurl = properties.getProperty("dburl") + properties.getProperty("dbname");
55+
String jdbcdriver = properties.getProperty("jdbcdriver");
56+
Class.forName(jdbcdriver);
57+
return DriverManager.getConnection(dbfullurl, dbuser, dbpass);
4258
}
43-
}
59+
}
Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,22 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<Context antiJARLocking="true" path="/JavaVulnerableLab" useHttpOnly="false"/>
2+
<Context antiJARLocking="true" path="/JavaVulnerableLab" useHttpOnly="false">
3+
<Resource name="jdbc/jvl"
4+
auth="Container"
5+
type="javax.sql.DataSource"
6+
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
7+
driverClassName="com.mysql.jdbc.Driver"
8+
url="jdbc:mysql://mysql:3306/abc?useSSL=false&amp;autoReconnect=true"
9+
username="root"
10+
password="root"
11+
initialSize="5"
12+
minIdle="5"
13+
maxIdle="20"
14+
maxActive="50"
15+
maxWait="10000"
16+
removeAbandoned="true"
17+
removeAbandonedTimeout="60"
18+
logAbandoned="true"
19+
testOnBorrow="true"
20+
validationQuery="SELECT 1"
21+
validationInterval="30000"/>
22+
</Context>

src/main/webapp/WEB-INF/web.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,5 +101,11 @@
101101
<servlet-name>xxe</servlet-name>
102102
<url-pattern>/xxe.do</url-pattern>
103103
</servlet-mapping>
104-
104+
105+
<resource-ref>
106+
<res-ref-name>jdbc/jvl</res-ref-name>
107+
<res-type>javax.sql.DataSource</res-type>
108+
<res-auth>Container</res-auth>
109+
</resource-ref>
110+
105111
</web-app>

0 commit comments

Comments
 (0)