Java Academy · บทเรียน

การแฮชเชิงเข้ารหัสด้วย MessageDigest

แฮชรหัสผ่านด้วย SHA-256 เติม salt เพื่อป้องกันการโจมตีด้วยตาราง rainbow และเปรียบเทียบไดเจสต์อย่างปลอดภัย

บทเรียน 1 จาก 413 ขั้นตอน

การแฮชเชิงเข้ารหัสด้วย MessageDigest เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

การแฮชเชิงเข้ารหัสคืออะไร

ฟังก์ชันแฮชเชิงเข้ารหัสจะแปลงข้อมูลที่มีขนาดใดก็ได้ให้เป็นค่าไดเจสต์ที่มีขนาดคงที่ ฟังก์ชันนี้เป็นแบบทางเดียว (ไม่สามารถย้อนกลับได้) ให้ผลแน่นอนเหมือนเดิม และต้านทานการชนกัน ใช้สำหรับจัดเก็บรหัสผ่าน ตรวจสอบความถูกต้องครบถ้วนของข้อมูล และสร้างลายเซ็นดิจิทัล

API MessageDigest

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

การแปลงแฮชเป็นสตริงเลขฐานสิบหก

ต้องแปลงผลลัพธ์อาร์เรย์ไบต์เป็นสตริงเลขฐานสิบหกเพื่อจัดเก็บหรือเปรียบเทียบ ใช้ HexFormat (Java 17 ขึ้นไป) หรือ 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();

ซอลต์: การเอาชนะตาราง Rainbow

ตาราง Rainbow จะจับคู่รหัสผ่านที่ใช้กันทั่วไปกับแฮชของรหัสผ่านเหล่านั้น การเติมซอลต์คือการเพิ่มค่าสุ่มให้กับรหัสผ่านแต่ละรายการก่อนแฮช ทำให้ตาราง Rainbow ใช้งานไม่ได้ ควรจัดเก็บซอลต์ไว้คู่กับแฮช

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.update(bytes) หลายครั้งก่อนเรียก md.digest() เพื่อแฮชข้อมูลที่มาถึงเป็นส่วน ๆ (แบบสตรีม)

MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update("part1".getBytes());
md.update("part2".getBytes());
byte[] hash = md.digest(); // hash of "part1" + "part2"

การเข้ารหัสแฮชเพื่อจัดเก็บ

จัดเก็บแฮชไบนารีเป็นสตริง Base64 (สั้นกว่าเลขฐานสิบหก) หรือสตริงเลขฐานสิบหก Base64 ใช้อักขระ 43 ตัวสำหรับ SHA-256 เทียบกับเลขฐานสิบหกที่ใช้ 64 ตัว ทั้งสองวิธีถูกต้อง — ขอเพียงใช้ให้สม่ำเสมอ

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") เพื่อตรวจสอบความถูกต้องครบถ้วนของข้อมูล เติมซอลต์ให้รหัสผ่านเสมอ แต่สำหรับการจัดเก็บรหัสผ่าน ให้ใช้ BCrypt/Argon2 ไม่ใช่ SHA แบบดิบ ใช้การเปรียบเทียบโดยใช้เวลาเท่ากันทุกกรณี (MessageDigest.isEqual) เพื่อป้องกันการโจมตีจากเวลา

เริ่มต้นได้ฟรี

เรียนรู้ Java ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
104
บทเรียน
374

คำถามที่พบบ่อย

บทเรียน “การแฮชเชิงเข้ารหัสด้วย MessageDigest” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การแฮชเชิงเข้ารหัสด้วย MessageDigest” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การแฮชเชิงเข้ารหัสด้วย MessageDigest”

แฮชรหัสผ่านด้วย SHA-256 เติม salt เพื่อป้องกันการโจมตีด้วยตาราง rainbow และเปรียบเทียบไดเจสต์อย่างปลอดภัย คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “การแฮชเชิงเข้ารหัสด้วย MessageDigest” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม

ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การแฮชเชิงเข้ารหัสด้วย MessageDigest
  2. การเข้ารหัสแบบสมมาตร AES
  3. HMAC-SHA256 เพื่อความถูกต้องครบถ้วนของข้อความ
  4. JWT: โครงสร้าง การสร้าง และการตรวจสอบ
← กลับไปที่ Java Academy