Hash Code และ Checksum - ความแตกต่างคืออะไร?


115

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

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

เรามีคำสองคำสำหรับสิ่งเดียวกันหรือมีความแตกต่างที่สำคัญระหว่างรหัสแฮชและเช็คซัม?


3
เพื่อสรุปคำตอบด้านล่าง: รหัสแฮชจะลดข้อมูลที่ป้อนให้เหลือเพียงเล็กน้อยเพื่อลดโอกาสที่จะเกิดการชนกัน ในทางกลับกันการตรวจสอบจะลดข้อมูลเข้าให้เหลือเพียงเล็กน้อยเพื่อลดโอกาสในการชนกัน คุณสามารถทำให้เสียงหนึ่งแตกต่างจากอีกเสียงได้โดยเปลี่ยนคำอธิบายตามอำเภอใจ
Dan Stahlke

3
@ DanStahlke - ไม่นั่นไม่ใช่คำตอบด้านล่างนี้ ใช่ทั้งคู่ลดจำนวนอินพุตให้น้อยลง แต่มีหลายวิธีหลายวิธีในการเลือกใช้อัลกอริทึมอะไร? ขึ้นอยู่กับเป้าหมายของคุณ เพื่อสรุปคำตอบสองอันดับแรกเป้าหมายของการตรวจสอบคือ " เพื่อตรวจหาข้อผิดพลาดที่พบบ่อยที่สุด " เลือกอัลกอริทึมที่ให้ผลการตรวจสอบที่แตกต่างกันสำหรับข้อผิดพลาดใด ๆ ที่ "พบบ่อยที่สุด" ในสถานการณ์ของคุณ หากคุณกังวลเกี่ยวกับการสลับบิตหนึ่งหรือสองบิตคุณสามารถเลือกอัลกอริทึมที่รับประกันการตรวจจับข้อผิดพลาดเฉพาะนั้นได้! นี่เป็นการแลกเปลี่ยนที่เฉพาะเจาะจงมาก
ToolmakerSteve

1
@ DanStahlke - ในทางกลับกันรหัสแฮชครอบคลุมการแลกเปลี่ยนที่เป็นไปได้ในวงกว้าง หากเราหมายถึงค่าที่ใช้ในการสร้างตารางแฮชเรารู้ว่าจะมีการชนกันจำนวนมาก นี่เป็นการแลกเปลี่ยนที่แตกต่างกันมาก (กว่าการตรวจสอบ) เราพยายามที่จะลดการชนโดยเฉลี่ย เราไม่รับประกันอะไร อาจมีอินพุตบางอย่างที่แตกต่างกันเพียงบิตเดียว แต่ให้ผลแฮชเดียวกัน นี่เป็นสิ่งที่ดีมากถ้าโดยเฉลี่ยแล้วเราได้รับค่าแฮชที่ดี แต่จะเป็นที่ยอมรับไม่ได้สำหรับการตรวจสอบ
ToolmakerSteve

คำตอบ:


72

ฉันจะบอกว่าการตรวจสอบ จำเป็นต้องมีรหัสแฮช อย่างไรก็ตามรหัสแฮชทั้งหมดไม่สามารถตรวจสอบได้ดี

การตรวจสอบมีจุดประสงค์พิเศษโดยจะตรวจสอบหรือตรวจสอบความสมบูรณ์ของข้อมูล (บางส่วนสามารถทำได้มากกว่านั้นโดยอนุญาตให้มีการแก้ไขข้อผิดพลาด ) การตรวจสอบ "ดี" นั้นง่ายต่อการคำนวณและสามารถตรวจจับความเสียหายของข้อมูลได้หลายประเภท (เช่นหนึ่ง, สอง, สามบิตที่ผิดพลาด)

แฮชโค้ดเพียงอธิบายฟังก์ชันทางคณิตศาสตร์ที่แมปข้อมูลกับค่าบางค่า เมื่อใช้เป็นวิธีการสร้างดัชนีในโครงสร้างข้อมูล (เช่นตารางแฮช) ความน่าจะเป็นในการชนกันต่ำเป็นที่พึงปรารถนา


6
บางทีอาจใช้แทนกันได้ แต่เมื่อพิจารณาว่าพวกเขามีเป้าหมายการออกแบบที่แตกต่างกันสิ่งนี้ทำให้เกิดความสับสน
Wim Coenen

