.git 폴더를 막고 4일, 스캐너 IP는 178개에서 175개로 그대로였지만 요청은 27,997건에서 589건으로 줄었다
지난 글에서 서버 요청의 16.7%가 .git 폴더를 뒤지는 요청이었고, 그중 4,917건은 실제로 파일을 내주고 있었다는 것을 확인하고 아파치 설정으로 막았습니다. 그 뒤 4일 동안 같은 로그를 다시 셌습니다. 차단 전 4일과 차단 후 4일을 같은 길이로 놓고 비교하면, .git을 건드린 IP 수는 178개에서 175개로 거의 같은데 요청 수는 27,997건에서 589건으로 97.9% 줄었습니다. 스캐너의 수는 그대로이고, 스캐너 하나가 보내는 요청 수가 157건에서 3.4건으로 줄어든 것입니다. 첫 요청에서 403을 받으면 그 뒤를 이어가지 않는다는 뜻입니다.
차단 전 4일과 후 4일
설정을 적용한 시각(9월 12일 15:25, 서버 시간)을 기준으로 앞뒤 96시간씩 잘랐습니다. 접속 로그는 combined 형식 줄만 세었습니다.
| 항목 | 차단 전 4일 | 차단 후 4일 | 변화 |
|---|---|---|---|
| 전체 요청 | 336,357 | 689,077 | 다른 사이트 봇 유입으로 증가 |
.git 요청 |
27,997 (8.3%) | 589 (0.09%) | −97.9% |
.git 요청 중 200 |
415 | 0 | 유출 0 |
.git 전송량 |
14.0MB | 115KB | −99.2% |
.git을 요청한 IP |
178 | 175 | 거의 같음 |
IP당 .git 요청 |
157.3 | 3.4 | −97.9% |
| 전체 404 | 61,339 | 38,821 | −36.7% |
| 전체 403 | 728 | 4,798 | 6.6배 |

