지운 비밀번호도 새는 홈페이지 점검 3단계

지운 비밀번호도 새는 홈페이지 점검 3단계

·(주)비젼솔루션·약 8분

개발자가 코드에서 비밀번호를 지워도 .git 폴더가 인터넷에 열려 있으면 과거 기록 속 비밀번호가 그대로 남아 있어요. 주소창 2줄과 무료 스크립트로 열려 있는지 보고, 무료 오픈소스 gitleaks로 지운 기록까지 찾는 방법을 정리했어요. 비용은 0원이에요.

목차클릭하여 접기/펼치기
  1. 1.지운 비밀번호가 .git에 남는 이유
  2. 2.홈페이지 점검 3단계
  3. 3.열렸다면 조치하고 회사에 적용하기
  4. 4.자주 묻는 질문
  5. 5.함께 보면 좋은 글

VISIONC 마스코트

지운 비밀번호가 .git에 남는 이유

코드에서 지웠는데, 왜 아직 남아 있을까요

"그 비밀번호는 예전에 코드에서 지웠어요." 외주 개발자에게 이런 말을 들으면 안심이 되죠. 그런데 홈페이지 서버에 .git 폴더가 열려 있다면 얘기가 달라져요.

.git은 프로그램을 고친 모든 순간을 쌓아 두는 작업 일지 서랍이에요. 일지에는 오늘 상태만 적히지 않고, 어제 지운 줄도 그대로 적혀 있어요. 보안 점검 업체 BoringSec의 2026년 7월 10일 글은 이 폴더가 HTTP로 접근되는 상태라면 소스 코드 전체와 모든 변경 기록, 한 번 올렸다가 "삭제한" 비밀값까지 복원할 수 있다고 설명해요. 같은 글의 FAQ에는 대부분의 저장소가 변경 기록 어딘가에 비밀값을 하나쯤은 갖고 있다는 취지의 설명도 있어요.

설정·백업 파일이 주소만 치면 내려받아지는 문제는 지난 글 우리 사이트 진짜 위험한 7가지 공격 유형 4번에서 다뤘어요. 이번 글은 겹치지 않게 .git 폴더 하나에만 집중해요. 파일을 지운 뒤에도 남는 기록이 핵심이거든요.

실제로 열려 있는 곳이 얼마나 될까요

보안 회사 Intruder가 2026년 8월 20일 공개한 조사를 같이 볼까요? 작업 방식부터 눈에 띄어요. 저장소를 통째로 받지 않고 전체 변경 기록을 훑어서, 비밀값이 든 곳만 골랐다고 해요. Intruder는 이렇게 해야 나중 변경에서 지워진 파일 속 비밀값까지 잡힌다고 설명해요. 그리고 이런 실수가 흔하고, 영향이 가장 큰 유출이 자주 나오는 곳이라고 덧붙여요.

HTTP 서비스가 살아 있는 호스트 350만 곳을 훑었더니 열려 있는 .git 저장소가 2만 8천 개 나왔어요. 거기서 AWS 접속 키 400개 이상, 스트라이프 결제 비밀 키 107개, OpenAI 키 123개, 텔레그램 토큰 80개, 깃허브 개인 접근 토큰 17개가 나왔어요. Intruder는 추출한 키 중 상당수가 점검 시점에도 유효했고, 스트라이프 키는 그중 일부만 유효했다고 밝혔어요.

center ▲ 열린 .git 저장소 조사 결과 · 출처: Intruder, 2026년 8월 20일 (단위가 서로 달라 이어 붙이지 않았어요)

홈페이지 점검 3단계

1단계: 주소창에 2줄 쳐 보세요

컴퓨터를 잘 몰라도 괜찮아요. 크롬이나 엣지를 열고, 본인 회사 홈페이지 주소 뒤에 아래 경로를 하나씩 붙여 보세요.

  1. https://내도메인.co.kr/.git/HEAD
  2. https://내도메인.co.kr/.git/config

BoringSec은 .git/config 하나만으로도 비공개 저장소 주소가, 오래된 구성에서는 심어 둔 접속 정보까지 드러날 수 있다고 짚어요.