8
@gumbo: ไม่ใช่ไม่ใช่ทุกแฮชโค้ดเป็นการตรวจสอบ ดูตัวอย่างสตริงจาก MSalters ด้านล่าง
MarcH

41

มีจุดประสงค์ที่แตกต่างกันอยู่เบื้องหลัง:

  • รหัสแฮช - ออกแบบมาให้สุ่มทั่วทั้งโดเมน (เพื่อลดการชนกันในตารางแฮชและอื่น ๆ ) นอกจากนี้รหัสแฮชการเข้ารหัสยังได้รับการออกแบบมาเพื่อให้ย้อนกลับทางคำนวณไม่ได้
  • ตรวจสอบผลรวม - ออกแบบมาเพื่อตรวจจับข้อผิดพลาดที่พบบ่อยที่สุดในข้อมูลและมักจะคำนวณได้อย่างรวดเร็ว (สำหรับการตรวจสอบสตรีมข้อมูลที่รวดเร็วอย่างมีประสิทธิภาพ)

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


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

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

22

มีความแตกต่างบางประการ:

  • เช็คซัมจะต้องแตกต่างกันเมื่ออินพุตแตกต่างกัน (บ่อยที่สุดเท่าที่จะเป็นไปได้) แต่สิ่งสำคัญเกือบเท่าที่จะคำนวณได้อย่างรวดเร็ว
  • รหัสแฮช (สำหรับใช้ในแฮชแท็ก) มีข้อกำหนดเหมือนกันและนอกจากนี้ควรกระจายอย่างเท่าเทียมกันในพื้นที่โค้ดโดยเฉพาะอย่างยิ่งสำหรับอินพุตที่คล้ายกัน
  • hashes การเข้ารหัสลับมีมากความต้องการที่เข้มงวดมากขึ้นว่าได้รับกัญชาคุณไม่สามารถสร้างการป้อนข้อมูลที่ผลิตกัญชานี้ เวลาในการคำนวณมาเป็นอันดับสองและขึ้นอยู่กับแอปพลิเคชันอาจเป็นที่พึงปรารถนาที่แฮชจะคำนวณได้ช้ามาก (เพื่อต่อสู้กับการโจมตีด้วยกำลังเดรัจฉาน)

1
ฉันไม่คิดว่าการตรวจสอบที่แตกต่างกันสำหรับปัจจัยการผลิตที่แตกต่างกันจะมีประโยชน์ใด ๆ มีไว้เพื่อตรวจสอบความสมบูรณ์เท่านั้นไม่ใช่เพื่อการแฮช
user541686

1
@ Mehrdad: แล้วคุณจะเสนอการตรวจสอบความสมบูรณ์ได้อย่างไรโดยไม่ให้ผลลัพธ์ที่แตกต่างกันสำหรับอินพุตที่แตกต่างกัน?
Michael Borgwardt

เอ่อบางทีฉันอาจจะพูดผิดไป? ฉันอ้างถึงส่วนที่คุณพูดว่า "เท่าที่จะทำได้" - ฉันแค่บอกว่าไม่มีเหตุผลที่พวกเขาจะคาดเดาไม่ได้หรือ "ไกล" เหมือนแฮช ตราบเท่าที่มีการเปลี่ยนแปลงบางอย่างในการตรวจสอบเมื่ออินพุตมีการเปลี่ยนแปลงโดยทั่วไปจะเป็นการตรวจสอบที่ดี ตรงกันข้ามกับแฮชซึ่งมีเป้าหมายในการกระจายสิ่งต่างๆอย่างเท่าเทียม / สุ่ม / คาดเดาไม่ได้ / "ไกล" ที่สุดเท่าที่จะเป็นไปได้ไปยังโคโดเมนของพวกเขา
user541686

ฉันคิดว่าคุณแค่ตีความที่ฉันหมายถึง "เท่าที่จะเป็นไปได้" ฉันแค่หมายความว่าการชนกันควรจะเกิดขึ้นน้อยมากที่สุดเท่าที่จะทำได้แม้ว่าจะหลีกเลี่ยงไม่ได้ก็ตาม ฉันจะเปลี่ยนคำพูด
Michael Borgwardt