전체 요청이 두 배가 된 것은 9월 16일 하루에 74.7.227.x 대역 IP 네 개가 같은 서버의 다른 사이트 게시판을 약 23만 건 긁어 간 탓이고, .git과는 관계가 없습니다. 그래서 비율보다 건수로 봐야 합니다.
스캐너 수는 그대로, 요청만 줄었다
차단 전에 .git을 요청한 IP 178개 가운데 1,000건 넘게 보낸 IP가 4개 있었고, 이 넷이 27,261건(97.4%)을 차지했습니다. 차단 후에는 1,000건 넘는 IP가 없고 가장 많이 보낸 IP도 51건입니다.
IP당 .git 요청 |
차단 전 IP 수 | 차단 후 IP 수 |
|---|---|---|
| 1건 | 55 | 69 |
| 2~5건 | 85 | 76 |
| 6~20건 | 31 | 27 |
| 21~100건 | 2 | 3 |
| 101~1,000건 | 1 | 0 |
| 1,000건 초과 | 4 | 0 |
1~20건을 보내는 IP는 전후가 비슷합니다. 이들은 /.git/config, /.git/HEAD 같은 파일 몇 개만 찔러 보고 지나가는 탐색 단계의 스캐너라, 200이 나오든 403이 나오든 요청 수가 같습니다. 사라진 것은 1,000건 이상을 보내던 넷입니다. 차단 전 .git 요청 27,997건의 80.2%는 .git/objects/ 아래 객체 파일이었는데, 이는 config와 HEAD가 200으로 열린 뒤에야 시작되는 두 번째 단계입니다. 첫 단계가 403으로 막히니 두 번째 단계가 없어졌습니다. 차단 후 .git/objects/ 요청은 0건입니다.
같은 IP가 전후에 어떻게 달라졌나
양쪽 기간에 모두 나타난 IP는 16개입니다. 그중 차단 전 10,231건을 보낸 45.148.10.120은 차단 후 5건을 보내고 그쳤습니다. 다른 15개는 전후 모두 20건 이하였고, 그 안에서는 늘기도 줄기도 했습니다. 스캐너가 목록에서 이 서버를 지운 것이 아니라, 매번 다시 와서 첫 파일을 요청하고 403을 받고 돌아간다고 봐야 합니다. 차단 후 .git 요청의 UA는 차단 전 85.2%를 차지했던 Firefox/78 문자열이 사라지고, 윈도 브라우저 UA 문자열이 절반 가까이입니다. 객체 파일을 긁던 도구가 쓰던 UA와 탐색용 도구가 쓰는 UA가 달랐던 셈입니다.
.git 첫 요청 다음에 온 요청 |
차단 전 (IP 수) | 차단 후 (IP 수) |
|---|---|---|
또 다른 .git 경로 |
63 | 40 |
| 없음 (그 요청이 마지막) | 31 | 30 |
/.env 계열 |
30 | 59 |
/ (홈) |
20 | 17 |
/graphql |
18 | 상위 8개 밖 |
차단 후에는 .git에서 403을 받은 IP가 다음으로 .env를 찔러 보는 경우가 늘었습니다. 스캐너가 .git과 .env를 한 묶음으로 돌리는 것이고, 하나가 막혀도 다른 하나는 계속 시도합니다.
.env는 22%만 막혔다
같은 설정에 .env도 넣었는데, 로그를 보면 .env 요청은 차단 전 13,013건에서 차단 후 16,986건으로 오히려 늘었고, 403은 3,799건(22.4%)뿐입니다. 12,555건(73.9%)은 여전히 404입니다. 이유는 경로에 있습니다.
| 요청 경로 | 응답 | 크기 | 시간 | 이유 |
|---|---|---|---|---|
/.env, /.env.bak |
403 | 199B | 16ms | FilesMatch가 잡음 |
/laravel/.env, /api/.env |
404 | 55,096B | 68ms | 폴더가 없어 워드프레스 404 페이지 |
다른 사이트의 /backend/.env |
404 | 196B | — | 폴더가 없어 아파치 404 |
루트 바로 아래 .env는 파일 이름 규칙에 걸려 403이 됩니다. 그런데 스캐너는 /laravel/.env, /backend/.env, /admin/.env처럼 하위 폴더 수십 개를 돌립니다. 그 폴더가 없으면 아파치는 파일 이름 규칙을 볼 것도 없이 404를 내고, 워드프레스 사이트에서는 .htaccess가 없는 경로를 index.php로 넘겨 55KB짜리 404 페이지를 만듭니다. 차단 후 4일 동안 이렇게 워드프레스가 렌더링한 .env 404가 1,697건이었습니다. 차단 전 2,116건과 큰 차이가 없습니다. .env는 .git과 달리 첫 파일이 막혀도 다음 경로를 계속 시도하니, 파일 이름이 아니라 URL 패턴으로 막아야 효과가 있습니다. 이 부분은 다음에 LocationMatch로 옮길지 정합니다.
에러 로그에 남은 것
403이 나면 아파치 에러 로그에 client denied by server configuration 한 줄이 남습니다. 차단 후 9월 17일 새벽까지 이 줄이 5,070개 쌓였고, 문서 루트별로 나누면 이 워드프레스 다중 사이트가 724건, 다른 사이트들이 97~731건씩입니다. 공격 대상이 특정 사이트가 아니라 서버의 모든 호스트 이름이라는 뜻이고, fail2ban 잼이 161일 동안 0건이었던 이유를 봤을 때처럼 이 줄을 세는 것이 IP 차단 규칙보다 유용합니다. 없는 PHP 파일을 찾는 Primary script unknown은 차단 전후 비슷한 속도로 쌓이고 있어 이번 설정과 무관합니다.
정리
.git차단은 요청을 막았다기보다 스캐너의 두 번째 단계를 없앴습니다. 첫 파일이 403이면 객체 파일 2만 건이 따라오지 않습니다.- 스캐너 IP 수는 변하지 않습니다. 막아도 매일 같은 수가 와서 첫 파일을 찔러 보고 갑니다. 그 비용은 IP당 3~4건, 199B짜리 응답이라 무시할 수 있습니다.
.env는 하위 폴더 경로 때문에 74%가 여전히 404이고, 그중 1,697건은 워드프레스가 55KB 페이지를 만들어 응답했습니다. 파일 이름 규칙으로는 부족합니다.
측정 방법
지난 글과 같은 접속 로그 다섯 개를 파이썬으로 파싱하되, 설정 적용 시각 2026-09-12 15:25(서버 시간, KST) 기준으로 앞뒤 96시간만 남겼습니다. 앞 창은 9월 8일 15:25부터, 뒤 창은 9월 16일 15:25까지입니다. .git 요청은 경로에 /.git이 든 것, .env 요청은 /.env가 든 것으로 잡았고, 워드프레스가 렌더링한 404는 응답 크기 1KB 이상으로 구분했습니다. IP별 요청 순서는 같은 IP의 줄을 시각순으로 늘어놓고 첫 .git 요청 바로 다음 줄을 본 것입니다. 응답 크기와 시간은 서버 안에서 curl --resolve로 kilho.org에 직접 요청해 잰 값입니다. 에러 로그는 9월 13일 로테이션 전후 두 파일에서 client denied 줄을 세고 경로에 든 문서 루트로 나눴습니다.