center ▲ 화면 결과 읽는 법 · 판별 기준 출처: BoringSec "Exposed .env and .git Files" (2026년 7월 10일)

결과는 화면에 뜬 내용으로 읽어요. BoringSec이 바라는 결과는 "파일 내용이 없는 404 또는 403"이에요. 상태 코드가 404나 403이어도 화면에 파일 내용이 보이면 열려 있는 거예요. 반대로 코드가 200이어도 홈페이지 첫 화면이 그대로 뜨면 파일이 아니에요. 화면 하나로 모든 주소를 처리하는 싱글 페이지 방식 사이트가 없는 주소에도 200과 메인 화면을 돌려주는 경우가 흔하다고 BoringSec이 설명해요.

진짜 .git/HEAD는 ref: refs/heads/로 시작해요. 진짜 .git/config에는 [core] 같은 제목 줄이 있어요. 이런 글자가 보이면 열려 있는 거예요.

⚠️ 열렸다고 화면을 캡처해서 단체 대화방에 올리지 마세요. 접속 정보가 그대로 보일 수 있어요.

2단계: 스크립트로 한 번에 확인하기

매번 손으로 치기 번거롭죠? 서버를 직접 관리하거나 개발 담당자가 있다면, 아래 내용을 check.sh로 저장해 두세요. curl이 있는 맥이나 리눅스에서 돌아가요. 저는 내 컴퓨터에 테스트 서버를 띄워서 아홉 가지 경우를 확인했어요. 없는 주소에도 메인 화면을 주는 서버는 "화면(HTML)", 진짜 .git 파일을 내주는 서버와 코드는 403인데 본문에 파일 내용이 섞여 나오는 서버는 "파일 내용 의심"으로 나왔어요. 본문 없는 404와 본문 없는 403은 "파일 내용 없음"이에요. 본문 없는 500과 본문 없는 200, 10초 안에 답이 없는 서버, 연결이 거부된 서버는 안전하다고 하지 않고 "확인 불가"로 나오는 것까지 확인했어요.

#!/bin/sh
# 사용법: sh check.sh https://내도메인.co.kr
DOMAIN="${1:?주소를 넣어 주세요}"
TMP=$(mktemp)
for p in /.git/HEAD /.git/config; do
  code=$(curl -s -m 10 -o "$TMP" -w "%{http_code}" "$DOMAIN$p")
  rc=$?
  head -c 2000 "$TMP" > "$TMP.h"
  if [ "$rc" -ne 0 ] || [ "$code" = "000" ]; then kind="확인 불가(요청 실패)"
  elif grep -qiE '<html|<!doctype' "$TMP.h"; then kind="화면(HTML)"
  elif grep -q '^ref: refs/heads/' "$TMP.h" || grep -q '^\[core\]' "$TMP.h"; then kind="파일 내용 의심"
  elif [ -s "$TMP" ]; then kind="내용 있음(직접 확인)"
  elif [ "$code" = "404" ] || [ "$code" = "403" ]; then kind="파일 내용 없음"
  else kind="확인 불가(본문 없음)"; fi
  echo "$(date '+%F %T') | $DOMAIN | $p | HTTP $code | $kind"
done
rm -f "$TMP" "$TMP.h"

3단계: 열린 곳이 없어도 해야 할 것, 지운 기록 찾기

여기가 이 글의 핵심이에요. 지금 막혀 있다고 과거가 깨끗한 건 아니거든요. 이미 한 번이라도 열렸다면 그 사이 누가 받아 갔는지 알 길이 없어요. 그래서 우리 쪽 저장소 기록 안에 지운 비밀값이 남아 있는지 직접 찾아봐야 해요. 개발 담당자의 컴퓨터나 서버에 저장소 폴더가 있다면 두 가지 방법이 있어요.

방법 A: git 기본 기능으로 찾기 (설치 불필요)

찾고 싶은 글자(예: 비밀번호 항목 이름)를 넣어서 모든 기록을 검색해요.

git log --all -p -S"DB_PASSWORD" --oneline

