1 คะแนน โดย GN⁺ 4 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • โทเค็นความปลอดภัย จะลงนามอยู่ภายในอุปกรณ์โดยไม่ส่งออกคีย์ส่วนตัวออกนอกอุปกรณ์ และต้องอาศัยการกระทำทางกายภาพจากผู้ใช้ ทำให้ผู้โจมตีจากระยะไกลสร้างลายเซ็นตามอำเภอใจได้ยาก
  • ใช้กับการยืนยันตัวตน 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

    • บนระบบ Linux สามารถใช้ Pluggable Authentication Module(PAM) เพื่อใช้โทเค็นความปลอดภัยกับการล็อกอินภายในเครื่องแบบไร้รหัสผ่านและการยกระดับสิทธิ์ 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 ความคิดเห็น

 
GN⁺ 4 시간 전
ความเห็นจาก Lobste.rs
  • เป็นบทความที่ยอดเยี่ยม และแค่การแสดงให้เห็นว่า สิ่งนี้ทำได้จริง ก็มีประโยชน์มากแล้ว
    ส่วนตัวผมหาเวอร์ชันไลบรารีที่เหมาะสำหรับให้มันทำงานไม่ได้ แต่ก็ได้รู้ว่า 1Password 8 เก็บ SSH key อย่างปลอดภัยได้ และ agent รองรับการ ปลดล็อกคีย์ด้วยการยืนยันตัวตนแบบชีวมิติ
    ตอนนี้เลยทั้งใช้ git และล็อกอินเข้า SSH host ได้แค่แตะนิ้วเท่านั้น
    คู่มือ: https://developer.1password.com/docs/ssh/get-started/

  • อันนี้ดูเหมือนจะ เฉพาะ Mac

    • ผมใช้โน้ตบุ๊ก Windows รุ่นใหม่ของบริษัทได้ เลยตั้งค่าให้ OpenSSH ทำงานร่วมกับ Windows Hello แบบนี้
      winget install Microsoft.OpenSSH.preview  
      ssh-keygen -t ecdsa-sk  
      
      หลังจากนั้นก็ทำงานเหมือนเดิม และทุกครั้งที่ใช้คีย์ SSH เข้าไปที่ไหนก็ตาม ก็จะผ่านขั้นตอนมาตรฐานของ Windows Hello ซึ่งให้ใช้เครื่องสแกนนิ้ว, การสแกนใบหน้า หรือ PIN ได้
      ผมยังไม่ได้มีโอกาสลองกับระบบ Linux ที่มี secure element แบบนั้น และบน Linux workstation ของผมมี TPM V1 อยู่ แต่ไม่รู้ชัดว่ามีวิธีไหนจะรับประกันได้ไหมว่าให้การลงนามเกิดขึ้นหลังจากยืนยันการมีอยู่ของผู้ใช้จริงเท่านั้น
      คนที่มีโน้ตบุ๊ก Linux อย่าง Framework อาจลองได้ หรือบางทีอาจใช้กับ Asahi ได้จริงด้วย
    • ก็น่าจะใช่เกือบทั้งหมด ผมไม่แน่ใจว่า Linux หรือ Windows มี เลเยอร์จำลอง TPM2 FIDO หรือเปล่า
  • แล้วใน ไฟล์ private key ที่ได้มาจริง ๆ มันมีอะไรอยู่ข้างในกันแน่?

    • @wrs ตอบไปก่อนแล้ว แต่ส่วน ssh: หรือก็คือแอปพลิเคชัน เทียบได้กับ origin ของ passkey และมีประโยชน์เวลาสร้าง resident key แยกตามโฮสต์หรือโดเมน
      ตัวอย่างเช่น ผมใช้มันเพื่อแยกคีย์ตามงาน แม้อยู่ใน Yubikey ตัวเดียวกันทางกายภาพก็ตาม
      flags ใช้ระบุว่าฮาร์ดแวร์ควรจัดการกับคีย์อย่างไร [1] และ agent ก็อาจเพิ่มข้อจำกัดของตัวเองเข้าไปได้
      ในทางเทคนิคแล้ว ยังสามารถเก็บ blob หรือ extension อื่น ๆ ไว้ใน FIDO key ได้ด้วย และที่ทำงานเก่าของผมเคยใช้มันส่ง credential เสริมอย่าง X.509 public key ไปพร้อมกับการยืนยันตัวตนด้วย วิธีนี้ค่อนข้างเจ๋งมาก
      [1]
      #define SSH_SK_USER_PRESENCE_REQD  0x01  
      #define SSH_SK_USER_VERIFICATION_REQD  0x04  
      #define SSH_SK_FORCE_OPERATION    0x10  
      #define SSH_SK_RESIDENT_KEY    0x20  
      
    • ตามที่ Claude บอก และเมื่อเช็กด้วย openssh_key_parser แล้ว โครงสร้างเป็นแบบนี้
      ตัวห่อชั้นนอกมีค่า magic openssh-key-v1\0, cipher=none, kdf=none จึงไม่ใช่ ciphertext
      public 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/การยืนยันตัวผู้ใช้ และเป็นคีย์แบบไม่ resident
      key_handle คือ credential ID แบบ opaque ขนาด 128 ไบต์ที่ถูกส่งเข้า authenticatorGetAssertion และอุปกรณ์จะถอดความภายในเพื่อกู้คืน Ed25519 seed
      นอกจากนี้ยังมี reserved ที่ว่างอยู่, คอมเมนต์ ahelwer@ah-mbair.local และ padding 01 02 03
    • ถ้าเอาไปใส่ตัวถอดรหัส base64 จะได้แบบนี้

      openssh-key-v1����\u0004none���\u0004none�������\u0001���J���\u001ask-ssh-ed25519@openssh.com��� 盘˪<F$KW\u0003+���\u0004ssh:���FtBgFtBg���\u001ask-ssh-ed25519@openssh.com��� 盘˪<F$KW\u0003+���\u0004ssh:\u0001���\u0013fІpF$D8"&0\u0014[X\u0018 'L=Ev\u0001 ')BjM]$}rTv6Z+p\u00199O\u000e8ݹ%V* f.|қ.%I{9\u0016 .W !\u007fD"8N ai*W�y53 �������\u0016ahelwer@ah-mbair.local\u0001\u0002\u0003
      ในนั้นมีเวอร์ชันมาตรฐานคีย์ v1, ชนิดคีย์ sk-ssh-ed25519@openssh.com ที่ถูกใส่มาซ้ำด้วยเหตุผลบางอย่าง และชื่อคีย์ที่มนุษย์อ่านได้คือ ahelwer@ah-mbair.local
      ที่เหลือน่าจะเป็นแฟล็กของ OpenSSH เช่น ต้องใช้ PIN หรือยืนยันการมีอยู่ของผู้ใช้หรือไม่ และเป็น handle GUID ที่ OpenSSH ส่งต่อพร้อม challenge ไปยัง FIDO/U2F API ได้
      OpenSSH สามารถอนุมานได้จากชนิดคีย์ โดยเฉพาะ sk ว่านี่ไม่ใช่ private key จริง แต่ต้องไปเรียกใช้ secure element แทน
      จากนั้นมันจะดูการตั้งค่า SecurityKeyProvider หรือ environment variable SSH_SK_PROVIDER เพื่อรู้ว่าควรโหลด dynamic library จากที่ไหนเพื่อใช้สื่อสารกับ secure element

  • บทความนี้เหมือนจะพูดถึงแค่ SSH แต่มีวิธีใช้ Secure Enclave หรือ TPM ในคอมพิวเตอร์ของผมให้เป็นคีย์ FIDO2 หรือ U2F ไหม?

    • ได้แน่นอน และแทบจะควรทำงานได้ด้วยการตั้งค่าพื้นฐานอยู่แล้ว
      Passkey เองก็เป็นรูปแบบหนึ่งของแนวทางนี้ ที่ใช้ private key แยกกันคนละดอกสำหรับแต่ละเว็บไซต์
  • พอเห็นแบบนี้แล้ว ก็แปลกดีที่การรองรับ API key แบบ asymmetric หรือ HMAC ที่ผูกกับฮาร์ดแวร์ได้ ยังไม่แพร่หลายกว่านี้
    ยิ่งมีสเปกอย่าง WebAuthn, DBSC(Device-Bound Session Credentials) และ OAuth2 DPOP ที่ผลักดันแนวทางนี้มากขึ้นเรื่อย ๆ ก็ยิ่งน่ายินดี