개발

비밀로그 자체 스캐닝 및 공격 (2025년 8월 5일)

정재익 2025. 8. 5. 23:57

ZAP을 이용한 스캐닝과 공격으로 비밀로그의 취약점을 진단했습니다.

이 글은 취약점을 해결한 이후에 공개로 전환될 예정입니다.
 

1. 개요

본 보고서는 ZAP(Zed Attack Proxy) 스캔 결과를 바탕으로 작성된 종합 보안 보고서입니다. 비밀로그의 현재 보안 상태를 평가하고 각 문제에 대한 상세 분석과 조치 사항을 작성했습니다.

스캐닝 뿐만 아니라 파일취약공격, SQL 인젝션, XSS등 약 30가지 이상의 공격들을 총 2만번 시행했는데 모두 방어할정도로 기본 보안은 나쁘지 않았습니다.
하지만 스캐닝에서 검출된 취약점을 보완하겠습니다

2. 취약점 요약

ZAP 스캔 결과, 총 11개의 경고가 감지되었습니다. 취약점의 리스크 레벨별 분포는 다음과 같으며, 정보성 리스크는 여기 적지 않았습니다.

  • 높음(High): 0건
  • 중간(Medium): 6건
  • 낮음(Low): 5건

다음은 리스크(Risk)와 신뢰도(Confidence) 수준에 따른 알림 수를 나타낸 표입니다.

리스크 \ 신뢰도 High Medium Low
High 0 0 0
Medium 5 1 0
Low 1 4 0

 

3. 리스크 / 신뢰도별 상세 분석

 
3.1. 중간(Medium) 리스크 / 높음(High) 신뢰도
총 5건이 발견되었으며, 주로 Content Security Policy(CSP) 및 헤더 설정과 관련된 문제였습니다.

  • CSP: Failure to Define Directive with No Fallback
  • CSP: Wildcard Directive
  • CSP: script-src unsafe-eval
  • CSP: script-src unsafe-inline
  • CSP: style-src unsafe-inline

 
CSP: Failure to Define Directive with No Fallback
frame-ancestors 지시어가 CSP에 정의되지 않아 공격자가 자신의 사이트의 iframe에 비밀로그를 끼워넣을 수 있습니다. 이른바 클릭재킹 공격이 가능합니다.

Next.js 서버와 스프링시큐리티에 frame-ancestors 'self' 설정으로 방어했습니디

 
CSP: Wildcard Directive
와일드카드로 인해 이미지 소스와 연결 소스의 범위가 넓다는 경고였습니다. 이 취약점은 공격자가 악성UI를 보여줄 수 있거나 임의의 외부 도메인에서 비밀로그로 요청을 보내는게 허용되어 정보가 유출될 수 있습니다.

와일드카드 사용을 중지하고 필요한 도메인만 명시하는 방법을 사용으로 방어했습니다
 
CSP: script-src unsafe-eval
스타일소스나 스크립트 소스에 unsafe-eval이 포함되어 있다는 경고입니다. 이 취약점은 공격자가 악성 스크립트에서 임의의 자바스크립트 코드 실행이 가능해집니다. XSS, 데이터 탈취, 세션 탈취, 악성코드 배포가 가능하기 때문에 방어해야합니다.

Next.js 서버와 스프링시큐리티에 unsafe-eval 제거로 방어했습니다

CSP: script-src style-src unsafe-inline

해당 설정은 인라인 스크립트 및 스타일 사용을 허용하여 XSS 공격의 잠재적 위험을 내포하고 있습니다. 이를 근본적으로 해결하려면 프론트엔드 전반의 구조를 리팩토링해야 하므로, 현재는 중장기 개선 과제로 설정해두었습니다.

다만, 다음과 같은 이유로 기본적인 방어 체계를 넘는 수준의 대응이 이루어졌다고 판단합니다.

1. ZAP을 통한 7천번 이상의 XSS 공격 시도를 모두 방어하였습니다.
2. CSP의 다른 주요 설정( `unsafe-eval`, `wildcard directive`)들을 모두 방어 하였습니다.
3. 서버 내부에서는 모든 사용자 입력에 대해 Sanitizer를 통한 검증 및 정제가 수행되고 있습니다.

위와 같은 조치를 기반으로, 현 시점에서는 `unsafe-inline` 설정이 실제 보안 위협으로 작용할 가능성은 낮다고 판단됩니다.

향후 CSP 개선 시에는 `nonce` 기반 스크립트 실행 제어 방식 또는 스타일 파일 외부화 방식으로 구조 개선을 고려 중입니다.