@ Mehrdad - ตอนแรกมันไม่สมเหตุสมผลสำหรับฉัน หากมีการตรวจสอบไม่ได้มีการกระจายที่ดีกว่าค่าการตรวจสอบเป็นไปได้นั่นหมายความว่ามีบางค่าการตรวจสอบซึ่งจะถูกส่งกลับค่าการป้อนข้อมูลอื่น ๆ อีกมากมาย (กว่า checksums อื่น ๆ ) แต่นั่นช่วยลดประโยชน์ของการตรวจสอบหรือไม่? [มันเพิ่มอัตราต่อรองที่ข้อมูลที่ถูกรบกวนจะให้ผลลัพธ์เหมือนเดิมใช่ไหม] อืมฉันผิดคุณพูดถูก: การตรวจสอบจะต้องดีในการตรวจจับการรบกวนที่อาจเกิดขึ้นเท่านั้น ซึ่งอาจไม่ต้องการการแจกแจงแบบสม่ำเสมอสำหรับค่าทั้งหมด
ToolmakerSteve

10

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

ตัวอย่างที่ชัดเจนคือสตริง การตรวจสอบสตริงควรรวมแต่ละบิตและลำดับมีความสำคัญ ในทางกลับกันแฮชโค้ดมักจะใช้เป็นเช็คซัมของคำนำหน้าที่มีความยาว จำกัด ได้ นั่นหมายความว่า "aaaaaaaaaaba" จะแฮชเหมือนกับ "aaaaaaaaaaab" แต่อัลกอริทึมการแฮชสามารถจัดการกับการชนดังกล่าวได้


คำตอบนี้คือคำตอบที่กดกริ่งให้ฉัน ดังนั้นความสมบูรณ์ของข้อมูลจึงไม่ใช่จุดสำคัญของแฮช
truthadjustr

9

Wikipediaทำให้ดี:

ฟังก์ชัน Checksum เกี่ยวข้องกับฟังก์ชันแฮชลายนิ้วมือฟังก์ชันการสุ่มและฟังก์ชันแฮชการเข้ารหัส อย่างไรก็ตามแต่ละแนวคิดเหล่านั้นมีการใช้งานที่แตกต่างกันดังนั้นจึงมีเป้าหมายในการออกแบบที่แตกต่างกัน ตัวเลขเช็คและพาริตีบิตเป็นกรณีพิเศษของเช็คซัมซึ่งเหมาะสำหรับข้อมูลขนาดเล็ก (เช่นหมายเลขประกันสังคมหมายเลขบัญชีธนาคารคำคอมพิวเตอร์ไบต์เดี่ยว ฯลฯ ) รหัสแก้ไขข้อผิดพลาดบางอย่างขึ้นอยู่กับการตรวจสอบพิเศษที่ไม่เพียงตรวจพบข้อผิดพลาดทั่วไป แต่ยังช่วยให้สามารถกู้คืนข้อมูลต้นฉบับได้ในบางกรณี


28
หลังจากอ่านแล้วฉันก็ยังสงสัยว่าความแตกต่างคืออะไร
kirk.burleson

@ kirk.burleson - ฉันจะบอกว่าพวกเขาจะเหมือนกันหลักการแต่ในทางปฏิบัติอย่างใดอย่างหนึ่งมักจะทำให้เกิดความสมดุล ในสถานการณ์ที่แตกต่างกันจะใช้การแลกเปลี่ยนที่แตกต่างกันดังนั้นจึงใช้แนวทางที่แตกต่างกัน ไม่ใช่เหตุผลจริงๆที่มีคำสองคำที่แตกต่างกันเพียงแค่บอกว่าหากคุณค้นหาเทคนิคที่ดีสำหรับการตรวจสอบคุณอาจพบชุดของอัลกอริทึมที่แตกต่างจากการค้นหารหัสแฮช
ToolmakerSteve

5

การตรวจสอบป้องกันการเปลี่ยนแปลงโดยไม่ได้ตั้งใจ

แฮชการเข้ารหัสช่วยป้องกันผู้โจมตีที่มีแรงจูงใจสูง

เมื่อคุณส่งบิตบนสายอาจเกิดขึ้นโดยบังเอิญที่บิตบางส่วนถูกพลิกหรือถูกลบหรือแทรก เพื่อให้ผู้รับตรวจพบ (หรือบางครั้งแก้ไข) อุบัติเหตุเช่นนี้ผู้ส่งใช้การตรวจสอบ

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


3
"แฮชการเข้ารหัส" เพิ่มความสับสนระหว่าง "แฮช" และ "เช็คซัม" "cryptographic checksum" จะดีกว่าเพราะไม่มี
MarcH

5

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

ที่มา: CompTIA ® Security + Guide to Network Security Fundamentals - Fifth Edition - Mark Ciampa -Page 191


4

ทุกวันนี้พวกเขาสามารถแลกเปลี่ยนกันได้ แต่ในสมัยก่อนการตรวจสอบเป็นเทคนิคที่เรียบง่ายมากที่คุณจะต้องเพิ่มข้อมูลทั้งหมด (โดยปกติจะเป็นไบต์) และใส่จำนวนไบต์ลงท้ายด้วยค่านั้นใน .. ทราบว่าข้อมูลต้นฉบับเสียหายหรือไม่ คล้ายกับบิตตรวจสอบ แต่มีไบต์


4

ความแตกต่างระหว่างฟังก์ชันแฮชโค้ดและฟังก์ชันการตรวจสอบคือถูกออกแบบมาเพื่อวัตถุประสงค์ที่แตกต่างกัน

  • การตรวจสอบใช้เพื่อค้นหาว่ามีการเปลี่ยนแปลงบางอย่างในอินพุตหรือไม่

  • แฮชโค้ดใช้เพื่อค้นหาว่ามีการเปลี่ยนแปลงบางอย่างในอินพุตหรือไม่และมี "ระยะห่าง" ระหว่างค่าแฮชโค้ดแต่ละค่ามากที่สุด

    นอกจากนี้อาจมีข้อกำหนดเพิ่มเติมสำหรับฟังก์ชันแฮชซึ่งตรงข้ามกับกฎนี้เช่นความสามารถในการสร้างต้นไม้ / คลัสเตอร์ / ถังของค่าแฮชโค้ดในช่วงต้น

    และหากคุณเพิ่มการสุ่มเริ่มต้นที่ใช้ร่วมกันคุณจะได้รับแนวคิดสำหรับการเข้ารหัส / แลกเปลี่ยนคีย์สมัยใหม่


เกี่ยวกับความน่าจะเป็น:

ตัวอย่างเช่นสมมติว่าข้อมูลอินพุตมีการเปลี่ยนแปลงอยู่เสมอ (100% ของเวลา) และสมมติว่าคุณมีฟังก์ชันแฮช / เช็คซัมที่ "สมบูรณ์แบบ" ซึ่งจะสร้างค่าแฮช / เช็คซัม 1 บิต ดังนั้นคุณจะได้รับค่าแฮช / เช็คซัมที่แตกต่างกัน 50% ของเวลาสำหรับข้อมูลอินพุตแบบสุ่ม

  • หากข้อมูลอินพุตแบบสุ่มของคุณมีการเปลี่ยนแปลงเพียง 1 บิตคุณจะสามารถตรวจจับได้ 100% ตลอดเวลาไม่ว่าข้อมูลอินพุตจะมีขนาดใหญ่เพียงใด

  • หาก 2 บิตในข้อมูลอินพุตแบบสุ่มของคุณมีการเปลี่ยนแปลงความน่าจะเป็นในการตรวจพบ "การเปลี่ยนแปลง" ของคุณจะถูกหารด้วย 2 เนื่องจากการเปลี่ยนแปลงทั้งสองอาจทำให้เป็นกลางซึ่งกันและกันและไม่มีฟังก์ชันแฮช / การตรวจสอบใดที่ตรวจพบว่า 2 บิตนั้นแตกต่างกันจริงในข้อมูลอินพุต .

    ...

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


2

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


1
เนื่องจากการตรวจสอบไม่ได้ถูกทำให้ยากที่จะย้อนกลับสิ่งนี้แสดงให้เห็นว่าการตรวจสอบจะไม่ดีสำหรับการตรวจสอบว่ามีการเปลี่ยนแปลงโดยเจตนาหรือไม่
benblasdell

0

ในการแบ่งข้อมูลคลัสเตอร์ Redis จะใช้ a hash slotเพื่อตัดสินใจว่าจะไปโหนดใด ยกตัวอย่างการทำงานของโมดูโลด้านล่าง:

123 % 9 = 6
122 % 9 = 5
141 % 9 = 6

6ขึ้นมาเป็นครั้งที่สองที่แตกต่างกันทั่วปัจจัยการผลิต จุดประสงค์ของแฮชคือการแมปค่าอินพุตกับค่าเอาต์พุตและความเป็นเอกลักษณ์ไม่ได้เป็นส่วนหนึ่งของดีล ดังนั้นสองอินพุตที่แตกต่างกันที่ให้ผลลัพธ์เดียวกันจึงใช้ได้ดีในโลกของแฮช

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


-4

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

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.