제공 서비스
웹 보안 점검 · 무료 단건 소스코드 보안 분석 (SAST) · 19,900원~ 외부 공격표면 관리 · 지속 관리 AI 취약점 진단 · 신규 모의해킹 · 침투 테스트
요금제 스토어 블로그 파트너 마이페이지 무료 보안 점검
가이드 2026.04.15 · 조회 2178

배포 후 5분 안에 해야 할 보안 체크리스트 8가지

사이트 배포 직후 5분 안에 확인해야 할 보안 항목 8가지. .env 노출, HTTPS, 보안 헤더, 디버그 모드까지.

S
보안 전문 기업 SENTRIX 레드팀
해킹대회 수상 · 보안 실무 10년 · 실전 진단 경험을 바탕으로 작성합니다.
{# 전환 데이터: '노출·유출·배포전' 불안형 글이 스캔 전환의 대부분. 그런 글엔 위험 프레임을 더 강하게, 개념·비교·가이드형 글엔 담백하게 문맥 분기(제목+태그 키워드로 판별). #}
읽기만 하지 말고 내 사이트 상태부터 확인해보세요. URL 하나로 30초 무료 점검.

배포 순간이 가장 위험하다

개발 환경에서는 문제없던 설정이 프로덕션에서 보안 구멍이 되는 경우가 많다. 디버그 모드 켜진 채 배포, .env 파일 포함, HTTPS 미설정, 모두 배포 직후 5분 안에 잡을 수 있는 문제다.

CodeScan에서 신규 배포 사이트 100개를 점검한 결과, 62%가 배포 첫날에 보안 취약점을 가지고 있었다. 대부분 아래 8가지 중 하나였다.

왜 하필 배포 직후인가. 공격자는 새로 뜬 도메인을 사람보다 먼저 안다. SSL 인증서가 발급되면 그 기록이 Certificate Transparency 로그에 실시간으로 남고, 봇은 이 로그를 24시간 감시하다가 새 도메인을 발견하는 즉시 /.env, /.git, /admin 같은 경로를 자동으로 긁어간다. 사람이 사이트를 홍보하기도 전에 스캐너가 먼저 문을 두드리는 셈이다. 아래 8가지는 그 자동화 공격이 가장 먼저 노리는 지점이다. 위에서부터 파급이 큰 순서로 정리했다.

1. 디버그 모드 꺼졌는지 확인

Django DEBUG=True, Next.js 개발 모드, Flask 디버그 모드. 에러 발생 시 소스코드, DB 쿼리, 환경변수가 에러 페이지에 노출된다. 배포 후 일부러 404나 500 에러를 발생시켜서 디버그 정보가 나오는지 확인한다.

디버그 모드가 위험한 진짜 이유는 단순한 정보 노출을 넘어선다. Django의 디버그 500 페이지는 스택 트레이스와 함께 settings 값 전체를 렌더링한다. 여기에 SECRET_KEY가 찍히면 공격자는 그 키로 세션 쿠키와 CSRF 토큰을 위조해 관리자로 로그인할 수 있다. 즉 디버그 페이지 하나가 계정 탈취로 직결된다. Flask도 debug=True면 대화형 디버거 콘솔(Werkzeug)이 켜져, PIN을 뚫으면 브라우저에서 서버 파이썬 코드를 그대로 실행할 수 있다.

# 위험 — 소스가 그대로 배포됨
DEBUG = True

# 안전 — 환경변수로 분리, 기본값은 꺼짐
import os
DEBUG = os.environ.get("DJANGO_DEBUG", "False") == "True"

직접 확인하는 법: 브라우저에서 존재하지 않는 주소(예: yourdomain.com/thispagedoesnotexist-9x8)에 접속한다. 노란색/컬러풀한 상세 에러 화면, 스택 트레이스, "Traceback" 문구가 보이면 디버그 모드가 켜진 것이다. 밋밋한 "404 Not Found"만 나와야 정상이다.

조치: 프로덕션 환경변수에서 디버그를 끄고 서버를 재시작한다. 디버그 페이지에 SECRET_KEY가 노출됐던 정황이 있다면 키를 즉시 재발급하고 기존 세션을 무효화한다.

2. 환경변수 파일 접근 차단

yourdomain.com/.env를 브라우저에서 직접 접속해본다. 다운로드되면 DB 비밀번호, API 키가 전부 노출된 것이다. .gitignore에 넣는 것과 웹서버에서 차단하는 것은 별개다.

이 둘을 혼동하는 게 사고의 핵심이다. .gitignore는 파일을 깃 저장소에 안 올릴 뿐, 배포된 서버의 웹 루트에 .env가 그대로 놓여 있으면 URL로 누구나 내려받는다. 공격자는 .env 하나만 손에 넣으면 DB 접속 정보, 결제 PG 시크릿, AWS 키, 메일 발송 계정까지 통째로 확보한다. 노출된 API 키는 봇이 수 분 내 탈취해 암호화폐 채굴이나 스팸 발송에 쓰고, 그 요금은 사이트 주인에게 청구된다.

# Nginx — 점(.)으로 시작하는 숨김 파일 접근 차단
location ~ /\. {
    deny all;
    return 404;
}

# Apache (.htaccess)
<FilesMatch "^\.">
    Require all denied
</FilesMatch>

직접 확인하는 법: 주소창에 yourdomain.com/.env, yourdomain.com/.git/config를 차례로 입력한다. 파일 내용이 화면에 뜨거나 다운로드되면 노출된 것이다. 404가 떠야 안전하다.

조치: 웹서버 레벨에서 숨김 파일 접근을 차단한다. 이미 노출됐다면 파일 안의 모든 시크릿을 재발급한다, 차단만 하고 키를 그대로 두면, 이미 긁어간 공격자에게는 소용없다.

3. HTTPS 강제 리다이렉트

http://로 접속했을 때 https://로 자동 리다이렉트되는지 확인한다. 리다이렉트 없이 HTTP로 접속 가능하면 로그인 정보, 쿠키가 평문으로 전송된다.

같은 와이파이를 쓰는 카페, 공용 공유기 환경에서 평문 HTTP는 옆자리에서 그대로 읽힌다(중간자 공격). 로그인 세션 쿠키가 평문으로 한 번이라도 흐르면 공격자가 그 쿠키를 복사해 비밀번호 없이 로그인한다. 리다이렉트만으로는 부족하다. 리다이렉트가 걸리기 전 첫 요청은 여전히 HTTP다. 이를 막는 게 HSTS 헤더로, 한 번 방문한 브라우저는 다음부터 아예 처음부터 HTTPS로만 접속한다.

# Nginx — HTTP를 HTTPS로 강제 + HSTS
server {
    listen 80;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}

직접 확인하는 법: 주소창에 http://를 명시해 접속한 뒤, 자동으로 https://로 바뀌는지 본다. 개발자 도구 Network 탭에서 첫 요청의 상태 코드가 301이면 정상이다.

조치: HTTP→HTTPS 301 리다이렉트를 걸고 HSTS 헤더를 추가한다. Cloudflare를 쓴다면 "Always Use HTTPS"를 켜면 즉시 적용된다.

4. 보안 헤더 설정

X-Content-Type-Options, X-Frame-Options, Strict-Transport-Security, Content-Security-Policy. 이 4개 헤더가 없으면 XSS, 클릭재킹, MIME 스니핑 공격에 노출된다. 브라우저 개발자 도구 Network 탭에서 응답 헤더를 확인한다.

각 헤더가 막는 공격은 다르다. X-Frame-Options가 없으면 공격자가 내 사이트를 투명한 iframe으로 자기 페이지에 겹쳐 올리고, 사용자가 "무료 쿠폰" 버튼을 누른다고 믿는 순간 실제로는 내 사이트의 "결제" 버튼을 누르게 만든다(클릭재킹). Content-Security-Policy는 XSS의 마지막 방어선으로, 공격자가 스크립트를 심는 데 성공해도 허용되지 않은 출처의 스크립트 실행을 브라우저가 차단한다.

# Nginx — 핵심 보안 헤더
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Content-Security-Policy "default-src 'self'" always;

직접 확인하는 법: F12로 개발자 도구를 열고 Network 탭에서 문서 요청을 클릭, Response Headers에서 위 4개 헤더가 있는지 본다. 없으면 그만큼 무방비다.

조치: 4개 헤더를 웹서버 설정에 추가한다. CSP는 사이트를 깨뜨릴 수 있으니 Content-Security-Policy-Report-Only로 먼저 관찰한 뒤 적용하는 게 안전하다.

5. 기본 관리자 경로 변경

/admin, /wp-admin, /dashboard 같은 기본 경로를 그대로 쓰면 자동화 공격의 첫 번째 타깃이 된다. 관리자 페이지 경로를 변경하고, IP 제한이나 2FA를 추가한다.

봇은 새 사이트를 발견하면 흔한 관리자 경로 수백 개를 초당 단위로 두드린다. 로그인 페이지가 노출되면 그다음은 자동 대입 공격(크리덴셜 스터핑)이다. 다른 사이트에서 유출된 아이디·비밀번호 조합 수백만 건을 그대로 넣어본다. 사용자가 같은 비밀번호를 재사용했다면 그대로 뚫린다. 경로 변경은 완벽한 방어가 아니라 자동화 스캔의 노이즈를 걷어내는 첫 단계이고, 진짜 방어는 그 뒤의 인증 강화다.

직접 확인하는 법: 시크릿 창(로그아웃 상태)에서 yourdomain.com/admin, /wp-login.php에 접속한다. 로그인 폼이 바로 뜨고 접속 IP 제한이 없다면 노출 상태다.

조치: 우선순위는 (1) 2단계 인증(2FA) 적용 → (2) 관리자 페이지 IP 화이트리스트 또는 VPN 뒤로 이동 → (3) 경로 변경 순이다. 경로만 바꾸고 인증을 방치하는 건 잠금장치 없이 문패만 떼는 것과 같다.

6. 에러 페이지에서 정보 유출

존재하지 않는 URL에 접속했을 때 서버 정보(Apache/2.4.41, Python/3.12)가 노출되는지 확인한다. 커스텀 404/500 페이지를 설정하고, 서버 버전 정보를 응답 헤더에서 제거한다.

버전 번호는 공격자에게 지도다. Server: Apache/2.4.41이 보이면 그 버전에 알려진 공개 취약점(CVE)을 그대로 찾아 대입한다. 정찰(reconnaissance) 시간을 몇 초로 줄여주는 셈이다. X-Powered-By: PHP/7.4.3, X-Powered-By: Express 같은 헤더도 마찬가지로 프레임워크와 버전을 자백한다.

# Nginx — 버전 노출 제거
server_tokens off;

# Express (Node.js) — X-Powered-By 제거
app.disable('x-powered-by');

직접 확인하는 법: 개발자 도구 Network 탭 Response Headers에서 Server, X-Powered-By 항목에 버전 숫자가 붙어 있는지 본다. Server: nginx처럼 버전 없이 나오거나 아예 없어야 좋다.

조치: 서버 토큰 노출을 끄고 커스텀 404/500 페이지를 설정한다. 버전을 숨긴다고 취약점이 사라지는 건 아니므로, 근본적으로는 서버·프레임워크를 최신 버전으로 유지하는 게 우선이다.

7. 쿠키 보안 속성

로그인 후 브라우저 개발자 도구에서 쿠키를 확인한다. Secure, HttpOnly, SameSite 속성이 설정되어 있는지 체크한다. 하나라도 빠지면 세션 탈취 위험이 있다.

세 속성은 각각 다른 공격을 막는다. HttpOnly가 없으면 XSS로 심어진 자바스크립트가 document.cookie로 세션 쿠키를 읽어 공격자 서버로 전송한다. Secure가 없으면 4번에서 본 것처럼 평문 HTTP 구간에서 쿠키가 새어 나간다. SameSite가 없으면 다른 사이트에서 넘어온 요청에도 쿠키가 자동으로 붙어 CSRF 공격에 노출된다. 세션 쿠키 하나가 곧 로그인 상태이므로, 이 쿠키가 새면 비밀번호가 아무리 강해도 무의미하다.

// 위험 — 보호 속성 없음
Set-Cookie: session=abc123

// 안전 — 세 속성 모두 적용
Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Lax

직접 확인하는 법: 로그인 후 개발자 도구 → Application(또는 Storage) 탭 → Cookies에서 세션 쿠키 행의 HttpOnly·Secure·SameSite 열에 체크가 있는지 본다.

조치: 프레임워크 세션 설정에서 세 속성을 켠다(Django SESSION_COOKIE_SECURE=True, SESSION_COOKIE_HTTPONLY=True, SESSION_COOKIE_SAMESITE='Lax'). 결제·로그인처럼 민감한 세션은 SameSite=Strict까지 고려한다.

8. 불필요한 포트 차단

80, 443 외에 열려 있는 포트가 있는지 확인한다. DB 포트(3306, 5432), Redis(6379)가 외부에 열려 있으면 직접 접속 시도가 가능하다.

특히 Redis(6379)와 MongoDB(27017)는 기본 설정에 인증이 없어, 외부에 열려 있으면 비밀번호 없이 데이터 전체를 읽고 지울 수 있다. 실제로 인터넷에 노출된 DB는 랜섬 봇의 단골 표적이다. 데이터를 통째로 지우고 "복구를 원하면 코인을 보내라"는 메시지만 남긴다. 인터넷에 노출된 서버 포트는 Shodan 같은 검색엔진에 이미 인덱싱돼 있어, 공격자는 스캔조차 할 필요 없이 취약한 DB를 검색으로 골라낸다.

# AWS Security Group — 외부에 열린 DB 포트 닫기
aws ec2 revoke-security-group-ingress \
  --group-id sg-xxxx \
  --protocol tcp --port 3306 \
  --cidr 0.0.0.0/0

직접 확인하는 법: 서버 밖(자기 노트북 등)에서 열린 포트를 점검한다. nmap yourdomain.com을 돌려 80·443 외 다른 포트가 open으로 뜨는지 본다. 또는 shodan.io에 서버 IP를 검색해 외부에서 무엇이 보이는지 확인한다.

조치: DB·캐시·검색엔진 포트는 클라우드 보안 그룹에서 0.0.0.0/0(전체 허용)을 제거하고, 애플리케이션 서버 IP나 내부 네트워크만 허용한다. 열어둘 이유가 없는 포트는 전부 닫는 게 기본이다.

8가지를 한 번에 확인하는 방법

위 항목을 하나씩 수동으로 확인하는 대신, URL 하나로 자동 점검할 수 있다. 보안 헤더, SSL, 포트, 환경변수 노출까지 17개 항목을 30초 만에 스캔한다. 보안 전문기업 SENTRIX가 레드팀 관점에서 설계한 스캐너로, 공격자가 실제로 먼저 확인하는 지점을 그대로 점검한다.

배포는 끝이 아니라 시작이다. SSL 인증서 만료, 새로 추가한 API의 인증 누락, 의존성 패키지의 신규 취약점은 배포 이후에도 계속 생긴다. 첫 점검으로 현재 상태를 확인한 뒤 정기 점검으로 이어가는 게 안전하다.

배포한 사이트 지금 바로 점검하기 →

[ ' ' , ' ' , ' ' , ' D e v O p s ' , ' C I / C D ' , ' ' ]

내 사이트도 점검해보세요

URL 하나면 21개 항목을 30초에 무료 점검합니다. 회원가입·카드 없이.

추천 상품
웹서비스 런칭 전 보안 세팅
런칭 전에 반드시 해야 하는 보안 설정을 원격으로 직접 해드립니다. HTTPS, 환경변수 분리, 보안 헤더…
220,000원 150,000원

AI 코딩 보안 체크리스트 받기

AI 코딩 보안 체크리스트(PDF)를 무료로 받아보세요.