저는 .env에 DB_PASSWORD=...를 넣었다가 다음 기록에서 파일을 지운 테스트 저장소를 만들었어요. 지운 뒤에는 폴더에서 grep을 돌려도 안 나왔는데, 위 명령은 그 줄이 있던 기록 두 곳을 모두 보여 줬어요. 파일에서 사라져도 기록에는 남는다는 걸 눈으로 확인한 셈이에요.

방법 B: 무료 오픈소스 gitleaks (MIT 라이선스)

gitleaks는 저장소의 과거 기록을 통째로 훑어 비밀번호나 접속 키처럼 보이는 것을 찾아 주는 도구예요. 맥은 brew install gitleaks로, 도커가 있다면 아래처럼 설치 없이 돌릴 수 있어요. 저장소 폴더 안에서 실행하세요.

docker run --rm -v "$PWD":/repo ghcr.io/gitleaks/gitleaks:latest git -v --redact /repo

--redact를 붙이면 찾은 비밀값을 화면에 가려서 보여 줘요. 저는 가짜 깃허브 토큰을 넣었다가 다음 기록에서 지운 테스트 저장소에 이 명령을 돌렸는데, 지워진 토큰을 github-pat 규칙으로 찾고 어느 기록에서 나왔는지까지 알려 줬어요. 한계도 있었어요. DB_PASSWORD=아무글자처럼 널리 알려진 키 모양이 아닌 값은 못 찾았어요. 그래서 방법 A로 항목 이름을 직접 검색하는 걸 같이 하세요. 또 gitleaks 저장소 안내에는 새 기능 개발은 끝났고 앞으로는 보안 패치만 나온다고 적혀 있어요.

도구비용설치와 요구 사양장점단점
이 글의 스크립트0원curl이 있는 PC면 충분해요2개 경로를 빠르게 보고, 접속 실패는 안전과 구분해요그 밖의 취약점은 못 봐요
git 기본 검색0원git이 깔린 PC면 돼요설치할 게 없고 항목 이름으로 바로 찾아요찾을 글자를 알고 있어야 해요
gitleaks (MIT)0원맥은 brew, 그 외에는 도커·릴리스 실행 파일·소스 빌드 중에서 골라요알려진 키 모양을 전체 기록에서 찾아요키 모양이 아닌 일반 비밀번호는 놓칠 수 있어요
Nuclei (MIT)0원공식 설치 안내에서 brew·도커·릴리스 실행 파일 중 고르면 돼요.git/config 노출 점검 템플릿이 공개돼 있어요명령 창 사용이 필요하고 결과 해석은 직접 해야 해요
전문 모의해킹유료요청만 하면 돼요점검 범위를 더 넓게 잡을 수 있어요비용이 들고 일정이 필요해요

Nuclei는 홈페이지 쪽 노출을 보는 도구예요. 설치는 공식 안내대로 세 가지 중 편한 것을 고르세요. 맥이나 리눅스는 brew install nuclei, 도커가 있다면 docker pull projectdiscovery/nuclei:latest, 둘 다 어렵다면 위 릴리스 페이지에서 내 운영체제용 파일을 받아 압축을 풀면 돼요. 설치한 뒤 아래 한 줄이면 .git/config가 열려 있는지 확인해요. 도커로 설치했다면 명령 앞에 docker run --rm projectdiscovery/nuclei:latest를 붙여서 -u 이하를 그대로 쓰면 돼요. 저는 이 도커 이미지로 테스트 서버에 돌려서, git-config 항목이 나오는 것까지 확인했어요. 이 템플릿은 .git/config 한 파일만 보고, 상태 코드 200에 [core]나 [credentials] 글자가 있고 HTML 화면이 아닐 때 찾아내요. 도구는 반드시 본인이 관리하는 사이트에만 쓰세요.

nuclei -u https://내도메인.co.kr -t http/exposures/configs/git-config.yaml

VISIONC 마스코트

열렸다면 조치하고 회사에 적용하기

열려 있었다면, 닫고 바꾸는 순서

BoringSec은 이런 파일이 밖에서 열리는 상태였다면 이미 내려받았다고 가정하라고 안내해요. 파일을 지워도 이미 받아 간 것은 사라지지 않으니까요. 기록 안에서 찾은 비밀값은 전부 새로 발급하세요. 데이터베이스 비밀번호, API 키, 로그인 서명용 비밀값(JWT 시크릿)이 모두 포함돼요. 제 해석으로는 저장소 기록에서 값을 지우는 작업만으로는 이미 받아 간 사본의 값이 사라지지 않으니, 기록 정리와 별개로 값 교체는 꼭 해야 해요.

