Skip to content

API 식별자 난독화를 위한 Hashids 도입#228

Open
ckdals4600 wants to merge 2 commits into
mainfrom
feature/#55-encryption-utill
Open

API 식별자 난독화를 위한 Hashids 도입#228
ckdals4600 wants to merge 2 commits into
mainfrom
feature/#55-encryption-utill

Conversation

@ckdals4600
Copy link
Copy Markdown
Contributor

@ckdals4600 ckdals4600 commented May 15, 2026

관련 이슈

PR 설명

작업 내용

1. Hashids 유틸리티 도입 및 환경 설정

  • HashidUtils 구현: application.yml의 전용 Salt 값을 활용하여 인코딩(Long -> String) 및 디코딩(String -> Long)을 전담하는 컴포넌트를 구현함.
  • 인프라 변경 없이 애플리케이션 레이어에서만 동작하도록 설계하여 도입 비용을 최소화함.

2. Jackson 커스텀 직렬화/역직렬화 자동화

  • 커스텀 라이브러리 구현: HashidSerializerHashidDeserializer를 구현하여 DTO 변환 과정을 자동화함.
  • 아키텍처 분리: 서비스 및 레포지토리 계층에서는 기존 Long 타입을 유지하여 로직의 일관성을 확보하고, 외부 통신 계층(DTO)에서만 데이터가 투명하게 변환되도록 처리함.

3. @DecodeHash 어노테이션 및 Formatter 구현

  • 커스텀 어노테이션 추가: Controller의 파라미터 레벨에 적용할 수 있는 @DecodeHash 어노테이션을 생성
  • FormatterFactory 구현: 스프링의 데이터 바인딩 시점에 개입하여, 난독화된 문자열을 Long 타입으로 자동 파싱해주는 HashidsFormatterFactory를 구현
  • WebMvcConfig 등록: 구현한 FormatterFactory를 스프링 FormatterRegistry에 등록하여 전역적으로 동작하도록 설정

3. API 적용 및 컨트롤러 보완

  • DTO 적용: LinkResponseDto 등 외부 노출 DTO의 ID 필드에 @JsonSerialize, @JsonDeserialize 어노테이션을 반영함.
  • Controller 간소화: @PathVariable 또는 @RequestParam@DecodeHash 어노테이션만 선언하면, 프론트엔드에서 넘어온 Hash 문자열이 자동으로 Long 타입 식별자로 바인딩됩니다.

2. Swagger(OpenAPI) 문서화 전역 자동

  • Controller 파라미터 자동화 (OperationCustomizer):
    • 구현체에 @DecodeHash만 선언하면 Swagger 문서 상에 자동으로 string 타입과 예시 값(aB9x2K8R)이 완벽하게 매핑되도록 커스터마이징함.
  • DTO 필드 자동화 (PropertyCustomizer):
    • DTO 내부 식별자 필드마다 중복 작성되던 지저분한 @Schema(type = "string", ...) 설정을 완전히 제거함.
    • Jackson의 @JsonSerialize@JsonDeserialize 속성을 추적·스캔하여, 해시 난독화 시리얼라이저를 사용하는 모든 DTO 필드가 Swagger 상에서 자동으로 string 타입으로 기술되도록 완전 자동화를 구현함

@ckdals4600 ckdals4600 linked an issue May 15, 2026 that may be closed by this pull request
@ckdals4600 ckdals4600 force-pushed the feature/#55-encryption-utill branch 2 times, most recently from 63ed3de to a875573 Compare May 15, 2026 12:28
@ckdals4600 ckdals4600 self-assigned this May 15, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 16, 2026

📊 코드 커버리지 리포트

Overall Project 93.65% 🍏
Files changed 100% 🍏

File Coverage
LinkController.java 100% 🍏
CommonErrorCode.java 100% 🍏
FeedbackController.java 100% 🍏
HashidsUtils.java 100% 🍏
ChatController.java 78.57% 🍏

@ckdals4600 ckdals4600 requested review from Goder-0 and minibr May 16, 2026 01:20
@ckdals4600 ckdals4600 changed the title API 식별자 난독화를 위한 Hashids 도입 및 DTO 직렬화 자동화 API 식별자 난독화를 위한 Hashids 도입 May 16, 2026
@Goder-0
Copy link
Copy Markdown
Contributor

Goder-0 commented May 20, 2026

이 부분은 구현 의도를 한번 확인해보고 싶습니다.

현재 PR의 목표가 API 식별자를 해시 문자열로만 받도록 바꾸는 것이라면, 아직 raw numeric ID 입력이 그대로 허용되고 있는 것 같습니다. 같은 PR의 통합 테스트에서도 PATCH /v1/links/{id}/title, GET /v1/links/{id} 등에 link.getId() 같은 raw 값을 그대로 넣는 케이스가 남아 있고, 제가 PR ref 기준으로 해당 테스트를 실행해 봤을 때도 그대로 통과했습니다.

