- โทเค็นความปลอดภัย จะลงนามอยู่ภายในอุปกรณ์โดยไม่ส่งออกคีย์ส่วนตัวออกนอกอุปกรณ์ และต้องอาศัยการกระทำทางกายภาพจากผู้ใช้ ทำให้ผู้โจมตีจากระยะไกลสร้างลายเซ็นตามอำเภอใจได้ยาก
- ใช้กับการยืนยันตัวตน SSH, U2F, การล็อกอินภายในเครื่องแบบไร้รหัสผ่าน,
sudo, และการลงนามคอมมิต git ได้ และอุปกรณ์ความปลอดภัยแบบฝังในโน้ตบุ๊กหรือสมาร์ตโฟนรุ่นใหม่สามารถมาแทน YubiKey ได้
- ไฟล์ “คีย์ส่วนตัว” ที่สร้างด้วย
ssh-keygen -t ed25519-sk ไม่ใช่คีย์ส่วนตัวจริง แต่เป็น แฮนเดิล ที่ชี้ไปยังคีย์ในโทเค็น และสามารถสร้างไฟล์คีย์ SSH ชุดเดิมจากโทเค็นเดียวกันบนคอมพิวเตอร์เครื่องอื่นได้
- บน MacBook สามารถตั้งค่า secure element เป็นคีย์ SSH เพื่อใช้ล็อกอิน SSH ด้วย Touch ID ได้ และสำหรับการลงนามคอมมิต git จำเป็นต้องตั้งค่า
user.signingKey ในรูปแบบ ssh-agent และ key:: แทนการใช้พาธไฟล์
- โทเค็นความปลอดภัยไม่สามารถกู้คืนคีย์ส่วนตัวได้หากทำหาย และยังมีความเสี่ยงด้านการใช้งานจากการแตะยืนยันซ้ำๆ ขณะที่บนโน้ตบุ๊ก Windows นั้น Windows Hello สามารถยืนยันการใช้คีย์ SSH ด้วยการจดจำใบหน้า ลายนิ้วมือ หรือ PIN ได้
ข้อดีและข้อจำกัดของโทเค็นความปลอดภัย
-
โครงสร้างหลักที่ป้องกันการโจมตีจากระยะไกล
- โทเค็นความปลอดภัยเป็นอุปกรณ์ที่เก็บคู่คีย์ส่วนตัว/คีย์สาธารณะไว้ภายในอุปกรณ์ โดยสามารถดึงคีย์สาธารณะออกมาได้ง่าย แต่ทำให้ คีย์ส่วนตัวไม่ออกไปนอกอุปกรณ์
- เมื่อส่งแพ็กเก็ตข้อมูลที่จะลงนามไปยังอุปกรณ์ อุปกรณ์จะลงนามภายในด้วยคีย์ส่วนตัว และโดยทั่วไปต้องมี การกระทำทางกายภาพของผู้ใช้ เช่น กดปุ่มสัมผัสที่กำลังกะพริบ
- แม้ผู้โจมตีจากระยะไกลจะเข้าถึงคอมพิวเตอร์ได้ หากผู้ใช้ไม่ได้กระทำอะไรในโลกจริง โทเค็นความปลอดภัยก็จะไม่ลงนามตามอำเภอใจให้ จึงดูดีกว่าวิธีเก็บคู่คีย์ SSH ส่วนตัว/สาธารณะทั้งชุดไว้เป็นไฟล์ในไดเรกทอรี
~/.ssh
- ยังมีตัวเลือกอย่าง SoloKeys และ Nitrokeys สำหรับผู้ที่ต้องการเฟิร์มแวร์ FOSS
- โทเค็นความปลอดภัยระดับสูงกว่ายังเพิ่มความสามารถด้านไบโอเมตริก เช่น เครื่องอ่านลายนิ้วมือในตัว แต่แก่นสำคัญคือโครงสร้างที่ไม่ปล่อยคีย์ส่วนตัวออกนอกอุปกรณ์
-
ความเสี่ยงที่เกิดจากการใช้งาน
- หากผู้ใช้ชินกับการกดโทเค็นความปลอดภัยทุกครั้งที่มันกะพริบ ก็อาจเผลอตอบสนองต่อคำขอที่เป็นอันตรายได้
- ในสถานการณ์ที่ต้องลงนามต่อเนื่องและต้องแตะโทเค็นซ้ำๆ ก็อาจสังเกตได้ยากว่ามีคำขอกะพริบเพิ่มมาอีกหนึ่งครั้งจริงหรือไม่
- Apple และ Microsoft ใช้วิธีให้แอปยืนยันตัวตนบนสมาร์ตโฟนแสดงรหัสตัวเลขแบบสุ่มในแต่ละคำขอ แล้วให้ผู้ใช้ป้อนรหัสนั้น แต่วิธีนี้ยุ่งยากและลดข้อได้เปรียบด้านการใช้งานของโทเค็นความปลอดภัยเมื่อเทียบกับแอปอย่าง Authy หรือ Google Authenticator ที่ใช้ TOTP
-
ปัญหาเรื่องการสูญหายและการสำรองข้อมูล
- หากทำโทเค็นความปลอดภัยหาย คีย์ส่วนตัวนั้นจะหายไปถาวรและไม่มีวิธีสำรองคืน
- เพื่อหลีกเลี่ยงความเสี่ยงที่จะถูกล็อกจากหลายบัญชี ควรซื้อโทเค็นความปลอดภัยอย่างน้อย 2 ชิ้นและลงทะเบียนไว้กับบริการเดียวกัน
- อีกทางเลือกหนึ่งคือแนวทางสำรองและกู้คืนแบบ BIP 39 ที่แปลงคีย์ส่วนตัวเป็นรายการคำที่มนุษย์อ่านได้แล้วจดเก็บไว้
- หากคีย์ส่วนตัวสามารถออกจาก secure enclave ได้ ก็อาจเกิดการโจมตีแบบฟิชชิงที่ล่อให้ผู้ใช้จดรายการคำเหล่านั้นไว้ในที่ที่ไม่ถูกต้องได้
- หากกังวลอย่างมากว่าจะทำโทเค็นความปลอดภัยหายทั้งหมด รายการคำแบบ BIP 39 ก็อาจเป็นทางเลือกสุดท้ายเพื่อกู้การเข้าถึงระบบกลับมา
การใช้โทเค็นความปลอดภัยกับ SSH และ git
-
เก็บคีย์ส่วนตัว SSH ไว้ในโทเค็นความปลอดภัย
- โดยทั่วไปเมื่อรัน
ssh-keygen จะได้ไฟล์คู่หนึ่งที่มีคีย์ส่วนตัวเต็มรูปแบบอยู่ภายใน
- หากต้องการเก็บคีย์ส่วนตัวไว้ในโทเค็นความปลอดภัย ให้ติดตั้ง libfido2 ตาม คู่มือ FIDO/U2F ของ Yubico แล้วรัน
ssh-keygen -t ed25519-sk ขณะเสียบโทเค็นความปลอดภัยอยู่
- แม้จะยังสร้างไฟล์คู่ขึ้นมา แต่ไฟล์ “คีย์ส่วนตัว” ในที่นี้ไม่ใช่คีย์ส่วนตัวจริง หากเป็นแฮนเดิลที่ชี้ไปยังคีย์ส่วนตัวในโทเค็นความปลอดภัย
- หากรัน
ssh-keygen -t ed25519-sk อีกครั้งด้วยโทเค็นความปลอดภัยตัวเดิม ก็สามารถสร้างไฟล์คีย์ส่วนตัว/คีย์สาธารณะชุดเดียวกันได้จากคอมพิวเตอร์เครื่องไหนก็ได้ ทำให้สิทธิ์เข้าถึง SSH เคลื่อนย้ายไปพร้อมกับโทเค็นความปลอดภัย ไม่ได้ผูกกับไฟล์ใดไฟล์หนึ่งบนเครื่องใดเครื่องหนึ่ง
-
การยืนยันตัวตนกับ git และการลงนามคอมมิต
- ประมาณ 90% ของสถานการณ์ที่ต้องกดโทเค็นความปลอดภัยเกิดขึ้นเพราะใช้งาน git
- บริการ git forge ต่างๆ รองรับการยืนยันตัวตน SSH สำหรับการ push และ pull และหากอัปโหลดไฟล์
id_ed25519_sk.pub ที่สร้างไว้ ก็จะอนุญาตให้ใช้คู่คีย์ของโทเค็นความปลอดภัยได้
- git ยังรองรับการใช้คีย์ SSH สำหรับลงนามคอมมิตด้วย และหากทำตามเอกสาร GitHub เรื่อง ตั้งค่าคีย์สำหรับลงนามด้วยคีย์ SSH แล้วรัน
git config --global commit.gpgsign true คอมมิตทั้งหมดก็จะถูกลงนามอัตโนมัติ
- เพื่อให้ git forge มองว่าคอมมิตนั้นเป็นลายเซ็นของตัวเอง จำเป็นต้องอัปโหลดคีย์สาธารณะอีกครั้ง โดยปกติช่องนี้จะแยกจากช่องสำหรับคีย์ยืนยันตัวตน SSH
-
ความไม่สะดวกของการลงนามคอมมิต
- เมื่อต้อง rebase รายการคอมมิตยาวๆ จะต้องลงนามคอมมิตใหม่ทั้งหมด
- YubiKey ที่มีเครื่องอ่านลายนิ้วมือมีอัตราการอ่านไม่ผ่านสูงเกินไปสำหรับการลงนามคอมมิตต่อเนื่องหลายสิบรายการ จนต้องเลิกใช้
- ใน jujutsu ซึ่งเป็นแรปเปอร์ของ git แบบ “rebase/amend เป็นศูนย์กลาง” มีวิธี ลงนามคอมมิตเฉพาะตอน push
-
การล็อกอินภายในเครื่องบน Linux และ sudo
การใช้ secure element ของ MacBook เป็นคีย์ SSH
- หากเสียบโทเค็นความปลอดภัยคาไว้ที่พอร์ต USB-C ตลอดเวลา มันจะยื่นออกมาเหมือนคานงัดเล็กๆ ที่อาจทำให้ทั้งพอร์ตและตัวโทเค็นเสียหายได้เมื่อเผลอทำตกหรือชนเข้า
- บน MacBook Air ชิป M1 รุ่นปี 2020 ได้ตั้งค่าองค์ประกอบความปลอดภัยแบบฝังให้เป็นคีย์ SSH ตามคู่มือของ Arian van Putten
sc_auth create-ctk-identity -l ssh -k p-256-ne -t bio
ssh-keygen -w /usr/lib/ssh-keychain.dylib -K -N ""
- คำสั่งนี้จะสร้างไฟล์คู่คีย์ส่วนตัว/คีย์สาธารณะ
id_ecdsa_sk_rk แล้วจึงย้ายไฟล์เหล่านี้ไปไว้ในไดเรกทอรี ~/.ssh
- ตรงนี้เช่นกัน ไฟล์คีย์ส่วนตัวไม่ใช่คีย์ส่วนตัวจริง แต่เป็นแฮนเดิลของคีย์ในอุปกรณ์ จึงอยู่ในรูปแบบที่นำไปวางแบบเปิดเผยได้
- หากต้องการเพิ่มคีย์สาธารณะเป็น authorized key ให้กับเซิร์ฟเวอร์ homelab ให้รันดังนี้
ssh-copy-id -i ~/.ssh/id_ecdsa_sk_rk.pub <server nickname>
- จากนั้นเพิ่มการตั้งค่าต่อไปนี้ใน
~/.ssh/config
Host *
IdentityFile ~/.ssh/id_ecdsa_sk_rk
SecurityKeyProvider=/usr/lib/ssh-keychain.dylib
- เมื่อรัน
ssh <server nickname> macOS จะขึ้นคำขอใช้ลายนิ้วมือโดยอัตโนมัติก่อนล็อกอิน แล้วจึงเข้าสู่ระบบ SSH ได้ตามปกติ
การลงนามคอมมิต git ด้วย secure element ของ MacBook
- แม้จะตั้งค่า
git config --global user.signingKey /Users/ahelwer/.ssh/id_ecdsa_sk_rk และอัปเดตไฟล์ .ssh/allowed_signers แล้ว การลงนามคอมมิต git ก็ยังไม่ทำงานทันที
- git จะลงนามคอมมิตไม่สำเร็จและแสดงข้อผิดพลาดอย่าง
device not found?
error: Signing file /var/folders/l5/5wqvq2l10p96wtdtfr6lvrvw0000gn/T//.git_signing_buffer_tmpc4uQgO
Confirm user presence for key ECDSA-SK SHA256:oQDA2SNYb2MoSQcxJVSmWyAeAWPqMp7rxliBRfi87as
Couldn't sign message: device not found?
Signing /var/folders/l5/5wqvq2l10p96wtdtfr6lvrvw0000gn/T//.git_signing_buffer_tmpc4uQgO failed: device not found?
fatal: failed to write commit object
- วิธีแก้คือใช้ ssh-agent แทนการอ้างอิงไฟล์ในไดเรกทอรี
~/.ssh โดยตรง
- ตามคู่มือข้างต้น ให้ลงทะเบียนคู่คีย์เข้า
ssh-agent ด้วยคำสั่งต่อไปนี้
ssh-add -K -S /usr/lib/ssh-keychain.dylib
- หลังจากนั้น ใน
user.signingKey ให้ใส่ตัวคีย์เองพร้อมเติม key:: นำหน้าเนื้อหาของ ~/.ssh/id_ecdsa_sk_rk.pub ลงใน ~/.gitconfig แทนพาธไฟล์
[user]
name = Andrew Helwer
signingKey = "key::sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGxFEdnIg6ppz+pQCdd1eisjOV4gxrjMv1Y4SbtdLoSm6CJCgPZ6q7lnNyuQQsdnS4/Tllsc656AQL7BO3OS47cAAAAEc3NoOg== ssh:"
- หลังตั้งค่านี้ ก็สามารถลงนามไฟล์ด้วยคีย์ใน secure element ของ MacBook และ push ไปยังไซต์ GitLab Pages ได้
ผลที่ลองบน Windows และ Linux
- ได้ทดลองแบบรวดเร็วบนโน้ตบุ๊ก Windows ของบริษัทด้วย
winget install Microsoft.OpenSSH.preview
ssh-keygen -t ecdsa-sk
- คำสั่งนี้ก็สร้างไฟล์คู่คีย์ส่วนตัว/คีย์สาธารณะเช่นกัน และตอนเชื่อมต่อ SSH ก็ยอมรับการจดจำใบหน้า ลายนิ้วมือ หรือ PIN ผ่านขั้นตอนล็อกอินมาตรฐานของ Windows Hello
- ส่วนบน Linux นั้นยังสาธิตไม่ได้ เพราะไม่มีสิทธิ์เข้าถึงโน้ตบุ๊กที่มี secure element และต้องผ่านการยืนยันว่ามีผู้ใช้อยู่จริงในลักษณะคล้ายกัน
1 ความคิดเห็น
ความเห็นจาก Lobste.rs
เป็นบทความที่ยอดเยี่ยม และแค่การแสดงให้เห็นว่า สิ่งนี้ทำได้จริง ก็มีประโยชน์มากแล้ว
ส่วนตัวผมหาเวอร์ชันไลบรารีที่เหมาะสำหรับให้มันทำงานไม่ได้ แต่ก็ได้รู้ว่า 1Password 8 เก็บ SSH key อย่างปลอดภัยได้ และ agent รองรับการ ปลดล็อกคีย์ด้วยการยืนยันตัวตนแบบชีวมิติ
ตอนนี้เลยทั้งใช้ git และล็อกอินเข้า SSH host ได้แค่แตะนิ้วเท่านั้น
คู่มือ: https://developer.1password.com/docs/ssh/get-started/
อันนี้ดูเหมือนจะ เฉพาะ Mac
ผมยังไม่ได้มีโอกาสลองกับระบบ Linux ที่มี secure element แบบนั้น และบน Linux workstation ของผมมี TPM V1 อยู่ แต่ไม่รู้ชัดว่ามีวิธีไหนจะรับประกันได้ไหมว่าให้การลงนามเกิดขึ้นหลังจากยืนยันการมีอยู่ของผู้ใช้จริงเท่านั้น
คนที่มีโน้ตบุ๊ก Linux อย่าง Framework อาจลองได้ หรือบางทีอาจใช้กับ Asahi ได้จริงด้วย
แล้วใน ไฟล์ private key ที่ได้มาจริง ๆ มันมีอะไรอยู่ข้างในกันแน่?
ssh:หรือก็คือแอปพลิเคชัน เทียบได้กับ origin ของ passkey และมีประโยชน์เวลาสร้าง resident key แยกตามโฮสต์หรือโดเมนตัวอย่างเช่น ผมใช้มันเพื่อแยกคีย์ตามงาน แม้อยู่ใน Yubikey ตัวเดียวกันทางกายภาพก็ตาม
flagsใช้ระบุว่าฮาร์ดแวร์ควรจัดการกับคีย์อย่างไร [1] และ agent ก็อาจเพิ่มข้อจำกัดของตัวเองเข้าไปได้ในทางเทคนิคแล้ว ยังสามารถเก็บ blob หรือ extension อื่น ๆ ไว้ใน FIDO key ได้ด้วย และที่ทำงานเก่าของผมเคยใช้มันส่ง credential เสริมอย่าง X.509 public key ไปพร้อมกับการยืนยันตัวตนด้วย วิธีนี้ค่อนข้างเจ๋งมาก
[1]
ตัวห่อชั้นนอกมีค่า magic
openssh-key-v1\0,cipher=none,kdf=noneจึงไม่ใช่ ciphertextpublic key blob ขนาด 74 ไบต์มีชนิดคีย์
sk-ssh-ed25519@openssh.com, จุด Ed25519 32 ไบต์fdcce889…03e7852bและแอปพลิเคชันssh:อยู่ภายใน ซึ่งค่านี้ใช้แยก namespace ของ FIDO credential ระหว่าง SSH กับ WebAuthnส่วน private มีขนาด 248 ไบต์ และเพราะ
cipher=noneจึงเป็น plaintext โดยมีcheckint1 == checkint2 == 0x46744267ซึ่งเป็นค่าสุ่ม, ชนิดคีย์และ public key ที่ซ้ำกัน, แอปพลิเคชันssh:และflags: 0x01แฟล็กนี้คือ
USER_PRESENCE_REQUIREDหมายถึงต้องแตะอุปกรณ์ แต่ไม่มี PIN/การยืนยันตัวผู้ใช้ และเป็นคีย์แบบไม่ residentkey_handleคือ credential ID แบบ opaque ขนาด 128 ไบต์ที่ถูกส่งเข้าauthenticatorGetAssertionและอุปกรณ์จะถอดความภายในเพื่อกู้คืน Ed25519 seedนอกจากนี้ยังมี
reservedที่ว่างอยู่, คอมเมนต์ahelwer@ah-mbair.localและ padding01 02 03บทความนี้เหมือนจะพูดถึงแค่ SSH แต่มีวิธีใช้ Secure Enclave หรือ TPM ในคอมพิวเตอร์ของผมให้เป็นคีย์ FIDO2 หรือ U2F ไหม?
Passkey เองก็เป็นรูปแบบหนึ่งของแนวทางนี้ ที่ใช้ private key แยกกันคนละดอกสำหรับแต่ละเว็บไซต์
พอเห็นแบบนี้แล้ว ก็แปลกดีที่การรองรับ API key แบบ asymmetric หรือ HMAC ที่ผูกกับฮาร์ดแวร์ได้ ยังไม่แพร่หลายกว่านี้
ยิ่งมีสเปกอย่าง WebAuthn, DBSC(Device-Bound Session Credentials) และ OAuth2 DPOP ที่ผลักดันแนวทางนี้มากขึ้นเรื่อย ๆ ก็ยิ่งน่ายินดี