할 일은 두 갈래예요. 열린 문을 닫는 일과, 노출된 비밀값을 모두 새로 발급하는 일이에요. BoringSec 글은 조치 목록에서 차단을 앞에, 비밀값 교체를 뒤에 두고 FAQ에서는 교체를 먼저 말하기도 해요. 그래서 어느 쪽이 먼저라고 단정하기보다 둘 다 같은 날 끝내는 게 좋아요.

⚠️ 설정을 고치기 전에 이것만은 지켜 주세요.

  1. 고칠 설정 파일을 먼저 복사해 날짜를 붙여 백업해 두세요. 문제가 생기면 되돌릴 수 있어요.
  2. 가능하면 운영 서버 말고 테스트 서버에서 먼저 확인하세요.
  3. 적용한 뒤 홈페이지 첫 화면과 로그인, 결제가 정상인지 열어 보세요.
  4. 서버 환경마다 설정이 달라서 아래 예시가 그대로 안 맞을 수 있어요. 확신이 없으면 호스팅 업체나 개발 담당자와 함께 하세요.

서버가 nginx라면 BoringSec이 소개한 아래 규칙이 한 예시예요. 점(.)으로 시작하는 경로를 막되 인증서 갱신용 .well-known만 남겨 둬요. .git도 점으로 시작하니 이 규칙에 걸려요.

location ~ /\.(?!well-known) {
    deny all;
}

nginx 공식 문서에 따르면 nginx는 먼저 접두어(prefix) location 중 가장 길게 맞는 것을 기억해 두고, 그다음 정규식 location을 설정 파일에 적힌 순서대로 검사해 처음 맞는 곳에서 멈춰요. 그래서 /.git/... 요청과 실제로 일치하는 다른 정규식 location이 이 규칙보다 위에 있으면 그쪽 설정이 쓰여요. 또 가장 길게 맞는 접두어 location에 ^~가 붙어 있으면 정규식 location은 아예 검사하지 않아서 이 규칙이 적용되지 않아요. 적용 후에는 꼭 1단계의 두 주소를 다시 열어 보세요. 또 같은 문서에 따르면 nginx -s reload는 새 설정의 문법을 먼저 검사하고, 문제가 있으면 기존 설정을 그대로 유지해요.