즉 응답 직렬화는 해시로 바뀌었지만, 입력 쪽에서는 숫자 ID를 계속 보낼 수 있어서 난독화 강제가 완전히 되지 않은 상태로 보이는데요. 이 부분은 의도된 호환 정책일까요, 아니면 @DecodeHash가 붙은 파라미터에서는 raw numeric ID를 거절하는 쪽이 맞을까요?

또한, 프론트의 즉각 대응이 이루어져야할 변경사항으로 보이는데요. 이 부분에 대해서도 의견 궁금합니다.

@ckdals4600
Copy link
Copy Markdown
Contributor Author

ckdals4600 commented May 20, 2026

이 부분은 구현 의도를 한번 확인해보고 싶습니다.

현재 PR의 목표가 API 식별자를 해시 문자열로만 받도록 바꾸는 것이라면, 아직 raw numeric ID 입력이 그대로 허용되고 있는 것 같습니다. 같은 PR의 통합 테스트에서도 PATCH /v1/links/{id}/title, GET /v1/links/{id} 등에 link.getId() 같은 raw 값을 그대로 넣는 케이스가 남아 있고, 제가 PR ref 기준으로 해당 테스트를 실행해 봤을 때도 그대로 통과했습니다.

즉 응답 직렬화는 해시로 바뀌었지만, 입력 쪽에서는 숫자 ID를 계속 보낼 수 있어서 난독화 강제가 완전히 되지 않은 상태로 보이는데요. 이 부분은 의도된 호환 정책일까요, 아니면 @DecodeHash가 붙은 파라미터에서는 raw numeric ID를 거절하는 쪽이 맞을까요?

또한, 프론트의 즉각 대응이 이루어져야할 변경사항으로 보이는데요. 이 부분에 대해서도 의견 궁금합니다.

꼼꼼한 리뷰 정말 감사합니다! 현재 raw numeric ID가 통과되고 있는 것은 의도된 하위 호환 정책이 아니라 Spring의 타입 변환 메커니즘이 만들어낸 엣지 케이스였습니다.

원인

  • 단순히 Formatter나 Converter 내부에서 디코딩 실패 시 BusinessException을 던지도록 구현했으나, Spring의 TypeConverterDelegate가 이 예외를 삼킨 뒤 숫자 형태이니 기본 Long 변환기 사용하는 자동 복구를 시도하여 raw numeric ID 값을 통과시켜버리는 현상이 있었습니다

해결 방법

검증 시점 격상

  • Spring이 자동 변환 하기 전에(Data Binding 이전), 파라미터를 먼저 가로채서 raw numeric Id를 원천 차단하는 DecodeHashInterceptor를 도입했습니다.
    인터페이스 기반 프록시 환경에서도 실제 컨트롤러의 어노테이션을 스캔하도록 구성했습니다.

명확한 에러 코드

  • 프론트엔드에서 단순한 파라미터 누락인지, 해시 변환을 안 한 것인지 직관적으로 파악할 수 있도록 해시 전용 커스텀 에러 코드 C-011 (INVALID_IDENTIFIER)를 신설하여 400 에러를 반환하도록 수정했습니다.

말씀하신 대로 난독화가 강제되었기 때문에, 프론트엔드 팀에서도 즉각적인 대응이 필요할 것 같습니다.
또한 통합 테스트 코드들도 해시를 전달하도록 모두 수정해 두었습니다.

@Goder-0
Copy link
Copy Markdown
Contributor

Goder-0 commented May 22, 2026

리베이스 부탁드립니다.

@ckdals4600 ckdals4600 force-pushed the feature/#55-encryption-utill branch 3 times, most recently from 6700685 to d6a7ba2 Compare May 22, 2026 17:42
- @DecodeHash의 raw numeric ID 통과 취약점 수정 및 검증 인터셉터 도입
- Hashids 난독화에 따른 Swagger 문서화 전역 자동화
- PathVariable Hashids 난독화를 위한 @DecodeHash 도입
@ckdals4600 ckdals4600 force-pushed the feature/#55-encryption-utill branch from d6a7ba2 to 12602ed Compare May 22, 2026 19:38
@ckdals4600
Copy link
Copy Markdown
Contributor Author

ckdals4600 commented May 22, 2026

리베이스 부탁드립니다.

@Goder-0 리베이스 및 커밋 정리 완료하였습니다.

Copy link
Copy Markdown
Contributor

@Goder-0 Goder-0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

작업이 완료되었다고 판단되어 승인합니다.
한편, 프론트 대응작업으로 Team-SoFa/linkiving#517 이슈를 생성하였습니다. 해당 이슈를 해결하는 PR이 올라온 이후 머지가 되는것이 좋을 것 같습니다.

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.

암호화 유틸리티 추가

2 participants