Blog >> PHP >> Whitepapers.
PHP 500 에러 대응
한국인터넷진흥원 에서 PHP 관련 업데이트 및 보안 조치 사항을 전달 받음. 이참에 로그를 분석 해 조치.
413 (대용량 초과 거부) 및 500 에러를 유발한 IP 추적
액세스 로그에서 대용량 차단(413) 및 서버 오류(500)를 발생시킨 IP와 발생 횟수를 상위 순으로 집계
grep -E '" (413|500) ' /var/log/httpd/*-access_log | awk '{print $1}' | sort | uniq -c | sort -nr | head -n 10
Fail2ban 필터 매칭 테스트 (실시간 검증)
fail2ban-regex /var/log/httpd/*-access_log /etc/fail2ban/filter.d/apache-overflow.conf
Fail2ban에 의해 실제 차단된 IP 실시간 확인
http-overflow 규칙에 의해 차단된 IP 목록을 확인
fail2ban-client status apache-overflow
Fail2ban 자체 로그에서 차단(Ban) 이력만 필터링
grep "\[apache-overflow\] Ban" /var/log/fail2ban.log | tail -n 20
특정 시점의 413/500 요청의 상세 URL 및 HTTP 메서드 확인. 어떤 경로로 어떤 대용량 요청이 들어왔는지 확인.
grep -E '" (413|500) ' /var/log/httpd/*-access_log | awk '{print $1, $6, $7, $9}' | tail -n 20그리고 에러 로그 확인.
조회 결과 대용량 Body 공격이 아니라, 취약점을 찔러보는 스캐너(GET)가 Apache와 PHP의 취약한 경로, 루프를 건드려 500 에러를 유발한 것.
# Apache 에러 로그 확인 (가상호스트 포함)
tail -n 30 /var/log/httpd/*-error_log
# PHP-FPM 에러 로그 확인
tail -n 30 /var/log/php-fpm/error-*.log
1. 비정상 500 에러 제거 및 취약점 스캔 1차 차단.
500 에러가 나는 두 가지 주요 원인을 서버 설정에서 먼저 잡아 비정상 응답을 없앰.
아파치 가상호스트 공통 설정에 <LocationMatch> 지시어 설정.
디렉터리 기반(<DirectoryMatch>)이 아니라, 요청 URL 기반(<LocationMatch>)으로 차단해야 ProxyPassMatch보다 앞 단에서 가로챌 수 있다.
# =================================================================
# URL 경로 기준으로 프록시 핸들러보다 먼저 403 차단
# =================================================================
<LocationMatch "^/wp-content/.*\.php$">
Require all denied
</LocationMatch>
<LocationMatch "^/wp-includes/.*\.php$">
Require all denied
</LocationMatch>사이트 별로 안전하게 통제하려면 .htaccess 최 상단에 [F,L] RewriteRule 을 두는 것이 가장 직관적이고 표준적인 워드프레스 보안 방식이며, 서버 전체 사이트에 일괄 적용하려면 디렉터리가 아닌 LocationMatch 를 사용.
문법 확인 및 무 중단 재 로드. 후 403 차단이 정상 유지되는지 확인. 최종 결과가 HTTP/2 403 으로 떨어지는지 확인.
작업 기대 결과는 www 301 리디렉션 후 HTTP/2 403
httpd -t && apachectl graceful
curl -IL https://gldigital.co.kr/wp-content/themes/engic/index.php참고로 워드프레스 멀티사이트, 서브도메인 운영 중 .htaccess
# BEGIN WordPress
# "BEGIN WordPress"와 "END WordPress" 사이의 지시문(줄)은
# 동적으로 생성되며 워드프레스 필터를 통해서만 수정해야합니다.
# 이 표시 사이의 지시문을 변경하면 덮어쓰게 됩니다.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
# wp-admin 슬래시 자동 보정
RewriteRule ^wp-admin$ wp-admin/ [R=301,L]
# 실제 파일/디렉터리는 바로 제공
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# 멀티사이트 코어 파일 통과
RewriteRule ^(wp-(content|admin|includes).*) $1 [L]
# 없는 경로는 모두 index.php로 전달 <- 문제
#RewriteRule ^(.*\.php)$ $1 [L]
RewriteRule . index.php [L]
</IfModule>
# END WordPress참고로 워드프레스 기본 .htaccess
# BEGIN WordPress
# "BEGIN WordPress"와 "END WordPress" 사이의 지시문(줄)은
# 동적으로 생성되며 워드프레스 필터를 통해서만 수정해야합니다.
# 이 표시 사이의 지시문을 변경하면 덮어쓰게 됩니다.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress2. Fail2ban 필터 및 감옥(Jail) 연동
스캐너들이 403 차단된 경로(/wp-content/*.php 등)나 취약점 파일 탐색으로 404/403/500 응답을 반복 유발할 때 방화벽 레벨에서 IP를 자동 격리하도록 구성.
- 포스트 위치:
- PHP
- Whitepapers
- Wordpress
- 보안패치



