본문으로 건너뛰기

AJP 커넥터 설정과 보안

AJP(Apache JServ Protocol)는 Apache HTTPD와 Tomcat 사이의 고속 바이너리 프로토콜입니다. 이 챕터에서는 AJP의 동작 원리, 최신 보안 설정(Ghostcat 취약점 대응), 그리고 실무에서 AJP를 사용해야 할 상황과 대안을 다룹니다.


AJP 프로토콜 개요

AJP는 웹 서버(Apache HTTPD)와 WAS(Tomcat) 간의 통신을 위해 설계된 바이너리 프로토콜입니다.

[클라이언트] ← HTTP/HTTPS → [Apache HTTPD :80/443]
↓ AJP (바이너리)
[Tomcat :8009]

[Java 웹 애플리케이션]

HTTP 프록시 vs AJP 비교

항목HTTP 프록시AJP
프로토콜HTTP (텍스트)바이너리
성능보통높음 (파싱 오버헤드 적음)
설정 복잡도낮음중간
보안 이슈표준 HTTP 보안Ghostcat 취약점 주의
현재 권장권장레거시 시스템 전용

현대적 권장사항: 신규 시스템에서는 AJP 대신 HTTP 프록시(mod_proxy_http)를 사용합니다. AJP는 Apache+Tomcat 구성의 레거시 방식입니다.


Ghostcat 취약점 (CVE-2020-1938)

2020년 2월 발견된 Ghostcat(유령 고양이)은 AJP 커넥터를 통해 Tomcat 웹 애플리케이션 내의 임의 파일을 읽을 수 있는 심각한 취약점입니다.

영향 범위

Tomcat 버전취약한 버전패치 버전
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+

대응 방법

1순위: AJP 커넥터 비활성화 (가장 안전)

<!-- server.xml — AJP 커넥터 주석 처리 -->
<!-- 아래 줄을 주석 처리하거나 삭제 -->
<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/> -->

2순위: secretRequired 강제 (AJP가 반드시 필요한 경우)

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

3순위: 접근 IP 제한

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

AJP 커넥터 설정 (보안 적용)

Tomcat 쪽 설정

<!-- 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=".*"/>
속성설명보안 설정
address수신 IP 주소127.0.0.1 (로컬만)
portAJP 포트8009 (기본)
secretRequired시크릿 필수 여부true
secret공유 시크릿강력한 무작위 문자열
allowedRequestAttributesPattern허용 요청 속성 패턴필요한 것만 허용

Apache HTTPD 쪽 설정 (mod_proxy_ajp)

# 필요 모듈 활성화
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 "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 프록시 — 언제 무엇을 쓸까

HTTP 프록시 사용 권장 상황

# mod_proxy_http 사용 (권장)
ProxyPass /api/ http://localhost:8080/api/
ProxyPassReverse /api/ http://localhost:8080/api/

# 장점:
# - 설정 단순
# - SSL/TLS 종료 관리 용이
# - Ghostcat 취약점 없음
# - 다양한 로드밸런서와 호환

AJP 사용이 유리한 상황

  • 아주 레거시한 Apache+Tomcat 구성을 유지해야 할 때
  • 네트워크 대역폭이 극히 제한적인 내부 환경
  • 기존 mod_jk(오래된 AJP 모듈) 사용 중 점진적 전환 기간

mod_jk에서 mod_proxy_ajp로 마이그레이션

오래된 시스템에서 mod_jk를 사용 중이라면 mod_proxy_ajp로 전환하는 것이 권장됩니다.

# 기존 mod_jk 설정 (레거시)
# LoadModule jk_module modules/mod_jk.so
# JkWorkersFile /etc/httpd/conf/workers.properties
# JkLogFile /var/log/httpd/mod_jk.log
# JkMount /* worker1

# 전환: 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

AJP 커넥터 상태 확인

# AJP 포트 리스닝 확인
ss -tlnp | grep 8009

# AJP 연결 테스트 (netcat)
echo -e "\x12\x34\x00\x01\x02" | nc localhost 8009

# Tomcat 로그에서 AJP 관련 메시지 확인
tail -f /opt/tomcat/latest/logs/catalina.out | grep -i ajp

완전한 보안 구성 예시

Tomcat server.xml (AJP 비활성화 권장)

<?xml version="1.0" encoding="UTF-8"?>
<Server port="-1" shutdown="SHUTDOWN">
<!-- ... listeners ... -->

<Service name="Catalina">

<!-- HTTP 커넥터만 활성화 -->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
address="127.0.0.1"/> <!-- 로컬만 허용 -->

<!-- AJP 커넥터 비활성화 (Ghostcat 방지) -->
<!--
<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 프록시 방식)

<VirtualHost *:80>
ServerName example.com
Redirect permanent / https://example.com/
</VirtualHost>

<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 프록시 (AJP 대신 권장)
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/

# 실제 IP 전달
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}s"
</VirtualHost>

Summary

항목권장 설정
Ghostcat 대응AJP 커넥터 비활성화 (주석 처리)
불가피한 AJP 사용secretRequired="true" + 강력한 시크릿
AJP 수신 IPaddress="127.0.0.1" (로컬만)
신규 시스템HTTP 프록시(mod_proxy_http) 권장
레거시 mod_jkmod_proxy_ajp로 전환 권장