Skip to main content
Advertisement

AJP Connector Configuration and Security

AJP (Apache JServ Protocol) is a high-speed binary protocol between Apache HTTPD and Tomcat. This chapter covers how AJP works, the latest security settings (Ghostcat vulnerability mitigation), and when to use AJP vs. the modern alternative.


AJP Protocol Overview

AJP is a binary protocol designed for communication between a web server (Apache HTTPD) and a WAS (Tomcat).

[Client] ← HTTP/HTTPS → [Apache HTTPD :80/443]
↓ AJP (binary)
[Tomcat :8009]

[Java Web Application]

HTTP Proxy vs AJP Comparison

ItemHTTP ProxyAJP
ProtocolHTTP (text)Binary
PerformanceModerateHigh (less parsing overhead)
ConfigurationSimpleMedium complexity
Security issuesStandard HTTP securityGhostcat vulnerability
Current recommendationRecommendedLegacy systems only

Modern recommendation: For new systems, use HTTP proxy (mod_proxy_http) instead of AJP. AJP is a legacy approach for Apache+Tomcat setups.


Ghostcat Vulnerability (CVE-2020-1938)

Ghostcat, discovered in February 2020, is a critical vulnerability that allows reading arbitrary files within a Tomcat web application via the AJP connector.

Affected Versions

Tomcat VersionVulnerablePatched
Tomcat 99.0.0.M1 ~ 9.0.309.0.31+
Tomcat 8.58.5.0 ~ 8.5.508.5.51+
Tomcat 77.0.0 ~ 7.0.997.0.100+

Remediation Options

Option 1: Disable AJP Connector (safest)

<!-- server.xml — Comment out the AJP connector -->
<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/> -->

Option 2: Enforce secretRequired (when AJP is necessary)

<Connector protocol="AJP/1.3"
address="127.0.0.1"
port="8009"
redirectPort="8443"
secretRequired="true"
secret="MyS3cr3tAJPK3y!2024"/>

Option 3: Restrict access by IP

<Connector protocol="AJP/1.3"
address="127.0.0.1" <!-- localhost only -->
port="8009"
redirectPort="8443"
secretRequired="true"
secret="MyS3cr3tAJPK3y!"/>

AJP Connector Configuration (with Security)

Tomcat Configuration

<!-- server.xml -->
<Connector protocol="AJP/1.3"
address="127.0.0.1"
port="8009"
redirectPort="8443"
maxThreads="150"
minSpareThreads="5"
connectionTimeout="10000"
secretRequired="true"
secret="YourSecureSecretHere"
allowedRequestAttributesPattern=".*"/>
AttributeDescriptionSecure Setting
addressListening IP127.0.0.1 (local only)
portAJP port8009 (default)
secretRequiredRequire secrettrue
secretShared secretStrong random string
allowedRequestAttributesPatternAllowed request attribute patternsAllow only what's needed

Apache HTTPD Configuration (mod_proxy_ajp)

# Enable required modules
sudo a2enmod proxy
sudo a2enmod proxy_ajp
sudo systemctl reload apache2
# /etc/apache2/sites-available/myapp.conf
<VirtualHost *:80>
ServerName example.com

ProxyRequests Off
ProxyPreserveHost On

# AJP proxy (with secret)
<Proxy "ajp://localhost:8009/?secret=YourSecureSecretHere">
Require all granted
</Proxy>

ProxyPass / ajp://localhost:8009/?secret=YourSecureSecretHere
ProxyPassReverse / ajp://localhost:8009/?secret=YourSecureSecretHere
</VirtualHost>

AJP vs HTTP Proxy — When to Use Which

# Using mod_proxy_http (recommended)
ProxyPass /api/ http://localhost:8080/api/
ProxyPassReverse /api/ http://localhost:8080/api/

# Advantages:
# - Simple configuration
# - Easier SSL/TLS termination management
# - No Ghostcat vulnerability
# - Compatible with various load balancers

When AJP Has Advantages

  • Must maintain very legacy Apache+Tomcat configurations
  • Internal environments with extremely limited network bandwidth
  • During gradual migration away from mod_jk (old AJP module)

Migrating from mod_jk to mod_proxy_ajp

If you're using the old mod_jk, switching to mod_proxy_ajp is recommended.

# Old mod_jk configuration (legacy)
# LoadModule jk_module modules/mod_jk.so
# JkWorkersFile /etc/httpd/conf/workers.properties
# JkMount /* worker1

# Replacement: mod_proxy_ajp
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so

ProxyPass / ajp://localhost:8009/?secret=MySecret
ProxyPassReverse / ajp://localhost:8009/?secret=MySecret

Verifying AJP Connector Status

# Check AJP port listening
ss -tlnp | grep 8009

# Check Tomcat logs for AJP messages
tail -f /opt/tomcat/latest/logs/catalina.out | grep -i ajp

Complete Secure Configuration Example

<?xml version="1.0" encoding="UTF-8"?>
<Server port="-1" shutdown="SHUTDOWN">
<Service name="Catalina">

<!-- HTTP connector only -->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
address="127.0.0.1"/>

<!-- AJP disabled (Ghostcat prevention) -->
<!--
<Connector protocol="AJP/1.3"
address="127.0.0.1"
port="8009"
redirectPort="8443"
secretRequired="true"
secret="ChangeMe!"/>
-->

<Engine name="Catalina" defaultHost="localhost">
</Engine>
</Service>
</Server>

Apache HTTPD (HTTP proxy approach)

<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

ProxyRequests Off
ProxyPreserveHost On

# HTTP proxy (recommended over AJP)
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/

RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}s"
</VirtualHost>

Summary

ItemRecommended Setting
Ghostcat mitigationDisable AJP connector (comment out)
Unavoidable AJP usesecretRequired="true" + strong secret
AJP listen addressaddress="127.0.0.1" (local only)
New systemsHTTP proxy (mod_proxy_http) recommended
Legacy mod_jkMigrate to mod_proxy_ajp
Advertisement