Repository navigation
[feat] 비밀번호 정책을 런타임 계약으로 노출 — 클라 사본이 낡아도 알 방법이 없다 #280
Description
문제
비밀번호 규칙의 정본은 PasswordValidation.REGEX 인데, 클라이언트가 이 값을 소스 수준에서 복제해야만 입력 중 피드백(규칙 충족 표시, 「다음」 버튼 활성)을 만들 수 있습니다. 서버 왕복으로는 매 키 입력을 판정할 수 없고, 타이핑 중인 비밀번호를 검증 목적으로 전송할 수도 없습니다.
복제 자체를 없애 달라는 요청이 아닙니다. 클라 쪽 규칙은 어떤 설계에서도 남습니다. 문제는 그 사본이 낡았는지 알 방법이 없다는 것입니다. 실제로 FE 정규식이 8~16자·특수문자 무제한 으로 어긋난 채 굳어 있었고(Afternote/Afternote-FE#1628), 사용자가 규칙 충족 표시를 전부 받은 뒤 제출에서 400 을 맞는 구간이 생겼습니다.
지금도 노출되기는 합니다 — 다만 계약이 아닙니다
springdoc(2.2.0)이 @Pattern 을 OpenAPI 스키마의 pattern 으로 내보내고 있음을 확인했습니다. @WebMvcTest + springdoc 으로 실제 /v3/api-docs 를 렌더해 측정했습니다(하니스는 기존 OpenApiGeneratedDocsTest 와 동일 구성):
SignupRequest.password pattern = ^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,15}$
PasswordChangeRequest.newPassword 동일
PasswordFindRequest.newPassword 동일
LoginRequest.password pattern 없음 ← 규칙 미적용과 일치
그런데 이 노출로는 클라가 문제를 못 닫습니다.
- 내려오는 건 자바 정규식 문자열 그대로입니다. 안드로이드의
java.util.regex는 ICU 백엔드라\d가 유니코드 Nd 범주까지 매칭합니다 — 전각1, 아라비아-인도١이 통과해 서버와 판정이 갈립니다. 클라는 이 문자열을 그대로 쓸 수 없고 반드시 손으로 옮겨 적어야 합니다(FE 는\d를[0-9]로 바꿔 씁니다). 정규식 문자열은 플랫폼 간 이식 가능한 계약이 아닙니다. MESSAGE는 스키마에 안 실립니다.description·example뿐입니다. 사용자에게 보여줄 안내 문구는 여전히 클라가 따로 적어야 하고, 그 결과 지금 시안·서버·클라 3자의 문구가 서로 다릅니다(fix(onboarding): 비밀번호 규칙을 서버와 같은 8~15자 허용 목록으로 좁힌다 (#1628) Afternote-FE#1644 참조)./v3/api-docs는 개발 문서 surface 입니다. 앱이 런타임에 물고 살 대상이 아니고, 스키마 형태 변경에 대한 안정성 보장도 없습니다.
제안 — 구조화된 정책 엔드포인트
GET /api/v1/auth/password-policy (무인증)
{
"minLength": 8,
"maxLength": 15,
"requiredCharClasses": ["ALPHA", "DIGIT", "SPECIAL"],
"allowedSpecialCharacters": "@$!%*#?&",
"message": "비밀번호는 8~15자의 영문, 숫자, 특수문자를 포함해야 합니다."
}정규식 문자열이 아니라 «구성 요소»로 내리는 것이 핵심입니다. 그래야 클라가 자기 플랫폼에서 정확한 판정을 조립하고(1번 함정 회피), 안내 문구까지 서버에서 받습니다(2번 해소). 규칙이 바뀌어도 앱 배포 없이 따라갑니다.
PasswordValidation.REGEX 를 이 정책 객체에서 파생시키면 서버 자신의 @Pattern 과 응답이 갈릴 일도 없습니다.
대안 — 서버 작업 없이 가는 길도 있습니다
FE 가 빌드 타임에 /v3/api-docs 의 pattern 을 읽어 규칙을 코드 생성하는 방법입니다. 다만 위 1·2번이 그대로 남아 반쪽입니다 — \d 는 손으로 고쳐야 하고 문구는 여전히 수기입니다. 우선순위 판단에 참고해 주십시오. 급한 이슈는 아닙니다.
클라이언트 상태
FE 는 지금 사본을 유지하되 표류를 막는 쪽으로 처리 중입니다 — 규칙을 한 곳(OnboardingPasswordRule)에 모으고 경계값 회귀 테스트로 고정합니다(Afternote/Afternote-FE#1644). 이 이슈는 그 작업의 선행 조건이 아니며, FE 가 대기하고 있지 않습니다. 이 이슈가 닫히면 사본을 「폴백 기본값 + 서버 응답 조립」으로 바꿉니다.
판정 리비전: origin/main 6364a6c (0831 deploy 성공 SHA, 실서버 동일). OpenAPI 노출은 위 하니스로 실측했고, 실서버 /v3/api-docs 직접 호출은 서버 점검 시간대(11:00 KST)라 하지 못했습니다.
Activity