3.2. 중간(Medium) 리스크 / 중간(Medium) 신뢰도
총 1건이 발견되었습니다.
클릭재킹 방지 헤더가 없다는 경고입니다.

여기에서는 frame-ancestors 'self' 뿐만 아니라 X-Frame-Options으로 구버전의 브라우저와 호환도 같이 요구하고 있습니다.

스프링서버에는 해당 보안 설정이 이미 있었기때문에 프론트 서버에 추가 적용하여 방어했습니다.

 
3.3. 낮음(Low) 리스크 / 높음(High) 신뢰도
총 1건이 발견되었습니다

Strict-Transport-Security 헤더 설정 경고입니다.
HSTS관련 경고입니다. 비밀로그는 기본적으로 http의 요청은 https로 리다이렉트 시키고 있지만 그 사이를 포착하면 중간자 공격이 가능할 수 있습니다. HSTS를 설정하여 브라우저가 자동으로 HTTPS로 접속하게 해야합니다.
스프링서버와 Next.js 서버에 관련 설정을 하여 방어했습니다.
 
3.4. 낮음(Low) 리스크 / 중간(Medium) 신뢰도
총 4건이 발견되었습니다

csrf토큰의 쿠키설정에 httpOnly가 없다는 경고
csrf토큰의 쿠키설정에 SECURE가 없다는 경고
csrf토큰의 쿠키설정에 samesite설정이 없다는 경고
X-Powered-By 응답 헤더 존재

 
csrf토큰에 secure와 samesite lax설정을 하여 방어했습니다. 다만 httponly 설정은 하면 안됩니다.
비밀로그는 rest api방식에 jwt와 csrf토큰을 사용하여 이중방어를 하고 있습니다. csrf토큰은 자체적으로 쿠키매니저로 만들어 xor핸들러를 통해 breach공격 방어를 하고있습니다. 때문에 프론트에서 csrf토큰을 1차로 읽어들이고 2차에서 서버로 검증하는 절차가 필요하기 때문에 httponly설정을 하지 않는 것이 맞습니다.
 
X-Powered-By 응답헤더는 자신이 어떤 기술로 동작하는지 알려줘서 취약점을 늘릴수 있습니다. 다만 이 헤더를 통해 로드밸런서나 프록시 서버가 요청을 적절한 서버로 라우팅하는 것에 도움을 줄 수도 있고 단순히 Next.js로 동작한다는 것을 아는것만으로 큰 피해를 입지는 않을 것 같습니다.
 
Next.js서버는 이미 웹 상에서 다양하게 사용되고 있는 서버고 만약 어떤 기술로 동작하는지를 숨기더라도 공격당할것은 공격을 당할것이고 막을 것은 막을 것입니다. 따라서 헤더를 숨겨 네트워크의 유연성을 감소시키는 것보단 근본적인 보안에 더 신경을 쓰는게 우선이라고 생각합니다. 실제로 ZAP이 실행한 XSS, 클릭재킹, SQL인젝션등 수만번의 각종 공격에 비밀로그는 한번도 뚫리지 않았습니다. 따라서 X-Powered-By 헤더를 없애는 것은 오히려 유연성을 감소시키는 일이라고 생각합니다.
 
 

3. 결론

본 ZAP 스캔 결과, 웹 애플리케이션은 심각한 High 리스크 취약점은 없었지만, Medium 리스크의 CSP 및 헤더 누락 문제와  Low 리스크의 보안 헤더 설정 오류를 확인했습니다. 

리스크 \ 신뢰도 High Medium Low
High 0 0 0
Medium 2 0 0
Low 0 2 0


11개의 경고를 4개의 경고로 감소 시켰으며 낮은 위험의 2개 경고는 csrf토큰의 httponly쿠키 미설정과 X-Powered-By 헤더 경고입니다. 해당 경고는 본론에 적은 것과 같은 이유로 조치하지 않았습니다. 사실상 경고 목록에서 제거해도 됩니다.

중간 위험 경고 2개는 script-src와 style-src의 unsafe-inline 경고로 본문에 적었듯이 당장 현재로서는 실제 보안 위협으로 판단하기 힘들고 중장기 적으로 해결해야할 과제입니다.

 

결론적으로 zap을 이용한 스캐닝으로 비밀로그의 전체적인 취약점들을 알아냈고 중장기 적으로 해결해야 할 unsafe-inline을 빼고 전부 해결하였으며 zap을 이용한 30가지 종류 이상의 해킹 수만번을 전부 방어하였습니다.