권한관리(SFR-001): - getAuthorities() 구현(EgovUserAuthorityDAO), AuthorityInterceptor 역할별 URL 접근제어 (COMTNMENUCREATDTLS×COMTNMENUINFO×COMTNPROGRMLIST 메뉴권한 기반, 캐시/TTL, ROLE_ADMIN 바이패스) - 권한 신청·승인 워크플로 + AUTHOR_CHANGE_HISTORY 이력(3년 보관), 조회·다운로드 계정관리(SFR-002): 계정관리정책, 장기미사용(휴면) 확장(취급자 포함)·사전알림, 계정잠금 5회 인증체계(SFR-003): 로그인 통합 2단계 인증(SecondFactorInterceptor+SecondFactorController), OTP QR 등록(ZXing)·비밀키 DB 영속(OTP_DEVICE, AES-GCM), 세션재발급(고정공격 방지), 자동로그아웃 30분 접속기록(SFR-004): PERSONAL_DATA_ACCESS_LOG(월파티션), PersonalDataLogAspect 한정수집, SHA-256 해시체인 무결성, 업무유형매핑, IP 취득보정, 비정상접근 탐지, 정기점검 리포트 DB: privacy DDL 11종 + 설치용 통합 SQL(privacy.install_mysql.sql, DDL+시드 DML) 빌드복구: pom.xml 시스템 jar/JAXB 선언, iBatis2 SQL주석 '#'→'No.' 정정 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
64 lines
4.3 KiB
Markdown
64 lines
4.3 KiB
Markdown
# 비밀번호 해시 알고리즘 점검노트 (개발항목 #27)
|
|
|
|
> 사업: 문화품앗이 개인정보보호 기능개선 (Ⅲ-3 인증체계 / SER-003 인증정보 보호)
|
|
> 점검일: 2026-07-21 | 점검자: Fork C(인증체계) | 대상: `EgovFileScrty.encryptPassword()`
|
|
> 성격: **점검(진단)만 수행 — 소스 미수정.** 조치는 후속 개발항목에서 진행.
|
|
|
|
---
|
|
|
|
## 1. 결론 (요약)
|
|
|
|
**알고리즘은 SHA-256으로 「개인정보의 안전성 확보조치 기준」의 일방향 암호화(SHA-256 이상) 요건을 충족한다. 다만 실제 운영 경로가 무솔트(no-salt) 오버로드를 사용하고, 반복(iteration)이 없으며, 해시값을 stdout으로 출력하는 잔존 코드가 있어 3건의 보완이 권고된다.**
|
|
|
|
| 점검 항목 | 판정 | 근거 |
|
|
|-----------|:----:|------|
|
|
| 해시 알고리즘 SHA-256 이상 | ✅ 충족 | `MessageDigest.getInstance("SHA-256")` |
|
|
| 솔트(salt) 적용 | ⚠ 미흡 | 실제 경로가 무솔트 오버로드 사용, 솔트 API는 미사용 |
|
|
| 키 스트레칭(반복) | ⚠ 미흡 | 1회 다이제스트, iteration/work-factor 없음 |
|
|
| 검증 시 상수시간 비교 | ✅ 양호 | `checkPassword`가 `MessageDigest.isEqual` 사용(단, 미사용) |
|
|
| 인증정보 로그 노출 | ⚠ 미흡 | 해시값 `System.out.println` 잔존 |
|
|
|
|
---
|
|
|
|
## 2. 실측 상세
|
|
|
|
### 2-1. 알고리즘 (파일: `src/main/java/egovframework/com/utl/sim/service/EgovFileScrty.java`)
|
|
|
|
| 메서드 | 위치 | 알고리즘 | 솔트 | 인코딩 |
|
|
|--------|------|----------|:----:|--------|
|
|
| `encryptPassword(String data)` | L219~237 | SHA-256 | ❌ 없음 | Base64 |
|
|
| `encryptPassword(String data, byte[] salt)` | L246~261 | SHA-256 (`md.update(salt)` 후 `digest`) | ✅ 있음 | Base64 |
|
|
| `checkPassword(String data, String encoded, byte[] salt)` | L271~281 | SHA-256 | ✅ 있음 | `MessageDigest.isEqual`(상수시간 비교) |
|
|
|
|
- 세 메서드 모두 **단일 패스 SHA-256**(반복/키 스트레칭 없음).
|
|
- 솔트 오버로드와 `checkPassword`는 구현되어 있으나 **실제 호출 지점이 없다**(주석 처리된 `main()` 테스트 L283~297에서만 참조).
|
|
|
|
### 2-2. 실제 사용 경로 — 무솔트 오버로드가 운영 경로
|
|
|
|
`encryptPassword(String)` (무솔트) 호출 지점(발췌):
|
|
|
|
| 경로 | 위치 | 성격 |
|
|
|------|------|------|
|
|
| **로그인 인증** | `EgovLoginServiceImpl.java:83` (`actionLogin` → `enpassword`) | 취급자/회원 로그인 검증 |
|
|
| 비밀번호 변경 | `EgovLoginServiceImpl.java:206`, `:237` | |
|
|
| 회원/사용자/업체 가입·변경 | `EgovUserManageServiceImpl`, `EgovMberManageServiceImpl`, `EgovEntrprsManageServiceImpl` 등 다수 | 저장 시 해시 |
|
|
| 프론트 회원관리 | `kr.or.arko.frt.biz.umt.web.*`, `kr.or.arko.frt.biz.merge.*` 등 | |
|
|
|
|
→ 로그인·가입·변경 등 **모든 실제 비밀번호 처리 경로가 무솔트 SHA-256**을 사용한다. 동일 평문 → 동일 해시가 되어 레인보우 테이블·동일비밀번호 식별에 취약.
|
|
|
|
### 2-3. 인증정보 로그 노출 (SER-003 / 중점점검 #61 인증정보노출 연계)
|
|
|
|
- `BizMberFrtManageController.java:553`
|
|
`System.out.println("3패스워드확인::" + EgovFileScrty.encryptPassword(mberManageVO.getPassword()));`
|
|
→ 비밀번호 해시값을 표준출력(로그)에 기록. 디버그 잔존 코드로 판단되며 제거 대상.
|
|
|
|
---
|
|
|
|
## 3. 권고 (조치는 후속 항목에서)
|
|
|
|
1. **솔트 전면 적용** — 운영 경로를 솔트 오버로드(`encryptPassword(String, byte[])`) + `checkPassword`로 이설. 사용자별 랜덤 솔트를 생성·저장(가입 시)하고 검증은 `checkPassword`(상수시간 비교)로 통일. 기존 무솔트 해시는 로그인 성공 시점 재해시(rehash-on-login) 방식으로 점진 마이그레이션.
|
|
2. **키 스트레칭 검토** — 단일 SHA-256 대신 반복(iteration) 적용 또는 표준 비밀번호 해시(PBKDF2 등)로의 상향을 발주기관과 협의. (기준상 SHA-256은 충족이나, 브루트포스 내성 강화 관점의 개선 권고.)
|
|
3. **해시값 로그 출력 제거** — `BizMberFrtManageController.java:553`의 `System.out.println` 삭제. 신규·변경 코드에 인증정보(비밀번호/해시/OTP비밀키) 출력 금지 규칙 적용(보안·품질 #61과 연계 점검).
|
|
|
|
> 본 점검은 진단 단계 산출물이며, 위 3건의 실제 코드 수정은 별도 개발항목 승인 후 진행한다.
|