클라우드플레어 같은 CDN을 쓴다면 /.git/*을 요청이 서버에 닿기 전에 막는 규칙을 추가하라고 BoringSec이 안내해요. 호스팅 업체 화면만 쓰는 분은 "점(.)으로 시작하는 경로와 .git 폴더 접근을 막아 달라"고 요청하세요. 제대로 막혔는지는 마지막에 꼭 1단계나 스크립트로 다시 확인하세요.

마지막은 뿌리 문제예요. BoringSec은 대표적인 원인으로 웹 서버가 보는 폴더가 프로젝트 폴더와 같은 경우나 프로젝트를 통째로 복사해 올리는 배포를 꼽아요. 그래서 웹 서버가 보는 폴더에는 브라우저에 필요한 파일만 두라고 권해요.

가상의 B사에 적용해 보면, 그리고 우리의 시각

부산에서 인테리어 자재 쇼핑몰을 하는 B사(직원 4명)를 가정해 볼게요. 쇼핑몰은 5년 전 외주로 만들었고, 대표님은 호스팅 관리 화면만 가끔 열어 봐요. 점검 첫날 /.git/HEAD를 쳤더니 ref: refs/heads/로 시작하는 글자가 떴다고 해 볼까요? 놀랍지만 상상 못 할 일은 아니죠. BoringSec이 원인으로 꼽듯 프로젝트 폴더째 올려 배포하는 경우가 있거든요.

B사가 할 일은 다섯 가지예요. 외주 개발자에게 숨김 경로 차단을 같은 날 요청하고, 저장소를 받아 gitleaks와 항목 이름 검색을 돌려 달라고 하고, 나온 비밀값을 전부 새로 발급하고, 고객 정보 접속 기록 확인을 요청하고, 한 달 뒤 같은 점검을 다시 하는 거예요.

내 업무와 연결하는 방법도 있어요. 스크립트를 도메인마다 돌리도록 감싸 두면 어떨까요? 회사 홈페이지, 쇼핑몰, 예약 사이트를 한 번에 볼 수 있죠. 그다음 항상 켜져 있는 리눅스 서버의 작업 예약(cron)에 한 줄을 넣으면 매달 1일 아침마다 알아서 돌아가요. 노트북은 꺼져 있으면 돌지 않으니 이 용도로는 맞지 않아요.

0 9 1 * * for d in https://회사사이트.co.kr https://쇼핑몰.co.kr; do sh ~/check.sh $d; done >> ~/check.log 2>&1

줄마다 점검 시각과 도메인이 함께 찍히니, 로그에서 의심, 직접 확인, 확인 불가 글자가 들어간 줄만 뽑아 구글 시트에 붙여 두면 점검한 시점과 대상 도메인별 상태 변화를 추적할 수 있어요. 확인 불가가 계속 찍히는 도메인은 점검이 안 되고 있다는 신호예요. 실제로 언제부터 열려 있었는지는 이 기록만으로 알 수 없고, 점검한 날과 처음 발견한 날만 보여 줘요. 개발 담당자에게 분기마다 gitleaks를 저장소 전체 기록에 한 번 돌려 보게 하는 것도 방법이에요. 여기까지는 직접 하실 수 있어요. 서버 설정 변경이나 이미 털렸는지 가리는 침해 확인은 전문가 손이 필요한 영역이에요.

우리는 이렇게 봐요. BoringSec은 자동 스캐너가 매일 같은 경로를 모든 도메인에 요청한다고 설명해요. 사람이 우리 회사를 콕 집어 노리는 게 아니라, 열려 있는 곳이 걸리기를 기다리는 방식이죠. 그리고 Intruder는 영향이 가장 큰 유출이 나중에 삭제된 파일의 과거 버전에서 자주 나온다고 설명해요. 제 해석으로는 이게 중소기업이 가장 놓치기 쉬운 지점이에요. "지웠으니 괜찮다"는 말이 보안에서는 확인 전까지 믿으면 안 되는 문장이거든요. 점검 한 번으로 이 말이 사실인지 확인할 수 있어요.

VISIONC 마스코트

자주 묻는 질문

Q. 주소창에 쳤더니 403이 떴는데 안전한가요? 403이라는 숫자만으로는 판단할 수 없어요. 화면에 파일 내용이 없어야 안전한 결과예요. 접속이 안 되거나 아무것도 안 뜨는 경우도 안전한 게 아니라 확인이 안 된 거예요. 코드는 403인데 ref:나 [core] 글자가 보이면 열려 있는 거예요. 스크립트가 본문까지 같이 보는 이유예요.

Q. 파일만 지우면 끝인가요? 아니에요. 이미 내려받은 것은 되돌릴 수 없어서, 노출됐던 비밀값은 모두 새로 발급해야 해요. 변경 기록 안에 남은 값도 같아요.

Q. 남의 사이트도 이렇게 확인해 봐도 되나요? 안 돼요. 본인이 관리하는 사이트만 점검하고, 남의 사이트는 반드시 허락을 받은 뒤에 하세요.

직접 점검이 부담스럽다면 (주)비젼솔루션의 모의해킹 진단에서 상담받을 수 있어요.

이 글이 도움이 되셨나요? 보안이 궁금한 분께 공유해 주세요. 댓글로 질문하시면 성심껏 답해 드릴게요!

함께 보면 좋은 글

웹사이트 보안 · 실전 진단

실전 모의해킹 진단, 바로 신청하기

OWASP 주요 위협 + 워드프레스 특화 · 1~2일 · 보고서 + 조치 후 재점검

790,000원290,000원부가세 포함
지금 신청·결제하기 →

우리 회사도 이렇게 할 수 있을까요?

무료 상담을 통해 현재 상황에 맞는 솔루션을 제안해드립니다.