MessageDigest를 사용한 암호화 해시
SHA-256으로 비밀번호를 해시하고 레인보 테이블 공격을 막기 위해 솔트를 추가하며 다이제스트를 안전하게 비교합니다.
MessageDigest를 사용한 암호화 해시은(는) CoddyKit의 무료 Java Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Java Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
암호학적 해시란 무엇입니까
암호학적 해시 함수는 크기에 관계없이 모든 데이터를 고정된 크기의 다이제스트로 매핑합니다. 단방향이므로 되돌릴 수 없고, 결정적이며, 충돌에 강합니다. 비밀번호 저장, 데이터 무결성 및 디지털 서명에 사용됩니다.
MessageDigest API
MessageDigest.getInstance("SHA-256")는 SHA-256 다이제스터를 반환합니다. digest(bytes)를 호출하면 해시를 계산하고 바이트 배열을 얻을 수 있습니다.
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest("password123".getBytes(StandardCharsets.UTF_8));
String hex = HexFormat.of().formatHex(hash);
System.out.println(hex); // 64-char hex string일반적인 알고리즘
JDK는 다음을 지원합니다. MD5(손상되었으므로 보안 용도로 절대 사용하지 마십시오), SHA-1(보안 용도로 더 이상 권장되지 않음), SHA-256(표준), SHA-512(더 강력함), SHA3-256(최신). 새 코드에는 항상 SHA-256 또는 SHA-512를 사용하십시오.
MessageDigest.getInstance("SHA-256"); // recommended
MessageDigest.getInstance("SHA-512"); // stronger
MessageDigest.getInstance("SHA3-256"); // SHA-3 family
// Never: MessageDigest.getInstance("MD5"); // cryptographically broken해시를 16진수 문자열로 변환하기
바이트 배열 결과는 저장하거나 비교할 수 있도록 16진수 문자열로 변환해야 합니다. Java 17 이상에서는 HexFormat을, 이전 버전에서는 String.format을 사용하십시오.
// Java 17+:
String hex = HexFormat.of().formatHex(hash);
// Older Java:
StringBuilder sb = new StringBuilder();
for (byte b : hash) sb.append(String.format("%02x", b));
String hex = sb.toString();솔트: 레인보 테이블 무력화
레인보 테이블은 일반적인 비밀번호와 해당 해시를 연결해 둔 표입니다. 해시하기 전에 각 비밀번호에 임의의 값을 추가하면 레인보 테이블을 무용지물로 만들 수 있습니다. 해시와 함께 솔트도 저장하십시오.
SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(salt);
byte[] hash = md.digest("password".getBytes(StandardCharsets.UTF_8));
// Store: Base64.encode(salt) + ":" + Base64.encode(hash)비밀번호 해싱 — 대신 BCrypt 사용
솔트를 사용한 SHA-256은 일반적인 SHA-256보다 낫지만 여전히 빠르므로 공격자가 초당 수십억 번 추측할 수 있습니다. 느린 KDF를 사용하십시오. 비밀번호에는 BCryptPasswordEncoder(Spring Security) 또는 PBKDF2와 Argon2를 사용하십시오.
// Spring Security — proper password hashing:
PasswordEncoder encoder = new BCryptPasswordEncoder(12); // cost factor 12
String hash = encoder.encode("password123");
boolean match = encoder.matches("password123", hash); // true파일 무결성 확인
파일을 해시하면 손상이나 변조를 감지할 수 있습니다. 계산한 해시를 신뢰할 수 있는 기준값과 비교하십시오.
MessageDigest md = MessageDigest.getInstance("SHA-256");
try (InputStream is = Files.newInputStream(Path.of("app.jar"))) {
byte[] buf = new byte[8192];
int n;
while ((n = is.read(buf)) > 0) md.update(buf, 0, n);
}
String hash = HexFormat.of().formatHex(md.digest());
System.out.println("SHA-256: " + hash);안전한 해시 비교
타이밍 공격을 방지하려면 일정한 시간의 비교를 수행하는 MessageDigest.isEqual()을 사용하십시오. 해시를 비교할 때는 String.equals()를 절대 사용하지 마십시오.
byte[] expected = computeHash(storedHash);
byte[] actual = computeHash(inputPassword);
boolean match = MessageDigest.isEqual(expected, actual); // constant-time업데이트 연속 처리
여러 조각으로 도착하는 데이터(스트리밍)를 해시하려면 md.digest()를 호출하기 전에 md.update(bytes)를 여러 번 호출하십시오.
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update("part1".getBytes());
md.update("part2".getBytes());
byte[] hash = md.digest(); // hash of "part1" + "part2"저장을 위한 해시 인코딩
이진 해시는 Base64(16진수보다 짧음) 또는 16진수 문자열로 저장하십시오. Base64는 SHA-256에 16진수의 64자보다 짧은 43자를 사용합니다. 둘 다 올바르므로 일관되게 사용하십시오.
byte[] hash = md.digest(data);
String base64 = Base64.getEncoder().encodeToString(hash); // 44 chars (with padding)
String hex = HexFormat.of().formatHex(hash); // 64 chars스트리밍을 위한 DigestInputStream
InputStream을 DigestInputStream으로 감싸면 읽는 동시에 해시를 계산할 수 있어 전체 파일을 메모리에 불러오지 않아도 됩니다.
MessageDigest md = MessageDigest.getInstance("SHA-256");
try (DigestInputStream dis = new DigestInputStream(Files.newInputStream(path), md)) {
dis.transferTo(OutputStream.nullOutputStream());
}
String hash = HexFormat.of().formatHex(md.digest());빠른 확인
솔트를 사용한 SHA-256이 여전히 비밀번호 저장에 권장되지 않는 이유는 무엇입니까
복습
데이터 무결성 검사에는 MessageDigest.getInstance("SHA-256")을 사용하십시오. 비밀번호에는 항상 솔트를 추가하되, 원시 SHA가 아니라 BCrypt 또는 Argon2를 비밀번호 저장에 사용하십시오. 타이밍 공격을 방지하려면 일정한 시간의 비교(MessageDigest.isEqual)를 사용하십시오.
자주 묻는 질문
“MessageDigest를 사용한 암호화 해시” 강의는 무료인가요?
네 — “MessageDigest를 사용한 암호화 해시” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Java Academy 강의 전체를 잠금 해제할 수 있습니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“MessageDigest를 사용한 암호화 해시”에서 뭘 배우나요?
SHA-256으로 비밀번호를 해시하고 레인보 테이블 공격을 막기 위해 솔트를 추가하며 다이제스트를 안전하게 비교합니다. 브라우저에서 직접 실행하는 실습 코드로 Java Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Java Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Java Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.
“MessageDigest를 사용한 암호화 해시” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Java Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Java Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- MessageDigest를 사용한 암호화 해시
- AES 대칭 암호화
- 메시지 무결성을 위한 HMAC-SHA256
- JWT: 구조, 생성 및 검증