지난 글인 AI로 만든 웹앱, 배포 전에 최소한 확인해야 할 보안 체크리스트에서는 배포 전에 확인해야 할 기본 보안 항목들을 정리했다.
이번 글에서는 그중에서도 소스코드나 서버 내부 설정을 보지 않고, 외부에서 확인할 수 있는 항목들을 정리해보려고 한다.
다만 먼저 전제부터 분명히 해야 한다.
보안 점검은 본인 소유이거나 명시적으로 허가받은 사이트에만 해야 한다.
이 글에서 말하는 점검은 공격적인 침투 테스트가 아니라, 배포된 웹앱의 외부 노출 상태를 확인하는 수준이다.
가장 먼저 확인할 것은 HTTPS다.
브라우저 주소창에서 자물쇠 표시가 보이는지 확인할 수 있고, 터미널에서는 아래처럼 헤더를 확인할 수 있다.
curl -I https://example.com
확인할 포인트는 다음과 같다.
HTTP에서 HTTPS로 리다이렉트되는지도 확인할 수 있다.
curl -I http://example.com
301, 308 같은 응답과 함께 Location: https://... 형태로 이동한다면 기본 방향은 맞다.
더 자세한 TLS 설정은 SSL Labs 같은 도구로도 확인할 수 있다.
보안 헤더는 브라우저에게 “이 사이트의 콘텐츠를 어떻게 다뤄야 하는지” 알려주는 설정이다.
확인은 간단하다.
curl -I https://example.com
대표적으로 볼 수 있는 헤더는 다음과 같다.
Strict-Transport-SecurityContent-Security-PolicyX-Frame-OptionsX-Content-Type-OptionsReferrer-PolicyPermissions-Policy각 헤더의 의미는 조금씩 다르다.
Strict-Transport-Security는 브라우저가 이후 접속에서 HTTPS를 우선 사용하도록 알려준다.
단, 이 헤더는 HTTPS 응답에서 전달되어야 의미가 있다.
Content-Security-Policy는 스크립트, 이미지, iframe 같은 리소스를 어떤 출처에서 불러올 수 있는지 제한한다.
XSS를 완전히 막아주는 것은 아니지만, 공격 영향을 줄이는 데 도움이 된다.
X-Frame-Options나 CSP의 frame-ancestors는 다른 사이트가 내 페이지를 iframe으로 끼워 넣는 것을 제한할 때 사용한다.
X-Content-Type-Options: nosniff는 브라우저의 MIME sniffing을 제한한다.
Referrer-Policy는 다른 사이트로 이동할 때 referrer 정보를 얼마나 보낼지 제어한다.
보안 헤더가 없다고 해서 곧바로 취약점이라고 단정할 수는 없다.
하지만 브라우저가 제공하는 방어 계층을 쓰지 않는 상태일 수는 있다.
MDN HTTP Observatory 같은 도구를 사용하면 이런 항목들을 한 번에 확인할 수 있다.
배포 과정에서 실수로 파일이 노출되는 경우가 있다.
예를 들면 이런 것들이다.
.env.git/configbackup.zipdb.sqlconfig.jsonserver.logadmin-backupold.zip이런 파일에는 DB 접속 정보, API secret, 내부 경로, 과거 소스코드가 포함될 수 있다.
확인은 본인 사이트에서만 해야 한다.
curl -I https://example.com/.env
curl -I https://example.com/.git/config
404 Not Found라면 보통 해당 경로에 파일이 없다는 뜻이다.
403 Forbidden은 접근이 차단된 상태일 수 있다.
반대로 200 OK와 함께 파일 내용이 내려온다면 즉시 조치가 필요하다.
robots.txt도 확인할 수 있다.
curl https://example.com/robots.txt
주의할 점은 robots.txt가 보안 장치가 아니라는 것이다.
검색엔진에게 크롤링 정책을 알려주는 파일일 뿐이고, 비밀 경로를 숨겨주는 기능은 아니다.
관리자 페이지가 존재하는 것 자체가 문제는 아니다.
문제는 인증 없이 접근 가능한 경우다.
예를 들면 이런 경로다.
/admin/dashboard/manage/test/dev/cms직접 만든 서비스라면 내가 만든 관리자/테스트 경로가 로그인 없이 열리는지 확인해야 한다.
정상적인 경우라면 다음 중 하나가 되어야 한다.
반대로 로그인하지 않았는데 관리자 화면이나 관리자 API 결과가 보인다면 위험하다.
URL을 모르면 접근할 수 없을 것이라는 기대는 보안이 아니다.
프론트엔드에서 버튼을 숨기는 것만으로도 부족하다.
서버/API 레벨에서 권한 검사가 필요하다.
도메인을 운영한다면 DNS 설정도 기본 점검 대상이다.
dig example.com
dig TXT example.com
dig TXT _dmarc.example.com
웹앱 보안과 직접 연결되는 항목도 있고, 운영 신뢰도와 연결되는 항목도 있다.
예를 들어 도메인으로 이메일을 보낸다면 SPF, DKIM, DMARC 설정을 확인하는 것이 좋다.
SPF는 이 도메인으로 메일을 보낼 수 있는 서버를 지정하는 방식이다.
DMARC는 SPF/DKIM 검사 결과를 바탕으로 수신 서버가 메일을 어떻게 처리할지 정책을 알려준다.
이 설정들이 없다고 웹앱이 바로 뚫리는 것은 아니다.
하지만 내 도메인을 사칭한 이메일이 악용될 가능성을 줄이는 데 도움이 된다.
또 하나 확인할 것은 오래된 DNS 레코드다.
사용하지 않는 서브도메인이 예전 클라우드 서비스나 호스팅 주소를 가리키고 있다면, 일부 환경에서는 서브도메인 탈취 위험으로 이어질 수 있다.
브라우저에 내려가는 JavaScript 번들은 사용자에게 공개된다고 봐야 한다.
프론트엔드 코드 안에 이런 값이 들어가 있으면 안 된다.
반대로 API endpoint, public key, 화면 라우트명 같은 정보가 보이는 것 자체가 항상 취약점은 아니다.
프론트엔드 애플리케이션에서는 어느 정도 공개될 수밖에 없다.
중요한 기준은 이것이다.
클라이언트에 공개되어도 되는 값인가?
브라우저 개발자 도구의 Network, Sources 탭을 보면 어떤 파일과 값이 내려가는지 확인할 수 있다.
소스맵(.map)도 운영 환경에서 공개할지 여부를 고민해야 한다.
소스맵 자체가 곧바로 취약점은 아니지만, 내부 코드 구조나 주석이 노출될 수 있다.
security.txt는 보안 취약점을 발견한 사람이 어디로 연락해야 하는지 알려주는 파일이다.
일반적으로 다음 경로에 둔다.
/.well-known/security.txt
예시는 이런 형태다.
Contact: mailto:security@example.com
Policy: https://example.com/security-policy
작은 서비스라면 꼭 필수는 아니지만, 보안 제보를 받을 의지가 있다면 준비해둘 만하다.
다만 security.txt를 만들어둔다고 서비스가 안전해지는 것은 아니다.
취약점 신고 채널을 명확히 하는 운영 장치에 가깝다.
여기까지의 항목들은 외부에서 어느 정도 확인할 수 있다.
하지만 이것만으로 “안전하다”고 말할 수는 없다.
외부 점검만으로 확인하기 어려운 것들이 있다.
이런 항목들은 테스트 계정, 소스코드, 서버 설정, DB 권한을 함께 봐야 한다.
그래서 외부 점검은 최종 보안 진단이라기보다 첫 번째 필터에 가깝다.
AI 개발 도구 덕분에 웹앱을 만드는 속도는 빨라졌다.
하지만 배포된 웹앱이 외부에서 어떻게 보이는지는 여전히 직접 확인해야 한다.
처음부터 완벽한 보안 진단을 하기는 어렵다.
그래도 아래 항목부터 확인하면 위험한 실수를 꽤 줄일 수 있다.
개인적으로는 AI로 만든 웹앱일수록 배포 직후 이런 질문을 해봐야 한다고 생각한다.
이 서비스는 기능적으로 동작하는가?
그리고 외부에 공개돼도 괜찮은 상태인가?
다음 글에서는 Supabase나 Firebase처럼 클라이언트에서 직접 DB/API를 사용하는 구조에서 특히 조심해야 할 권한 설정 문제를 정리해보려고 한다.