Skip to content

fix: 비밀번호 인코더 선택이 로케일에 따라 달라지는 문제 수정 - #332

Open
wantaekchoi wants to merge 1 commit into
eGovFramework:mainfrom
wantaekchoi:fix/security-config-hash-switch-locale
Open

fix: 비밀번호 인코더 선택이 로케일에 따라 달라지는 문제 수정#332
wantaekchoi wants to merge 1 commit into
eGovFramework:mainfrom
wantaekchoi:fix/security-config-hash-switch-locale

Conversation

@wantaekchoi

Copy link
Copy Markdown
Contributor

수정 사유 Reason for modification

  • 버그수정 Bug fixes
  • 기능개선 Enhancements
  • 기능추가 Adding features
  • 기타 Others

수정된 소스 내용 Modified source

EgovSecurityConfiguration.passwordEncoder는 설정값 hash를 소문자로 정규화해 switch 키로 씁니다. 인자 없는 toLowerCase()는 JVM 기본 로케일을 따르므로, 터키어·아제르바이잔어 로케일에서 "PLAINTEXT"는 점 없는 ı가 섞인 "plaıntext"가 되어 case "plaintext"에 걸리지 않습니다.

그러면 default 분기로 빠지고 securityHash.startsWith("sha")도 아니므로 NoOpPasswordEncoder 대신 BCryptPasswordEncoder가 선택됩니다. 평문으로 저장된 비밀번호를 BCrypt로 검증하게 되어 로그인이 실패합니다.

같은 파일이 이미 정답을 갖고 있습니다. xframeOptions 분기는 같은 종류의 정규화를 Locale.ROOT로 합니다.

:488  switch (xfo.trim().toUpperCase(Locale.ROOT))   // 있음
:213  switch (securityHash.toLowerCase())            // 없음

AS-IS

String securityHash = (rawHash == null || rawHash.trim().isEmpty()) ? "sha-256" : rawHash.trim().toLowerCase();
...
switch (securityHash.toLowerCase()) {
...
    String algorithm = securityHash.replace("-", "").toUpperCase();

TO-BE

String securityHash = (rawHash == null || rawHash.trim().isEmpty()) ? "sha-256" : rawHash.trim().toLowerCase(Locale.ROOT);
...
switch (securityHash) {
...
    String algorithm = securityHash.replace("-", "").toUpperCase(Locale.ROOT);

switch 문의 securityHash.toLowerCase()는 바로 위에서 이미 정규화한 값을 다시 소문자화하던 것이라 함께 지웠습니다. authenticationManager의 같은 정규화에도 Locale.ROOT를 넣었습니다.

같은 결함 클래스를 Locale.ROOT로 고친 선례가 이 저장소에 있습니다 — DefaultMapUserDetailsMapping의 컬럼명 소문자화(#321).

영향 범위

ASCII 설정값은 기본 로케일이 무엇이든 결과가 같습니다. 바뀌는 것은 터키어 계열 로케일에서 i/I가 든 값뿐이고, 현재 switch 케이스 중에는 plaintext가 해당합니다.

JUnit 테스트 JUnit tests

  • JUnit 테스트 JUnit tests
  • 수동 테스트 Manual testing

EgovSecurityConfigurationHashLocaleTest 1건을 추가했습니다. 기본 로케일을 tr-TR로 바꾼 상태와 영어 로케일에서 각각 hash=PLAINTEXTNoOpPasswordEncoder로 해석되는지 봅니다.

수정 지점만 되돌린 상태(RED)

[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
[ERROR]   EgovSecurityConfigurationHashLocaleTest.plaintextHashResolvesUnderTurkishLocale
          터키어 로케일에서도 PLAINTEXT는 NoOp으로 해석되어야 한다
          ==> Unexpected type, expected: <NoOpPasswordEncoder> but was: <BCryptPasswordEncoder>

수정 후(GREEN, 모듈 전체)

[INFO] Tests run: 32, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS

EgovSecurityConfiguration.passwordEncoder는 설정값 hash를 소문자로 정규화해
switch 키로 쓴다. 인자 없는 toLowerCase()는 JVM 기본 로케일을 따르므로,
터키어·아제르바이잔어 로케일에서 "PLAINTEXT"는 점 없는 ı가 섞인 "plaıntext"가
되어 case "plaintext"에 걸리지 않는다.

그러면 default 분기로 빠지고 securityHash.startsWith("sha")도 아니므로
NoOpPasswordEncoder 대신 BCryptPasswordEncoder가 선택된다. 평문으로 저장된
비밀번호를 BCrypt로 검증하게 되어 로그인이 전부 실패한다.

같은 파일이 이미 정답을 갖고 있다. xframeOptions 분기는 같은 종류의 정규화를
Locale.ROOT로 한다.

  :488  switch (xfo.trim().toUpperCase(Locale.ROOT))

hash 쪽 정규화 두 곳과 알고리즘 이름 대문자화에 Locale.ROOT를 명시했다.
switch 문의 securityHash.toLowerCase()는 바로 위에서 이미 정규화한 값을 다시
소문자화하던 것이라 함께 지웠다.

같은 결함 클래스를 Locale.ROOT로 고친 선례가 이 저장소에 있다 —
DefaultMapUserDetailsMapping의 컬럼명 소문자화(eGovFramework#321).
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