- Token bảo mật ký bên trong thiết bị mà không xuất khóa riêng tư ra ngoài, đồng thời yêu cầu thao tác vật lý từ người dùng nên kẻ tấn công từ xa khó tạo chữ ký tùy ý
- Có thể dùng cho xác thực SSH, U2F, đăng nhập cục bộ không mật khẩu,
sudo, ký commit git, và phần cứng bảo mật tích hợp trên laptop/điện thoại thông minh hiện đại có thể thay thế YubiKey
- Tệp “khóa riêng tư” được tạo bằng
ssh-keygen -t ed25519-sk thực ra không phải khóa riêng tư thật mà là một handle trỏ tới khóa trong token, và có thể tạo cùng một tệp khóa SSH trên máy tính khác với cùng token đó
- Trên MacBook, có thể cấu hình secure element làm khóa SSH để đăng nhập SSH bằng Touch ID, còn với ký commit git thì cần cấu hình
user.signingKey theo dạng ssh-agent và key:: thay vì đường dẫn tệp
- Token bảo mật không thể khôi phục khóa riêng tư nếu bị mất và có rủi ro về trải nghiệm sử dụng khi người dùng quen với việc chạm lặp lại; trên laptop Windows, Windows Hello có thể xác nhận việc dùng khóa SSH bằng nhận diện khuôn mặt, vân tay hoặc PIN
Ưu điểm và giới hạn của token bảo mật
-
Cấu trúc cốt lõi để ngăn tấn công từ xa
- Token bảo mật là thiết bị giữ cặp khóa riêng tư/công khai bên trong, trong đó khóa công khai có thể dễ dàng lấy ra nhưng khóa riêng tư không rời khỏi thiết bị
- Khi gửi gói dữ liệu cần ký tới thiết bị, dữ liệu sẽ được ký bên trong thiết bị bằng khóa riêng tư, và thường cần thao tác vật lý của người dùng như nhấn nút cảm ứng đang nhấp nháy
- Ngay cả khi kẻ tấn công từ xa truy cập được vào máy tính, nếu người dùng không thực hiện thao tác trong thế giới thực thì token bảo mật cũng không ký tùy ý, nên cách này có vẻ tốt hơn việc lưu toàn bộ cặp khóa riêng tư/công khai SSH thành tệp trong thư mục
~/.ssh
- Cũng có các lựa chọn dành cho người muốn firmware FOSS như SoloKeys và Nitrokeys
- Các token bảo mật cao cấp hơn còn bổ sung sinh trắc học như đầu đọc vân tay tích hợp, nhưng cốt lõi vẫn là cấu trúc không để khóa riêng tư rời khỏi thiết bị
-
Rủi ro phát sinh từ tính tiện dụng
- Nếu người dùng quen với việc nhấn token bảo mật mỗi khi nó nhấp nháy, họ có thể vô thức phản hồi cả những yêu cầu độc hại
- Trong các tác vụ ký liên tục phải chạm token lặp đi lặp lại, rất khó thực sự nhận ra một yêu cầu nhấp nháy thêm lần nữa
- Apple và Microsoft dùng cách hiển thị mã số ngẫu nhiên cho từng yêu cầu truy cập trong ứng dụng xác thực trên điện thoại để người dùng nhập lại, nhưng cách này khá phiền và làm giảm lợi thế về trải nghiệm của token bảo mật so với các ứng dụng Authy hay Google Authenticator dùng TOTP
-
Vấn đề mất thiết bị và sao lưu
- Nếu làm mất token bảo mật, khóa riêng tư tương ứng sẽ biến mất vĩnh viễn và không có cách sao lưu
- Để tránh nguy cơ bị khóa khỏi nhiều tài khoản, khi mua token bảo mật nên mua ít nhất 2 chiếc và đăng ký chúng với cùng dịch vụ
- Một phương án khác là cách sao lưu/khôi phục bằng việc chuyển khóa riêng tư thành danh sách từ mà con người có thể đọc và ghi lại, như BIP 39
- Nếu khóa riêng tư có thể rời khỏi secure enclave, cũng có thể xuất hiện tấn công lừa đảo khiến người dùng ghi danh sách từ đó ở nơi không an toàn
- Nếu thực sự lo ngại khả năng mất hết mọi token bảo mật, danh sách từ BIP 39 có thể là phương án cuối cùng để giành lại quyền truy cập hệ thống
Dùng token bảo mật với SSH và git
-
Đặt khóa riêng tư SSH trong token bảo mật
- Thông thường khi chạy
ssh-keygen, một cặp tệp chứa đầy đủ khóa riêng tư sẽ được tạo ra
- Để đặt khóa riêng tư trong token bảo mật, hãy cài libfido2 theo hướng dẫn FIDO/U2F của Yubico, rồi chạy
ssh-keygen -t ed25519-sk khi token đang được cắm vào
- Khi đó vẫn tạo ra một cặp tệp, nhưng tệp “khóa riêng tư” thực ra không phải khóa riêng tư thật mà là một handle trỏ tới khóa riêng tư nằm trong token bảo mật
- Nếu chạy lại
ssh-keygen -t ed25519-sk với cùng token bảo mật, có thể tạo cùng một cặp tệp khóa riêng tư/công khai trên bất kỳ máy nào, nên quyền truy cập SSH sẽ di chuyển cùng token bảo mật chứ không gắn với một tệp cụ thể trên một máy cụ thể
-
Xác thực git và ký commit
- Khoảng 90% số lần phải chạm token bảo mật là do dùng git
- Các git forge triển khai xác thực SSH cho thao tác push và pull, và chỉ cần tải lên tệp
id_ed25519_sk.pub đã tạo ở trên là có thể cho phép cặp khóa của token bảo mật
- git cũng hỗ trợ khóa SSH cho ký commit; sau khi làm theo thiết lập khóa ký bằng khóa SSH trong tài liệu GitHub rồi chạy
git config --global commit.gpgsign true, mọi commit sẽ được tự động ký
- Để git forge nhận commit là do chính bạn ký, cần tải khóa công khai lên thêm lần nữa; trường này thường tách biệt với trường dùng cho xác thực SSH
-
Sự bất tiện của ký commit
- Khi rebase một danh sách commit dài, bạn phải ký lại toàn bộ commit
- YubiKey có đầu đọc vân tay có tỷ lệ nhận sai quá cao để ký liên tục hàng chục commit, nên cuối cùng phải ngừng dùng
- Trong jujutsu, một wrapper của git theo hướng “rebase/amend-first”, có cách chỉ ký commit tại thời điểm push
-
Đăng nhập cục bộ Linux và sudo
Dùng secure element của MacBook làm khóa SSH
- Nếu cứ cắm token bảo mật ở cổng USB-C, nó sẽ lòi ra như một đòn bẩy nhỏ có thể làm hỏng cả cổng lẫn token nếu vô tình va đập hoặc làm rơi
- Trên MacBook Air M1 đời 2020, tác giả đã làm theo hướng dẫn của Arian van Putten để cấu hình phần tử bảo mật tích hợp làm khóa SSH
sc_auth create-ctk-identity -l ssh -k p-256-ne -t bio
ssh-keygen -w /usr/lib/ssh-keychain.dylib -K -N ""
- Lệnh này tạo cặp tệp khóa riêng tư/công khai
id_ecdsa_sk_rk, rồi chuyển các tệp đó vào thư mục ~/.ssh
- Ở đây nữa, tệp khóa riêng tư không phải khóa riêng tư thật mà là handle tới khóa nằm trong thiết bị, nên có dạng có thể dán công khai
- Để thêm khóa công khai vào máy chủ homelab làm authorized key, chạy như sau
ssh-copy-id -i ~/.ssh/id_ecdsa_sk_rk.pub <server nickname>
- Sau đó thêm cấu hình sau vào
~/.ssh/config
Host *
IdentityFile ~/.ssh/id_ecdsa_sk_rk
SecurityKeyProvider=/usr/lib/ssh-keychain.dylib
- Khi chạy
ssh <server nickname>, macOS sẽ tự động hiển thị yêu cầu xác thực vân tay trước khi đăng nhập, rồi đăng nhập SSH diễn ra bình thường
Ký commit git bằng secure element của MacBook
- Ngay cả khi đặt
git config --global user.signingKey /Users/ahelwer/.ssh/id_ecdsa_sk_rk và cập nhật tệp .ssh/allowed_signers, việc ký commit git vẫn không hoạt động ngay
- git sẽ báo lỗi khi ký commit, như
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
- Giải pháp là dùng ssh-agent thay vì trỏ trực tiếp tới tệp trong thư mục
~/.ssh
- Theo tutorial ở trên, hãy đăng ký cặp khóa vào ssh-agent bằng lệnh sau
ssh-add -K -S /usr/lib/ssh-keychain.dylib
- Sau đó, trong
user.signingKey, không dùng đường dẫn tệp mà đặt chính khóa với tiền tố key:: trước nội dung của ~/.ssh/id_ecdsa_sk_rk.pub vào ~/.gitconfig
[user]
name = Andrew Helwer
signingKey = "key::sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGxFEdnIg6ppz+pQCdd1eisjOV4gxrjMv1Y4SbtdLoSm6CJCgPZ6q7lnNyuQQsdnS4/Tllsc656AQL7BO3OS47cAAAAEc3NoOg== ssh:"
- Sau cấu hình này, tác giả có thể ký tệp bằng khóa nằm trong secure element của MacBook và push lên trang GitLab Pages
Kết quả thử nghiệm trên Windows và Linux
- Tác giả cũng thử nhanh trên laptop Windows do công ty cấp
winget install Microsoft.OpenSSH.preview
ssh-keygen -t ecdsa-sk
- Lệnh này cũng tạo ra cặp tệp khóa riêng tư/công khai, và khi kết nối SSH thì chấp nhận một trong các luồng đăng nhập tiêu chuẩn của Windows Hello: nhận diện khuôn mặt, vân tay hoặc PIN
- Trên Linux, tác giả không thể demo vì không có quyền truy cập vào chiếc laptop có secure element sau bước xác nhận sự hiện diện thực tế của người dùng tương tự như trên
1 bình luận
Ý kiến trên Lobste.rs
Bài viết rất hay, và chỉ riêng việc cho thấy điều này là khả thi đã cực kỳ hữu ích
Cá nhân tôi thì chưa tìm ra đúng phiên bản thư viện để làm nó chạy, nhưng tôi biết được rằng 1Password 8 lưu khóa SSH an toàn và agent hỗ trợ mở khóa bằng xác thực sinh trắc học
Vì vậy giờ tôi có thể làm việc với git và đăng nhập vào host SSH chỉ bằng cách đặt ngón tay lên cảm biến
Hướng dẫn: https://developer.1password.com/docs/ssh/get-started/
Cái này có vẻ chỉ dành cho Mac
Tôi chưa có dịp thử hệ thống Linux nào có phần tử bảo mật như vậy, và máy trạm Linux của tôi có TPM V1 nhưng tôi không rõ có cách nào đảm bảo thao tác ký chỉ được thực hiện sau khi xác nhận sự hiện diện thực sự của người dùng hay không
Có lẽ ai dùng laptop Linux như Framework có thể thử. Biết đâu nó cũng thật sự chạy được trên Asahi
Vậy chính xác thì trong file private key được cung cấp có những gì?
ssh:, tức application, tương ứng với origin của passkey và hữu ích khi tạo resident key theo từng host hoặc domainVí dụ, tôi dùng nó để tách khóa theo từng mục đích ngay cả trên cùng một Yubikey vật lý
flagschỉ định phần cứng phải xử lý khóa như thế nào [1]. Agent cũng có thể tự thêm các ràng buộc riêngVề mặt kỹ thuật, bạn cũng có thể lưu các blob hoặc extension khác trong khóa FIDO, và ở công việc trước đây tôi từng dùng nó để chuyển các thông tin xác thực phụ như khóa công khai X.509 cùng với quá trình xác thực. Cách này khá hay
[1]
Phần bao ngoài có magic value
openssh-key-v1\0,cipher=none,kdf=none, nên nó không phải bản mãBlob public key dài 74 byte chứa kiểu khóa
sk-ssh-ed25519@openssh.com, điểm Ed25519 32 bytefdcce889…03e7852b, và applicationssh:; giá trị này dùng để tách namespace thông tin xác thực FIDO giữa SSH và WebAuthnPhần private dài 248 byte và vì
cipher=nonenên ở dạng plain text. Nó chứa giá trị ngẫu nhiêncheckint1 == checkint2 == 0x46744267, kiểu khóa và public key lặp lại, applicationssh:, vàflags: 0x01Cờ này là
USER_PRESENCE_REQUIRED, nên cần chạm nhưng không yêu cầu PIN/xác minh người dùng, và đây là khóa không thường trúkey_handlelà credential ID mờ đục dài 128 byte được truyền vàoauthenticatorGetAssertion, và thiết bị sẽ giải nó nội bộ để khôi phục seed Ed25519Ngoài ra còn có
reservedrỗng, commentahelwer@ah-mbair.local, và padding01 02 03Bài này có vẻ chỉ nói về SSH, nhưng có cách nào dùng Secure Enclave hoặc TPM trên máy tính của tôi như khóa FIDO2 hoặc U2F không?
Passkey cũng là một dạng của cách làm này, dùng private key riêng biệt cho từng website
Nhìn vào điều này, tôi thấy khá lạ là hỗ trợ cho API key bất đối xứng hoặc HMAC có thể ràng buộc với phần cứng lại không phổ biến hơn
Thật đáng mừng khi ngày càng có nhiều đặc tả thúc đẩy hướng này hơn, như WebAuthn, DBSC(Device-Bound Session Credentials), và OAuth2 DPOP