Đánh giá bảo mật Nym
Kiểm toán tính bảo mật của các thành phần cốt lõi Nym
Giới thiệu
Vào tháng 7 năm 2021, Nym đã trải qua một cuộc kiểm toán bảo mật do Jean-Philippe Aumasson, một chuyên gia bảo mật nổi tiếng thực hiện. Mục tiêu là xác định những lỗ hổng và lỗi tiềm ẩn trong mã nguồn của Nym, tập trung vào mật mã, bảo mật mã và bảo mật giao thức. Đánh giá nhằm đảm bảo tính toàn vẹn và độ bền vững của hệ thống, bao quát các khía cạnh chính của kiến trúc và triển khai. Bạn có thể xem báo cáo kiểm toán đầy đủ tại đây.
Tóm tắt cuộc kiểm toán
Cuộc kiểm toán diễn ra vào mùa hè năm 2021. Phạm vi của cuộc kiểm toán bao gồm nhiều kho lưu trữ của dự án Nym, bao gồm:
- Kho lưu trữ chính của Nym: nymtech/nym, triển khai các dịch vụ mixnode, cổng và trình xác thực.
- Định dạng gói Sphinx Mixnet: nymtech/sphinx, được sử dụng bởi các mixnode.
- Giao thức Chữ ký Ngưỡng làm mù Coconut: nymtech/coconut, được sử dụng để cấp phát thông tin xác thực.
Cuộc kiểm toán liên quan đến việc xem xét phiên bản mới nhất của mã trong nhánh phát triển, thường xuyên được làm mới do sự tiến triển nhanh chóng của dự án. Nhóm Nym đã cung cấp cho JP Aumasson quyền truy cập đầy đủ vào codebase, các thông số kỹ thuật chi tiết của dự án, các tài liệu nghiên cứu và tài liệu hỗ trợ.
Các khía cạnh trọng tâm của cuộc kiểm toán
Kiểm toán tập trung vào ba lĩnh vực chính: bảo mật mã, mật mã và thiết kế giao thức. Các kiểm toán viên đã kiểm tra kỹ lưỡng codebase của Nym để xác định các lỗ hổng, tìm kiếm các vấn đề phổ biến như các mô hình lập trình không an toàn và các lỗi xử lý sai. Chú ý đặc biệt đến tính an toàn của bộ nhớ và tránh những cạm bẫy như tràn số nguyên.
Đánh giá mật mã đã bao quát một loạt các nguyên hàm cốt lõi được Nym sử dụng, chẳng hạn như AES-128-CTR, BLAKE2b, ChaCha, Ed25519, và những nguyên hàm khác. Mục tiêu là đảm bảo thực hiện đúng các thuật toán này và xác minh khả năng chống lại các cuộc tấn công kênh bên, sử dụng sai tham số và lỗi trong quá trình tạo ngẫu nhiên.
Ngoài việc xem xét các thành phần riêng lẻ, cuộc kiểm toán cũng đã đánh giá các giao thức định nghĩa chức năng cốt lõi của Nym. Điều này bao gồm việc xem xét định dạng gói Sphinx và giao thức chữ ký mù ngưỡng Coconut để xác định bất kỳ điểm yếu nào có thể làm tổn hại đến quyền riêng tư hoặc tính bào mật. Cuộc đánh giá tập trung vào các rủi ro rò rỉ thông tin tiềm ẩn đe dọa đến sự ẩn danh của người dùng, cũng như các lỗ hổng như bỏ qua xác minh MAC, các cuộc tấn công nhóm nhỏ, và các sai sót trong các hoạt động mật mã hóa như phép toán BLS12-381 và zero-knowledge proof.
Tổng quan về các phát hiện
Chín lỗ hổng bảo mật đã được phát hiện trong quá trình kiểm toán. Không có cái nào được đánh giá là nghiêm trọng, hai lỗ hổng được đánh giá là mức độ cao, một mức độ trung bình, và sáu mức độ thấp. Ngoài ra, 17 quan sát đã được thực hiện, đưa ra các khuyến nghị để củng cố thêm mạng lưới Nym. Dưới đây là tổng quan về các bản sửa lỗi đã được thực hiện để giải quyết tất cả các lỗ hổng bảo mật được xác định.
S-SPHX-01: Thiếu xác thực khóa (Thấp)
Vấn đề được xác định trong nymtech/sphinx liên quan đến việc thiếu xác thực các khóa riêng và công khai đã được khắc phục bằng cách di chuyển sang thư viện x25519, vị trí mà về bản chất đã đảm bảo tính hợp lệ của khóa thông qua thiết kế của nó. Việc triển khai x25519 đảm bảo rằng các khóa riêng tư được kẹp đúng cách, có nghĩa là chúng tự động bị giới hạn trong một tập hợp con hợp lệ của các số vô hướng, loại bỏ nguy cơ sử dụng các khóa riêng tư không hợp lệ. Ngoài ra, mặc dù x25519 không xác thực rõ ràng các khóa công khai, triển khai thang Montgomery của nó vô tình ngăn chặn việc sử dụng một số điểm trên đường cong không hợp lệ. Điều này giảm thiểu rủi ro gặp phải các điểm tại vô cực hoặc các khóa công khai bị định dạng sai khác. Hơn nữa, quá trình trao đổi khóa đảm bảo rằng một bí mật chung all-zero có thể được phát hiện và từ chối nếu cần thiết. Bằng cách tận dụng x25519, chúng tôi đã cải thiện đáng kể xác thực khóa, giảm thiểu rủi ro sử dụng các khóa không hợp lệ hoặc có định dạng sai trong hệ thống. Điều này giải quyết hiệu quả những mối quan tâm đã được nêu ra trong đợt kiểm toán liên quan đến xác thực khóa.
S-COCO-01: Phân phối thiên lệch từ hash đến số vô hướng (Thấp)
Quá trình băm để suy ra một số vô hướng trong trường BLS12-381 trước đây liên quan đến việc ánh xạ đầu ra của hàm băm trực tiếp đến một phần tử trường vô hướng. Tuy nhiên, cách tiếp cận này đã đưa ra độ lệch do hoạt động giảm mô-đun (mod p), có thể dẫn đến phân phối không đồng đều khi đầu ra băm không hoàn toàn phù hợp với mô-đun nguyên tố của trường. Để giải quyết vấn đề này, chúng tôi đã thay thế hàm hash-to-scalar hiện có bằng hàm hash_to_field từ bls12_381 crate. Hàm này tuân theo thông số hash-to-field tiêu chuẩn, đảm bảo ánh xạ đồng đều và không thiên vị của đầu ra băm đến các phần tử trường. Ngoài ra, giao thức zk-Nym, thay thế giao thức Coconut, cũng dựa vào hàm này cho các hoạt động băm của nó, đảm bảo tính nhất quán và chính xác trong các phép tính mật mã.
S-COCO-02: quyền truy cập tệp khóa keygen-cli (Thấp)
Các kiểm toán viên đã lưu ý rằng các tệp khóa keygen-cli có quyền mặc định, nhưng chúng nên có quyền hạn chế hơn để đảm bảo an toàn hơn. Vấn đề này không yêu cầu bất kỳ thay đổi nào, vì keygen-cli chỉ được sử dụng trong những giai đoạn đầu triển khai Coconut của chúng tôi. Nó không còn là một phần của kho Nym chính và không được sử dụng tích cực. Vì công cụ này đã lỗi thời nên không cần thực hiện thêm hành động nào liên quan đến quyền tệp của nó.
S-CRYP-01: Khả năng tái sử dụng mã hóa luồng IV (Cao)
Sự cố liên quan đến một hàm mã hóa dữ liệu bằng vectơ khởi tạo (IV). Nếu không cung cấp IV, hàm sẽ mặc định sử dụng zero IV, điều này có thể dẫn đến việc tái sử dụng IV. Vấn đề này đã được giải quyết bằng cách tích hợp giao thức AES-GCM-SIV trong giai đoạn đăng ký. Để ngăn chặn các cuộc tấn công hạ cấp, chúng tôi đã loại bỏ tùy chọn sử dụng khóa AES-128-CTR cũ để giao tiếp giữa máy khách và cổng. Miễn là cả khách hàng và cổng đều được cập nhật, chúng sẽ luôn tạo ra một IV ngẫu nhiên, khác không.
S-PROT-01: Khả năng chi tiêu hai lần thông tin xác thực (Cao)
Các kiểm toán viên nhận thấy rằng phiên bản Coconut được đánh giá thiếu cơ chế phát hiện chi tiêu hai lần, điều này có thể cho phép nhiều cổng xác thực thông tin xác thực không chính xác là chưa sử dụng cùng một lúc. Tuy nhiên, hợp đồng băng thông Coconut sau đó đã được cập nhật để theo dõi việc sử dụng thông tin xác thực bằng cách lưu trữ trạng thái on chain, giải quyết vấn đề này. Ngoài ra, Coconut đã được thay thế bởi giao thức zk-nyms, trong đó bao gồm tính năng phát hiện chi tiêu hai lần được tích hợp sẵn.
S-NYM-01: Các phụ thuộc có lỗ hổng bảo mật đã biết (Trung bình)
Các kiểm toán viên đã xác định rằng một số thành phần trong dự án Nym đang xây dựng trên các phiên bản cũ hơn của các phụ thuộc có lỗ hổng bảo mật đã biết. Ví dụ, kho lưu trữ Sphinx đã sử dụng phiên bản generic-arraycrate không an toàn, kho lưu trữ cốt lõi của Nym dựa vào một tokio, đã lỗi thời và máy khách Nym có một số crate có các vấn đề bảo mật đã biết, một số trong đó có vẻ như có thể khai thác được trong ngữ cảnh của Nym. Theo khuyến nghị của các kiểm toán viên, chúng tôi thường xuyên cập nhật các phụ thuộc. Hiện chúng tôi đang chủ động quản lý các phụ thuộc của mình thông qua Dependabot, liên tục giám sát và tự động phát hiện các gói lỗi thời hoặc dễ bị tấn công trong kho lưu trữ của mình. Xem các sửa lỗi Dependabot được áp dụng liên tục trong kho lưu trữ của chúng tôi.
S-NYM-02: Lỗi giải mã không được xử lý (Thấp)
Sự cố được xác định trong mã xảy ra trong hàm recover_identifier ở nym/common/nymsphinx/acknowledgments/identifier.rs, trong đó các lỗi giải mã, chẳng hạn như tham số không hợp lệ, không được xử lý đúng cách. Điều này có thể dẫn đến trạng thái hỗn loạn hoặc các trạng thái không an toàn khác. Một vấn đề tương tự tồn tại trong hàm recover_plaintext trong nym/common/nymsphinx/src/receiver.rs. Việc không quản lý được các lỗi giải mã có khả năng khiến hệ thống rơi vào trạng thái không ổn định hoặc không an toàn. Sau khi xem xét cẩn thận các hàm, chúng tôi kết luận rằng ví dụ đầu tiên được cung cấp, trong recover_identifier, không phải là một vấn đề. Không thể cung cấp tham số không chính xác, vì mọi thứ đều được tham số hóa với AckEncryptionAlgorithm (iên kết), nghĩa là bất kỳ giá trị không hợp lệ nào sẽ bị phát hiện tại thời điểm biên dịch.
Trường hợp thứ hai mà họ đề cập, recover_plaintext, không còn tồn tại nữa. Tuy nhiên, mã thay thế nó, recover_plaintext_from_regular_packet, có một trường hợp lỗi lý thuyết có thể xảy ra nếu chúng ta thay đổi một số tham số thành các giá trị bất thường. Chúng tôi đã giải quyết vấn đề này bằng cách thêm xử lý lỗi hợp lý để đảm bảo rằng hệ thống vẫn ổn định, ngay cả trong các trường hợp ngoại lệ.
S-NYM-03: Tạo ID đoạn hỗn loạn (Thấp)
Đoạn mã được sử dụng để tạo ID đoạn mới sẽ chọn ngẫu nhiên một giá trị i32 và lấy giá trị tuyệt đối của nó. Tuy nhiên, cách tiếp cận này có thể dẫn đến tình trạng hỗn loạn trong các trường hợp giá trị được chọn ngẫu nhiên là i32::MIN, vì giá trị tuyệt đối của nó không thể được biểu diễn trong các giới hạn của i32. Điều này dẫn đến lỗi 'cố gắng phủ định với lỗi tràn' do những hạn chế của mã hóa 2 phần bù.
Chúng tôi đồng ý rằng vấn đề này được xếp loại mức độ nghiêm trọng quá thấp, vì khả năng gặp phải là khoảng 1 trong 4 tỷ. Tuy nhiên, chúng tôi đã giải quyết vấn đề bằng cách triển khai sửa lỗi được khuyến nghị bởi kiểm toán viên để ngăn chặn tình trạng hỗn loạn tiềm ẩn và sự cố bất ngờ, đặc biệt khi hàng triệu người dùng tạo ra hàng ngàn ID phân đoạn.
S-NYM-04: Mnemonic chưa được xóa về 0 (Thấp)
Vấn đề đã xác định cho thấy rằng cụm từ ghi nhớ BIP39 được sử dụng để kết nối dịch vụ nymd đã không được xóa sau khi sử dụng, dẫn đến việc có nhiều bản sao của cụm từ ghi nhớ vẫn tồn tại trong bộ nhớ. Điều này làm tăng nguy cơ bị lộ, vì cụm từ ghi nhớ dễ nhận dạng trong bộ nhớ hơn so với các khóa mật mã thô. Để giải quyết vấn đề này, chúng tôi đã thực hiện một số biện pháp giảm thiểu. Trong các thành phần Rust, chúng tôi đã tích hợp gói zeroize để đảm bảo rằng bất kỳ bộ nhớ nào chứa cụm từ ghi nhớ đều được xóa một cách an toàn ngay khi không còn nằm trong phạm vi. Vì JavaScript là ngôn ngữ có bộ thu gom rác và không cung cấp quyền kiểm soát trực tiếp đối với việc xử lý bộ nhớ, nên chúng tôi đã áp dụng một cách tiếp cận khác để giảm thiểu khả năng bị lộ trong thời gian chạy JavaScript. Cụ thể, chúng tôi đã sửa đổi hệ thống để thời gian chạy JavaScript kết thúc sau khi cụm từ ghi nhớ được chuyển đến lớp Rust. Điều này đảm bảo rằng tất cả các trường hợp của cụm từ ghi nhớ trong bộ nhớ JavaScript đều được xóa khi thời gian chạy tắt. Cụm từ ghi nhớ được chuyển sang Rust càng sớm càng tốt, giảm thiểu nguy cơ bị lộ trong JavaScript. Khi đã ở trong Rust, zeroize đảm bảo rằng tất cả các phiên bản của cụm từ ghi nhớ được xóa an toàn khi chúng không còn cần thiết. Với những thay đổi này, chúng tôi đã giảm thiểu đáng kể sự hiện diện của cụm từ ghi nhớ trong bộ nhớ, giảm nguy cơ bị lộ và đảm bảo rằng dữ liệu nhạy cảm được quản lý và xóa một cách an toàn.
Tóm lại
Chúng tôi muốn cảm ơn JP Aumasson vì chuyên môn và sự tận tâm của ông trong suốt quá trình kiểm toán. Chúng tôi cũng đánh giá cao sự hợp tác và tính chuyên nghiệp được thể hiện trong cả giai đoạn lập kế hoạch và thực hiện kiểm toán. Cam kết của chúng tôi đối với bảo mật vẫn là ưu tiên hàng đầu, và chúng tôi mong muốn tiếp tục hợp tác với các chuyên gia để duy trì các tiêu chuẩn cao nhất cho hệ sinh thái.