Skip to content

feat: require app key header on API requests - #184

Merged
isoo127 merged 1 commit into
developfrom
feat/app-key
Sep 23, 2026
Merged

isoo127 merged 1 commit into
developfrom
feat/app-key

Conversation

@isoo127

@isoo127 isoo127 commented Sep 23, 2026

Copy link
Copy Markdown
Member

✏️ 작업 개요

모든 /api 요청에 x-app-key 헤더 검사를 추가했습니다. 공식 앱이 아닌 클라이언트(토큰만 확보한 스크립트 등)가 API를 직접 호출하는 것을 막기 위함이고, 키 값은 APP_KEY 환경변수로 주입합니다.

로그인·회원가입처럼 토큰 없이 열려 있는 엔드포인트까지 포함해 /api/** 전체가 대상입니다. 다만 어드민 대시보드는 브라우저에서 동작해 키를 들고 있을 수 없으므로, ADMIN으로 인증된 요청은 검사에서 면제됩니다.

🔨 작업 상세 내용

  1. 앱키 검사 필터 추가 (AppKeyAuthenticationFilter)

    • 대상은 /api/**. 헤더가 없거나 값이 다르면 **403 G403**으로 차단합니다
    • 키 비교는 MessageDigest.isEqual로 상수 시간 비교하고, 키가 여러 개여도 단축평가 없이 전부 비교해서 어느 키에 걸렸는지가 응답 시간으로 새지 않게 했습니다
    • JWT 인증 필터 뒤에 등록됩니다. ADMIN 인증 요청을 면제하려면 인증 결과를 봐야 하기 때문입니다
    • /admin/**, /actuator/**, /docs, 정적 리소스는 검사 대상이 아닙니다
  2. 어드민 면제 방식

    • 어드민 페이지가 브라우저에서 /api/training/**, /api/puzzle/cache/**를 직접 호출합니다. 페이지 HTML에 키를 심는 방법도 있었지만, 키가 브라우저에 노출되지 않도록 ADMIN 인증 요청을 면제하는 쪽을 택했습니다
    • 따라서 앱키가 실제로 강제되는 것은 ADMIN이 아닌 주체의 /api/** 요청입니다
  3. 키 로테이션 / 비활성화

    • APP_KEY는 콤마 구분 목록을 받습니다. 새키,구키로 배포 → 앱 업데이트 확산 대기 → 새키만 남기기 순서로 무중단 교체가 가능합니다
    • 값이 비어 있으면 필터를 등록하지 않고 경고 로그만 남깁니다. 키 미설정 때문에 서버가 못 뜨는 상황을 피하기 위함입니다
  4. 환경변수 / 배포 설정

    • application.yml에 app.key: ${APP_KEY:} 추가, .env.example 갱신
    • ci.yml, cd-prod.yml, cd-test.yml의 빌드 env와 서버용 .env 생성 단계에 APP_KEY 추가
  5. 문서 / 테스트

    • OpenAPI에 x-app-key apiKey 스킴을 추가해 /docs에서 키를 넣고 호출할 수 있게 했습니다 (겸사겸사 SwaggerConfig → OpenApiConfig로 이름 변경)
    • 필터 단위 테스트 7건 추가(정상 / 누락 / 불일치 / 로테이션 / ADMIN 면제 / 비대상 경로)
    • 로컬 컨테이너를 실제로 띄워 확인했습니다. 키 없음·오류 키 → 403, 등록된 두 키 → 통과, 어드민 토큰(헤더·쿠키) → 키 없이 통과, APP_KEY 공백 → 검사 비활성화. 전체 테스트 275건 통과

💡 생각해볼 문제

  • 머지 전에 APP_KEY GitHub Secret 등록이 필요합니다. 지금은 시크릿이 없어서, 이대로 배포하면 빈 값이 들어가 검사가 꺼진 채로 나갑니다
  • 앱키는 앱 바이너리에 들어가는 값이라 프록시로 트래픽을 한 번만 보면 노출됩니다. 자동화 스크립트 수준의 남용을 막는 진입장벽이지 결정적 방어는 아니고, 유출되면 위 로테이션 절차로 교체하면 됩니다

Check x-app-key against APP_KEY on every /api request, accepting a comma separated list so keys can be rotated, and skip the check for admin authenticated requests. An empty APP_KEY turns the check off.
@isoo127
isoo127 merged commit 69b9666 into develop Sep 23, 2026
1 check passed
@isoo127
isoo127 deleted the feat/app-key branch September 23, 2026 12:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant