SSH คืออะไร และมีหลักการทำงานอย่างไรในระบบ Linux
ทำความเข้าใจโปรโตคอล SSH สำหรับการรีโมทเข้าเซิร์ฟเวอร์อย่างปลอดภัยผ่านพอร์ต 22 เรียนรู้กลไกการเข้ารหัส การยืนยันตัวตนด้วย Key และความแตกต่างระหว่าง Client กับ Server
SSH คืออะไร
SSH (secure shell) คือโปรโตคอลสำหรับเข้าสู่ระบบคอมพิวเตอร์เครื่องอื่นและรันคำสั่งผ่านการเชื่อมต่อที่เข้ารหัส สิ่งที่คุณพิมพ์จะถูกส่งไปยังเครื่องปลายทาง และผลลัพธ์จะถูกส่งกลับมา โดยที่ไม่มีใครที่ดักจับข้อมูลบนเครือข่ายระหว่างทางสามารถอ่านข้อมูลเหล่านั้นได้ เซิร์ฟเวอร์ Linux ที่เช่ามาไม่มีหน้าจอหรือคีย์บอร์ดเชื่อมต่ออยู่ ดังนั้น SSH จึงเป็นวิธีหลักในการใช้งานเครื่องดังกล่าว
ชื่อนี้ครอบคลุมสองส่วน SSH คือโปรโตคอลซึ่งอธิบายไว้ใน RFC 4251 ถึง RFC 4254 ส่วน OpenSSH คือโปรแกรมที่นำโปรโตคอลนี้ไปใช้งานจริง และเป็นสิ่งที่เซิร์ฟเวอร์ Linux และแล็ปท็อปเกือบทุกเครื่องใช้งานอยู่ เมื่อมีคนพูดว่า "SSH เข้าไปที่เซิร์ฟเวอร์" พวกเขาหมายถึงการใช้โปรแกรมไคลเอนต์ ssh บนเครื่องของตนเพื่อสื่อสารกับโปรแกรมเซิร์ฟเวอร์ sshd ที่ปลายทางอีกด้านหนึ่ง
ปัญหาที่ SSH ถูกสร้างขึ้นมาเพื่อแก้ไข
การล็อกอินระยะไกลมีมานานกว่า SSH โดย Telnet จะเปิดการเชื่อมต่อ TCP แบบปกติที่พอร์ต 23 และส่งข้อมูลทุกไบต์ตามที่พิมพ์ไปตรงๆ ไม่มีการเข้ารหัสใดๆ รวมถึงรหัสผ่านของคุณด้วย ใครก็ตามที่สามารถมองเห็นทราฟฟิกนี้จะสามารถอ่านข้อมูลได้ ไม่ว่าจะเป็นบุคคลในเครือข่ายสำนักงานเดียวกัน หรือผู้ดูแลเราเตอร์ตัวใดก็ตามที่อยู่ระหว่างทาง ตระกูล rlogin ก็มีจุดอ่อนแบบเดียวกัน และยังเชื่อถือเครื่องไคลเอนต์โดยอ้างอิงจากชื่อ ซึ่งหมายถึงการเชื่อถือสิ่งที่เครือข่ายกล่าวอ้างว่าเป็นชื่อนั้นๆ
Tatu Ylönen เขียน SSH รุ่นแรกขึ้นในปี 1995 ที่ Helsinki University of Technology หลังจากเกิดการโจมตีแบบดักจับรหัสผ่านบนเครือข่ายของมหาวิทยาลัย การออกแบบนี้ยังคงส่วนที่เป็นประโยชน์ของ telnet ไว้ คือการเป็นสตรีมไบต์ระหว่างเทอร์มินัลของคุณกับเชลล์ระยะไกล และเพิ่มสองสิ่งที่ telnet ไม่มีคำตอบให้ คือการเข้ารหัสสตรีม และการพิสูจน์ว่าเซิร์ฟเวอร์ที่ปลายทางคือเครื่องที่คุณต้องการเชื่อมต่อจริงๆ
ส่วนที่สองนี้เป็นสิ่งที่มองข้ามได้ง่าย และเป็นครึ่งหนึ่งของสิ่งที่ SSH เป็น การเข้ารหัสเพียงอย่างเดียวไม่สามารถปกป้องคุณได้ เครื่องที่อยู่ตรงกลางอาจตอบรับการเชื่อมต่อของคุณ เข้ารหัสข้อมูลอย่างสมบูรณ์แบบ อ่านทุกสิ่งที่คุณส่ง และส่งต่อไปยังเซิร์ฟเวอร์จริงได้ SSH ป้องกันสิ่งนี้โดยการกำหนดตัวตนถาวรให้กับเซิร์ฟเวอร์ทุกเครื่อง ซึ่งเรียกว่า host key และตรวจสอบตัวตนนี้ในการเชื่อมต่อทุกครั้ง
การทำงานของโมเดลไคลเอนต์และเซิร์ฟเวอร์
มีโปรแกรมอยู่สองส่วน บนฝั่งเซิร์ฟเวอร์ sshd จะทำงานตลอดเวลาเพื่อรอรับการเชื่อมต่อ ส่วนบนเครื่องของคุณ ssh จะเป็นตัวสร้างการเชื่อมต่อ โปรแกรมทั้งสองนี้แยกจากกันและมีไฟล์คอนฟิกูเรชันแยกกัน การสับสนระหว่างสองส่วนนี้เป็นสาเหตุที่พบบ่อยที่สุดที่ทำให้การแก้ไขค่าไม่มีผล
- เซิร์ฟเวอร์อ่านค่าจาก
/etc/ssh/sshd_configซึ่งเป็นจุดที่ใช้ปิดการล็อกอินด้วยรหัสผ่านและกำหนดพอร์ตที่ใช้รับการเชื่อมต่อ - ไคลเอนต์อ่านค่าจาก
/etc/ssh/ssh_configสำหรับค่าเริ่มต้นของระบบ จากนั้นจะอ่าน~/.ssh/configสำหรับการตั้งค่าเฉพาะโฮสต์ของคุณเอง
บน Debian และ Ubuntu ยูนิตของเซอร์วิสมีชื่อว่า ssh ส่วนบน RHEL, Rocky และ Fedora จะใช้ชื่อว่า sshd สำหรับ Ubuntu รุ่นใหม่ๆ จะติดตั้งแบบ socket activated ดังนั้น systemctl status ssh อาจรายงานสถานะเป็น inactive (dead) ในขณะที่เครื่องยังสามารถเข้าถึงได้ตามปกติ เนื่องจาก ssh.socket เป็นยูนิตที่ทำหน้าที่รับการเชื่อมต่อและจะเรียกใช้งานเซอร์วิสเมื่อมีการร้องขอเท่านั้น
ไคลเอนต์ไม่จำเป็นต้องเป็น OpenSSH เสมอไป โปรแกรมอย่าง PuTTY บน Windows, Termius บนโทรศัพท์ และฟีเจอร์รีโมทซัพพอร์ตที่มาพร้อมกับโปรแกรมแก้ไขข้อความต่างๆ ล้วนใช้โปรโตคอลเดียวกันเพื่อสื่อสารกับ sshd ตัวเดียวกัน นอกจากนี้ Windows 10 และ 11 ยังรวม OpenSSH client มาให้ด้วย ทำให้สามารถใช้คำสั่ง ssh you@server ใน PowerShell ได้ทันทีโดยไม่ต้องติดตั้งอะไรเพิ่ม
เหตุใด SSH จึงใช้พอร์ต 22
พอร์ตคือตัวเลขที่บอก kernel ว่าการเชื่อมต่อขาเข้านั้นเป็นของโปรแกรมใดที่กำลังรอรับการเชื่อมต่ออยู่ และ พอร์ตบน Linux ก็ทำงานในลักษณะเดียวกันสำหรับทุกบริการ SSH ใช้พอร์ต 22 เพราะ IANA ได้กำหนดไว้ในปี 1995 โดย Ylönen ได้ขอหมายเลขที่ว่างอยู่ซึ่งอยู่ติดกับโปรโตคอลที่ SSH ถูกเขียนขึ้นมาเพื่อทดแทน ได้แก่ 21 คือ FTP, 23 คือ telnet และ 22 คือพอร์ตที่ยังไม่มีการใช้งาน
เนื่องจาก 22 เป็นค่าเริ่มต้น ทุกอย่างจึงสันนิษฐานว่าเป็นพอร์ตนี้ ทั้ง Git remote, สคริปต์สำรองข้อมูล และแผงควบคุมของผู้ให้บริการของคุณ ต่างพยายามเชื่อมต่อที่พอร์ต 22 เป็นอันดับแรก เช่นเดียวกับสแกนเนอร์อัตโนมัติทุกตัวบนอินเทอร์เน็ต เซิร์ฟเวอร์ใหม่ที่เปิดใช้งานการล็อกอินด้วยรหัสผ่านจะเริ่มสะสมบรรทัดข้อความในลักษณะนี้ภายใน /var/log/auth.log เพียงไม่กี่นาทีหลังจากบูตเครื่อง:
Failed password for invalid user admin from 203.0.113.55 port 43122 ssh2ทราฟฟิกเหล่านั้นเกิดขึ้นอย่างต่อเนื่องและไม่ได้มุ่งเป้ามาที่คุณโดยเฉพาะ การย้าย sshd ไปยังพอร์ต 2222 จะช่วยลดบรรทัดข้อความเหล่านั้นลงได้มาก เพราะสแกนเนอร์ส่วนใหญ่กำลังกวาดตรวจทั้งอินเทอร์เน็ตที่พอร์ต 22 แทนที่จะเจาะจงศึกษาเซิร์ฟเวอร์ของคุณ การทำเช่นนี้ไม่ได้ทำให้เครื่องของคุณถูกเจาะได้ยากขึ้นสำหรับผู้ที่ตั้งใจจะโจมตีคุณจริงๆ ให้ถือว่าการเปลี่ยนพอร์ตเป็นเพียงการลดสัญญาณรบกวนเท่านั้น
คุณสามารถเฝ้าดูการตอบสนองของเซิร์ฟเวอร์ก่อนที่คุณจะล็อกอินได้ดังนี้:
nc 203.0.113.10 22บน Ubuntu 24.04 คำสั่งนี้จะแสดงผลลัพธ์ที่ใกล้เคียงกับ SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13 โดย banner จะถูกส่งออกมาเป็นข้อความธรรมดา (cleartext) ก่อนที่จะมีการเข้ารหัสใดๆ เกิดขึ้น เนื่องจากทั้งสองฝั่งจำเป็นต้องใช้ข้อมูลนี้เพื่อตกลงเวอร์ชันของโปรโตคอล ให้กด Ctrl+C เพื่อปิดการเชื่อมต่อ
สิ่งที่เกิดขึ้นบนเครือข่ายเมื่อคุณเชื่อมต่อ
ลำดับขั้นตอนต่อไปนี้คือสิ่งที่ ssh you@server ทำก่อนที่คุณจะเห็นพรอมต์
- ไคลเอนต์แปลงชื่อโฮสต์เป็นที่อยู่ IP จากนั้นเปิดการเชื่อมต่อ TCP ไปยังพอร์ต 22
- ทั้งสองฝั่งส่งแบนเนอร์เวอร์ชันของตนเองในรูปแบบข้อความธรรมดา (cleartext)
- ทั้งสองฝั่งส่งรายการอัลกอริทึมที่รองรับ ได้แก่ การแลกเปลี่ยนกุญแจ, การเข้ารหัส (cipher), การตรวจสอบความถูกต้องของข้อความ และการบีบอัดข้อมูล ทั้งหมดยังคงเป็นข้อความธรรมดา โดยจะเลือกตัวเลือกที่แข็งแกร่งที่สุดที่ทั้งสองฝั่งรู้จัก
- เริ่มกระบวนการแลกเปลี่ยนกุญแจ OpenSSH ปัจจุบันนิยมใช้
curve25519-sha256ทั้งสองฝั่งจะได้กุญแจลับร่วมกันโดยที่กุญแจนั้นไม่เคยถูกส่งผ่านเครือข่าย ดังนั้นผู้ที่บันทึกการสนทนาทั้งหมดไว้จะไม่สามารถถอดรหัสได้ในภายหลัง - เซิร์ฟเวอร์ลงลายมือชื่อผลลัพธ์ของการแลกเปลี่ยนนั้นด้วยกุญแจส่วนตัวของโฮสต์ ไคลเอนต์ของคุณจะตรวจสอบลายมือชื่อเทียบกับกุญแจสาธารณะของโฮสต์ที่มีอยู่ในไฟล์ ขั้นตอนนี้คือสิ่งที่ป้องกันไม่ให้เครื่องที่อยู่ตรงกลางปลอมตัวเป็นเซิร์ฟเวอร์ของคุณ
- เริ่มการเข้ารหัส
chacha20-poly1305@openssh.comเป็น cipher เริ่มต้นใน OpenSSH ปัจจุบัน - หลังจากขั้นตอนนี้เท่านั้นที่ไคลเอนต์จะตรวจสอบสิทธิ์ของคุณด้วยรหัสผ่านหรือกุญแจ ชื่อผู้ใช้และรหัสผ่านของคุณจะถูกส่งผ่านภายในช่องทางที่เข้ารหัสไว้แล้ว
- ไคลเอนต์เปิดช่องทางและร้องขอเชลล์
ลำดับในรายการนี้คือความแตกต่างทั้งหมดเมื่อเทียบกับ telnet การตรวจสอบสิทธิ์จะเกิดขึ้นหลังจากช่องทางถูกเข้ารหัสและหลังจากเซิร์ฟเวอร์พิสูจน์ตัวตนแล้ว ดังนั้นจึงไม่มีช่วงเวลาใดที่รหัสผ่านของคุณจะถูกส่งผ่านเครือข่ายโดยไม่มีการป้องกัน
ผู้ที่เฝ้าดูเครือข่ายยังคงได้รับข้อมูลบางอย่าง พวกเขาเห็นที่อยู่ IP ของคุณ, ที่อยู่ IP ของเซิร์ฟเวอร์, พอร์ต 22, แบนเนอร์เวอร์ชันทั้งสองฝั่งที่เป็นข้อความธรรมดา รวมถึงจังหวะเวลาและขนาดโดยประมาณของทุกแพ็กเก็ต แต่พวกเขาจะไม่เห็นชื่อผู้ใช้, รหัสผ่าน, คำสั่ง หรือผลลัพธ์ของคำสั่งของคุณ การค้นหาชื่อโฮสต์ในขั้นตอนที่ 1 ไม่ใช่ส่วนหนึ่งของ SSH และโดยปกติจะไม่เป็นส่วนตัว ดังนั้น การสืบค้น DNS ที่แปลงชื่อเซิร์ฟเวอร์ของคุณ อาจเปิดเผยว่าคุณกำลังจะเชื่อมต่อไปยังเครื่องใด แม้ว่าตัวเซสชันจะถูกปิดผนึกไว้ก็ตาม
โฮสต์คีย์และข้อความแจ้งเตือน fingerprint ในการเชื่อมต่อครั้งแรก
เมื่อ openssh-server ถูกติดตั้ง ระบบจะสร้างคู่กุญแจโฮสต์สำหรับเครื่องนั้นและเขียนลงใน /etc/ssh/ ตัวอย่างเช่น ssh_host_ed25519_key และ ssh_host_ed25519_key.pub ส่วนที่เป็น private key จะไม่ถูกส่งออกจากเซิร์ฟเวอร์ ส่วนที่เป็น public key คือตัวตนของเซิร์ฟเวอร์ ซึ่งเป็นสิ่งที่ลายเซ็นในขั้นตอนที่ 5 จะถูกนำไปตรวจสอบเทียบ
ในการเชื่อมต่อครั้งแรกไปยังเซิร์ฟเวอร์ใหม่ ไคลเอนต์ของคุณจะไม่มีข้อมูลสำหรับเปรียบเทียบ จึงแสดงข้อความถามคุณดังนี้:
The authenticity of host '203.0.113.10 (203.0.113.10)' can't be established.
ED25519 key fingerprint is SHA256:E9nVQ5Sm2oQ3nGm5Zf1tOaU7Xh0k2p8bWc4dLrTvYxA.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?ค่า fingerprint คือ SHA256 hash ของ public key ของโฮสต์ ซึ่งแสดงในรูปแบบ base64 เพื่อให้สั้นพอที่จะตรวจสอบด้วยสายตา การพิมพ์ yes จะเป็นการบันทึกกุญแจนั้นลงใน ~/.ssh/known_hosts บนเครื่องของคุณ การเชื่อมต่อครั้งถัดไปทั้งหมดไปยังที่อยู่เดิมจะนำกุญแจที่เซิร์ฟเวอร์เสนอมาเปรียบเทียบกับกุญแจที่จัดเก็บไว้ หากตรงกัน ระบบจะไม่แสดงข้อความใดๆ และคุณจะเข้าสู่พรอมต์คำสั่งได้ทันที
รูปแบบนี้เรียกว่า trust on first use และควรยอมรับความจริงเกี่ยวกับความเสี่ยงที่เกิดขึ้น การเชื่อมต่อครั้งแรกเป็นช่วงเวลาเดียวที่คุณไม่มีการป้องกัน เพราะคุณกำลังยอมรับกุญแจที่ไม่เคยเห็นมาก่อน เพื่อปิดช่องว่างนี้ ให้หาค่า fingerprint ผ่านช่องทางอื่นแล้วนำมาเปรียบเทียบ ผู้ให้บริการส่วนใหญ่จะแสดงค่านี้ไว้ใน output ของการบูตบนเว็บคอนโซล และคุณยังสามารถสั่งแสดงค่านี้บนเซิร์ฟเวอร์ได้ด้วยตนเอง:
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pubคำสั่งนั้นจะแสดงสตริง SHA256: เดียวกับที่พรอมต์แสดงให้คุณเห็น ตัวเลือก [fingerprint] ในพรอมต์มีไว้เพื่อการนี้โดยเฉพาะ คือให้คุณวางค่า fingerprint ที่คุณคาดหวังไว้ แล้วไคลเอนต์จะดำเนินการต่อก็ต่อเมื่อค่าตรงกับที่เซิร์ฟเวอร์นำเสนอเท่านั้น
บน Debian และ Ubuntu ค่า known_hosts จะถูกทำ hash ไว้โดยค่าเริ่มต้น ไฟล์จึงเก็บรายการที่ขึ้นต้นด้วย |1| แทนที่จะเป็นชื่อโฮสต์ที่อ่านออกได้ ให้รันคำสั่ง ssh-keygen -F 203.0.113.10 เพื่อค้นหารายการสำหรับโฮสต์ที่ต้องการ
เหตุใด SSH จึงแจ้งว่า host key มีการเปลี่ยนแปลง
ไม่ช้าก็เร็ว คุณจะต้องพบกับข้อความเตือนชุดนี้:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!ข้อความจะลงท้ายด้วย Host key verification failed. และไคลเอนต์จะปฏิเสธการเชื่อมต่อ นอกจากนี้ยังแสดง Password authentication is disabled to avoid man-in-the-middle attacks. เนื่องจากความเสียหายที่การตรวจสอบนี้มีไว้เพื่อป้องกัน คือการที่คุณพิมพ์รหัสผ่านลงในเครื่องที่ไม่รู้จัก
ข้อความดังกล่าวดูเหมือนเป็นเหตุฉุกเฉิน แต่ส่วนใหญ่แล้วไม่ใช่ สาเหตุทั่วไปมีดังนี้:
- คุณสร้างหรือติดตั้งเซิร์ฟเวอร์ใหม่ ทำให้
sshdสร้าง host key ชุดใหม่ขึ้นมาในระหว่างการบูตครั้งแรก นี่เป็นสาเหตุที่พบบ่อยที่สุด - คุณทำลาย VPS เครื่องเก่าและสร้างเครื่องใหม่ขึ้นมาแทน โดยผู้ให้บริการได้กำหนด IP address เดิมให้กับเครื่องใหม่นั้น
- คุณกำลังเชื่อมต่อผ่าน forward หรือ load balancer ซึ่งปัจจุบันส่งคำขอไปยังเครื่อง backend เครื่องอื่น
- มีบางอย่างกำลังดักจับการเชื่อมต่อของคุณอยู่จริง
ให้ตัดสินใจก่อนว่าสาเหตุคืออะไรก่อนที่จะลบข้อมูลใดๆ หากคุณเพิ่งติดตั้งเครื่องใหม่เมื่อสิบนาทีก่อน สาเหตุย่อมชัดเจนอยู่แล้ว แต่หากไม่มีการเปลี่ยนแปลงใดๆ ในฝั่งของคุณ ให้หยุดและตรวจสอบทันที เพราะคำเตือนนี้คือการทำงานตามปกติของระบบรักษาความปลอดภัย เมื่อคุณมั่นใจแล้ว ให้ลบรายการเก่าออกและเชื่อมต่อใหม่:
ssh-keygen -R 203.0.113.10การเชื่อมต่อครั้งถัดไปจะแสดง prompt ให้ตรวจสอบ fingerprint อีกครั้ง ซึ่งเปิดโอกาสให้คุณเปรียบเทียบค่า fingerprint กับข้อมูลใน console ของผู้ให้บริการได้อีกครั้ง
การล็อกอินด้วยรหัสผ่านเทียบกับการล็อกอินด้วยคีย์
การยืนยันตัวตนด้วยรหัสผ่านจะส่งรหัสผ่านของคุณเข้าไปภายในช่องทางที่เข้ารหัสไว้แล้ว และ sshd จะตรวจสอบรหัสผ่านนั้นกับฐานข้อมูลบัญชีผู้ใช้ โดยปกติจะผ่านทาง PAM (pluggable authentication modules) วิธีนี้ไม่จำเป็นต้องมีการเตรียมการใดๆ ซึ่งเป็นเหตุผลที่ผู้ให้บริการสามารถส่งมอบเซิร์ฟเวอร์ใหม่ให้คุณโดยมีเพียงรหัสผ่าน root เท่านั้น
จุดอ่อนไม่ได้อยู่ที่การเข้ารหัส แต่อยู่ที่รหัสผ่านเป็นความลับที่สั้น คุณต้องส่งรหัสผ่านไปยังเซิร์ฟเวอร์ทุกครั้งที่ล็อกอิน และพอร์ต 22 ก็ถูกเครื่องจักรที่ไม่มีวันเหนื่อยล้าพยายามสุ่มเดารหัสผ่านอยู่ตลอดเวลา
การยืนยันตัวตนด้วย public key ทำงานต่างออกไป คุณสร้างคู่กุญแจขึ้นบนเครื่องของคุณเอง โดยส่วนที่เป็น public key จะถูกนำไปใส่ไว้ใน ~/.ssh/authorized_keys ภายในบัญชีผู้ใช้ของคุณบนเซิร์ฟเวอร์ ส่วนที่เป็น private key จะเก็บไว้บนแล็ปท็อปของคุณและไม่มีการส่งผ่านเครือข่าย ในการล็อกอิน ไคลเอนต์จะลงลายมือชื่อในข้อมูลชุดหนึ่งซึ่งรวมถึงตัวระบุเซสชันจากการแลกเปลี่ยนคีย์ และเซิร์ฟเวอร์จะตรวจสอบลายมือชื่อนั้นโดยใช้ public key ที่มีอยู่แล้ว เนื่องจากข้อมูลที่ลงลายมือชื่อนั้นผูกติดอยู่กับเซสชันนี้เพียงเซสชันเดียว ลายมือชื่อที่ถูกดักจับได้จึงไม่มีค่าสำหรับนำไปใช้ในกรณีอื่น
โปรดสังเกตทิศทางให้ดี เพราะการสลับทิศทางเป็นเรื่องที่เกิดขึ้นบ่อยและเป็นอันตราย: public key ต้องอยู่บนเซิร์ฟเวอร์ ส่วน private key ต้องอยู่กับคุณเท่านั้น หาก private key ถูกคัดลอกไปยังเซิร์ฟเวอร์ คุณจะไม่สามารถเชื่อถือ private key นั้นได้อีกต่อไป
การล็อกอินด้วยคีย์มีรูปแบบความล้มเหลวเฉพาะตัว sshd จะเพิกเฉยต่อคีย์หากสิทธิ์การเข้าถึงไฟล์ (file permissions) หลวมเกินไป และจะระบุไว้ใน log ของเซิร์ฟเวอร์ดังนี้:
Authentication refused: bad ownership or modes for directory /home/ubuntu/.sshไคลเอนต์จะแจ้งเตือนคุณเพียงแค่ Permission denied (publickey) เท่านั้น ซึ่งเป็นข้อความเดียวกันสำหรับสาเหตุที่แตกต่างกันนับสิบประการ ดังนั้นการ อ่านข้อผิดพลาด publickey อย่างถูกต้อง จึงเป็นสิ่งที่ควรเรียนรู้ก่อนที่คุณจะถูกล็อกไม่ให้เข้าใช้งาน งานปฏิบัติในการสร้างคีย์ การป้องกันด้วย passphrase และการโหลดคีย์เข้าสู่ agent อยู่ในหัวข้อ การจัดการ SSH key และการปิดการล็อกอินด้วยรหัสผ่านโดยไม่ทำให้ตัวเองเข้าใช้งานไม่ได้นั้นอยู่ในหัวข้อ การเพิ่มความปลอดภัยให้ SSH บน VPS
SFTP, scp และการทำ port forwarding ใช้การเชื่อมต่อเดียวกัน
นี่คือแนวคิดหลักที่ทำให้โลกของ SSH ทั้งหมดเชื่อมโยงกัน การยืนยันตัวตนจะเปิดการเชื่อมต่อที่เข้ารหัสไว้ และการเชื่อมต่อนี้สามารถรองรับช่องทางสื่อสาร (channel) หลายช่องทางที่เป็นอิสระต่อกันได้ในเวลาเดียวกัน โดย shell เป็นเพียงช่องทางประเภทหนึ่งจากหลายๆ ประเภท
- Remote shell:
ssh you@serverจะเปิด session channel และร้องขอ interactive shell - คำสั่งเดียว:
ssh you@server uptimeจะเปิด channel, รันคำสั่งหนึ่งคำสั่ง, แสดงผลลัพธ์ แล้วจบการทำงาน - SFTP: ไคลเอนต์จะร้องขอให้
sshdเริ่มต้น subsystemsftpของมัน และการถ่ายโอนไฟล์จะทำงานอยู่ภายในช่องทางการเชื่อมต่อเดียวกัน SFTP เป็นโปรโตคอลการถ่ายโอนไฟล์ที่ทำงานบน SSH และไม่มีส่วนเกี่ยวข้องใดๆ กับการออกแบบของ FTP ส่วนโปรโตคอลที่เป็น FTP ที่เพิ่มการเข้ารหัสเข้ามาจะเรียกว่า FTPS ซึ่งไม่เกี่ยวข้องกัน - scp: ใช้คัดลอกไฟล์โดยใช้การล็อกอินเดียวกัน ตั้งแต่ OpenSSH 9.0 ที่ปล่อยออกมาในปี 2022 เป็นต้นมา
scpจะใช้โปรโตคอล SFTP เป็นพื้นฐานโดยค่าเริ่มต้น - Port forwarding:
ssh -L 8080:localhost:80 you@serverจะเปลี่ยนพอร์ต 8080 บนแล็ปท็อปของคุณให้เป็นประตูสู่พอร์ต 80 บนเซิร์ฟเวอร์ โดยข้อมูลจะถูกส่งผ่านภายในช่องทางการเชื่อมต่อที่เข้ารหัสไว้ ส่วน-Rจะทำการ forward ในทิศทางตรงกันข้าม และ-D 1080จะเปลี่ยน session ให้กลายเป็น SOCKS proxy - Git: remote อย่างเช่น
git@github.com:user/repo.gitคือการล็อกอินผ่าน SSH ซึ่งฝั่งรีโมทจะรันตัวจัดการคำสั่งแทนที่จะเป็น shell - rsync และ Ansible ก็เป็น SSH ไคลเอนต์เช่นกัน โดยเครื่องมือเหล่านี้จะเปิด channel, รันบางอย่าง และอ่านผลลัพธ์กลับมา
ทุกรายการในรายการข้างต้นใช้พอร์ตเดียวกัน, ใช้การตรวจสอบ host key เดียวกัน และใช้ข้อมูลยืนยันตัวตนชุดเดียวกัน นี่คือเหตุผลว่าทำไมการตั้งค่า key authentication เพียงครั้งเดียวจึงคุ้มค่าทันที เพราะเครื่องมือเหล่านี้ทั้งหมดจะได้รับประโยชน์จากการตั้งค่านั้น และนี่คือเหตุผลที่ไฟล์ ~/.ssh/config เดียวกันที่ช่วยให้คุณล็อกอินได้รวดเร็วขึ้น คือไฟล์เดียวกันกับที่ช่วยให้คุณขยายขีดความสามารถเมื่อต้อง จัดการเซิร์ฟเวอร์ Linux หลายเครื่อง จากแล็ปท็อปเพียงเครื่องเดียว
สิ่งที่ SSH ไม่ได้ทำ
- SSH ไม่ได้ทำให้เซิร์ฟเวอร์ของคุณปลอดภัย SSH เพียงแค่ปกป้องเส้นทางไปสู่ประตู แต่ตัวประตูยังคงอยู่และจะมีคนพยายามหมุนลูกบิดประตูอยู่เสมอ การใช้ การบล็อกความพยายามล็อกอินซ้ำๆ ด้วย fail2ban จะช่วยจัดการกับปริมาณการโจมตี และการใช้การยืนยันตัวตนด้วยกุญแจ (key-only authentication) จะช่วยกำจัดสิ่งที่ผู้โจมตีพยายามเดาออกไป
- SSH ไม่ได้ปกป้องคุณจากเครื่องของคุณเอง ใครก็ตามที่เข้าถึงแล็ปท็อปของคุณได้ ย่อมเข้าถึง private key และ agent ที่คุณโหลดไว้ได้เช่นกัน
- SSH ไม่ได้ปิดบังว่าคุณกำลังใช้งาน SSH อยู่ หมายเลขพอร์ตและข้อความ version banner แบบ cleartext จะประกาศให้ทราบโดยทั่วกัน
- SSH ไม่ได้ครอบคลุมถึงสิ่งที่เกิดขึ้นก่อนการเชื่อมต่อจะถูกสร้างขึ้น การค้นหาชื่อโฮสต์ (name lookup) และการตัดสินใจของคุณว่าจะเชื่อถือที่อยู่ใด ทั้งสองอย่างนี้เกิดขึ้นก่อนเสมอ
ขั้นตอนถัดไปหลังจากนี้
หากคุณกำลังเปิดหน้าต่างคอนโซลของเซิร์ฟเวอร์ใหม่จากผู้ให้บริการอยู่ ลำดับการทำงานที่เหมาะสมนั้นชัดเจนอยู่แล้ว ให้เข้าสู่ระบบ สร้างผู้ใช้งานทั่วไป ติดตั้งคีย์ของคุณ จากนั้นจึงปิดช่องทางที่เข้าถึงได้ง่ายทิ้งไป สิบนาทีแรกบน VPS เครื่องใหม่ จะอธิบายลำดับขั้นตอนดังกล่าวตั้งแต่ต้นจนจบ และ VPS คืออะไรกันแน่ จะช่วยอธิบายถึงตัวเครื่องที่อยู่เบื้องหลังหากคุณยังไม่คุ้นเคยกับคำศัพท์เหล่านี้ หลังจากนั้น บทความเรื่องคีย์และการเพิ่มความปลอดภัย (hardening) คือสองหัวข้อที่คุณควรอ่านตามลำดับนั้น
FAQ
SSH ย่อมาจากอะไร?
SSH ย่อมาจาก secure shell เป็นโปรโตคอลสำหรับล็อกอินเข้าสู่คอมพิวเตอร์ระยะไกลและรันคำสั่งผ่านการเชื่อมต่อที่เข้ารหัส โดยถูกกำหนดไว้ใน RFC 4251 ถึง RFC 4254 สำหรับ OpenSSH คือการนำโปรโตคอลนี้ไปใช้งานที่นิยมใช้กันมากที่สุด ซึ่งประกอบด้วย ssh ฝั่งไคลเอนต์บนเครื่องของคุณ และ sshd ฝั่งเซิร์ฟเวอร์บนเครื่องระยะไกล SSH เข้ามาแทนที่ telnet ซึ่งส่งข้อมูลทุกอย่างรวมถึงรหัสผ่านผ่านเครือข่ายในรูปแบบข้อความธรรมดา (plain text)
ทำไม SSH ถึงใช้พอร์ต 22?
IANA กำหนดให้พอร์ต 22 เป็นพอร์ตสำหรับ SSH ในปี 1995 โดยอยู่ถัดจาก FTP บนพอร์ต 21 และ telnet บนพอร์ต 23 ซึ่งเป็นโปรโตคอลที่ SSH ถูกสร้างขึ้นมาเพื่อทดแทน ไม่มีสิ่งใดบังคับให้ต้องใช้หมายเลขนี้ โดย Port ใน /etc/ssh/sshd_config สามารถเปลี่ยนพอร์ตบนเซิร์ฟเวอร์ได้ และ ssh -p ใช้สำหรับเลือกพอร์ตอื่นบนฝั่งไคลเอนต์ เนื่องจาก 22 เป็นค่าเริ่มต้น บอทสแกนอัตโนมัติจึงพยายามเชื่อมต่อเข้ามาตลอดเวลา ซึ่งเป็นสาเหตุที่ทำให้ /var/log/auth.log ของเซิร์ฟเวอร์ใหม่เต็มไปด้วยบรรทัด Failed password for invalid user การเปลี่ยนพอร์ตช่วยลดสัญญาณรบกวนเหล่านี้ได้ แต่ไม่ได้เพิ่มความปลอดภัยที่แท้จริง
ควรทำอย่างไรเมื่อ SSH แจ้งเตือนว่า host key เปลี่ยนไป?
ให้หาสาเหตุก่อนที่จะลบข้อมูลใดๆ สาเหตุทั่วไปที่พบมักไม่มีอันตราย เช่น เซิร์ฟเวอร์ถูกติดตั้งใหม่ทำให้ sshd สร้าง host key ชุดใหม่ขึ้นมา หรือมีการนำเครื่องใหม่มาใช้ IP address เดิม หากคุณทราบว่าเครื่องถูกติดตั้งใหม่ ให้รันคำสั่ง ssh-keygen -R <host> เพื่อลบ key เดิมที่จัดเก็บไว้ แล้วเชื่อมต่อใหม่ จากนั้นเปรียบเทียบ fingerprint ที่แสดงกับค่าที่คอนโซลของผู้ให้บริการรายงาน หากคุณไม่ได้เปลี่ยนแปลงอะไรในฝั่งของคุณ ห้ามเชื่อมต่อและห้ามพิมพ์รหัสผ่านเด็ดขาด OpenSSH จะปฏิเสธการยืนยันตัวตนด้วยรหัสผ่านในสถานะนี้โดยอัตโนมัติด้วยเหตุผลดังกล่าว
SFTP และ scp ต่างจาก SSH หรือไม่?
ทั้งสองทำงานอยู่บนพื้นฐานของ SSH เมื่อคุณยืนยันตัวตนสำเร็จแล้ว การเชื่อมต่อ SSH สามารถรองรับช่องทาง (channel) ได้หลายช่องทาง ซึ่ง shell เป็นเพียงหนึ่งในนั้น SFTP เป็นโปรโตคอลการถ่ายโอนไฟล์ที่ใช้ระบบย่อย sftp ของ sshd ผ่านการเชื่อมต่อเดียวกัน และ scp ได้ใช้โปรโตคอล SFTP เป็นพื้นฐานมาตั้งแต่ OpenSSH 9.0 การทำ port forwarding และ Git over SSH ก็เป็นช่องทางหนึ่งบนการเชื่อมต่อเดียวกันเช่นกัน ทั้งหมดนี้ใช้พอร์ตเดียวกัน การตรวจสอบ host key เดียวกัน และการล็อกอินเดียวกัน โปรดทราบว่า SFTP ไม่ใช่ FTP ที่เพิ่มการเข้ารหัสเข้ามา เพราะโปรโตคอลนั้นเรียกว่า FTPS ซึ่งเป็นโปรโตคอลแยกต่างหาก
การยืนยันตัวตนด้วย key ดีกว่ารหัสผ่านจริงหรือไม่?
จริง สำหรับเซิร์ฟเวอร์ทุกเครื่องที่เข้าถึงได้จากอินเทอร์เน็ต รหัสผ่านเป็นความลับสั้นๆ ที่คุณต้องส่งให้เซิร์ฟเวอร์ทุกครั้งที่ล็อกอิน และพอร์ต 22 ก็ถูกสุ่มเดาโดยบอทอัตโนมัติตลอดเวลา สำหรับการใช้ key pair ส่วนที่เป็น private key จะไม่เคยออกจากเครื่องของคุณ โดยไคลเอนต์จะลงลายเซ็นข้อมูลที่ผูกกับเซสชันปัจจุบัน และเซิร์ฟเวอร์จะตรวจสอบลายเซ็นนั้นกับ public key ใน ~/.ssh/authorized_keys ลายเซ็นที่ถูกบันทึกไว้ไม่สามารถนำไปใช้ซ้ำกับเซิร์ฟเวอร์อื่นได้ ควรปกป้อง private key ด้วย passphrase เพราะไฟล์ key ที่ไม่มี passphrase จะถือเป็นช่องทางล็อกอินสำหรับใครก็ตามที่คัดลอกไฟล์นั้นไปได้