zkLogin là một Sui primitive, là cơ chế xác thực đầu tiên trong Web3—một cơ chế xác thực thực sự không cần tin cậy, an toàn và thân thiện với người dùng. Với zkLogin, các nhà phát triển có thể tạo ra trải nghiệm tích hợp liền mạch cho phép người dùng đăng nhập bằng thông tin xác thực Web2 quen thuộc, chẳng hạn như Google hoặc Facebook, để tạo và quản lý địa chỉ Sui một cách dễ dàng.
Khi ký giao dịch cho một địa chỉ bằng zkLogin, phải cung cấp một giá trị salt duy nhất để biểu thị thông tin xác thực OAuth hoặc Web2 liên kết với địa chỉ Sui. Giá trị salt này rất quan trọng để đảm bảo rằng các địa chỉ trên chuỗi không thể được truy ngược lại thông tin xác thực Web2 của người dùng. Máy chủ salt chịu trách nhiệm tạo, lưu trữ và cung cấp salt theo cách có thể dự đoán được bất cứ khi nào giao dịch được khởi tạo. Các nhà phát triển có một số tùy chọn để tạo và lưu trữ giá trị salt này, cho dù ở phía máy khách hay phía máy chủ.
Tại Mysten Labs, chúng tôi vận hành một máy chủ salt sử dụng một hạt giống chính kết hợp với JSON Web Token (JWT) của người dùng để tạo ra giá trị salt có thể tái tạo cho mỗi người dùng trên mỗi ứng dụng. Quy trình này bao gồm việc xác minh JWT với nhà cung cấp. Do tính nhạy cảm của hạt giống chính, việc lưu trữ một máy chủ salt trong môi trường điện toán thông thường sẽ là vô trách nhiệm. Việc bảo vệ hạt giống chính là rất quan trọng để duy trì sự tách biệt giữa các danh tính Web2 với các địa chỉ Sui.
Để bảo vệ danh tính người dùng của khách hàng và đối tác, máy chủ salt của chúng tôi hoạt động trong môi trường điện toán an toàn, đảm bảo bảo vệ khỏi việc vô tình hoặc cố ý tiếp xúc. Chúng tôi sẽ phác thảo cách tiếp cận của mình tại đây để những người khác có nhu cầu triển khai giải pháp tương tự tham khảo.
zkLogin và máy chủ salt
Như đã thảo luận ở trên, máy chủ salt đóng vai trò quan trọng trong việc duy trì quyền riêng tư và bảo mật cho thông tin xác thực Web2 của người dùng khi sử dụng zkLogin. Sử dụng một hạt giống chính bí mật và JWT của người dùng, máy chủ salt tạo ra một giá trị salt duy nhất cho người dùng đó đối với ứng dụng đó, nhưng ẩn kết nối khỏi danh tính của người dùng với hoạt động Sui của họ, đảm bảo quyền riêng tư về mặt mật mã. Giá trị salt là bắt buộc trước khi tạo bằng chứng zkLogin và do đó trước khi phát hành giao dịch trên chuỗi.
Khi ai đó sử dụng ứng dụng được hỗ trợ bởi máy chủ salt Mysten Labs, họ nhập thông tin xác thực Web2 của mình và ứng dụng yêu cầu JWT từ nhà cung cấp xác thực. Sau đó, ứng dụng sẽ gửi JWT đến máy chủ salt để lấy giá trị salt. Mỗi lần địa chỉ Sui được lấy từ danh tính của người dùng, bao gồm cả việc tính toán bằng chứng gốc để lấy chữ ký zkLogin của người dùng, salt được sử dụng để đảm bảo rằng địa chỉ của người dùng luôn có thể được tính toán một cách xác định từ mã thông báo của họ mà không tiết lộ ràng buộc giữa hai bên.
Lặn vào máy chủ muối
Có ba mục tiêu chính trong việc bảo vệ hạt giống chính được sử dụng bởi máy chủ salt. Nó phải được tạo ra một cách an toàn, được bảo vệ khỏi việc tiếp xúc với bất kỳ người nào trong Mysten Labs và được bảo vệ khỏi việc tiếp xúc bên ngoài với internet thông qua dịch vụ hoặc thông qua các cuộc tấn công kênh phụ trong nhà cung cấp đám mây của chúng tôi. Nếu không có người hoặc hệ thống nào nhìn thấy khóa ngoại trừ máy chủ salt, chúng tôi có thể tin tưởng vào tính bảo mật của nó và do đó tính hợp lệ của ánh xạ băm từ JWT đến các địa chỉ trên chuỗi.
Hệ thống máy tính đáng tin cậy
Có nhiều tùy chọn khác nhau để lưu trữ cơ sở hạ tầng tính toán đáng tin cậy. Trong một thế giới lý tưởng, tất cả các phép tính băm sẽ diễn ra trong một mô-đun phần cứng đáng tin cậy như Mô-đun bảo mật phần cứng (HSM) hoặc Mô-đun nền tảng đáng tin cậy (TPM).
Tuy nhiên, việc liên kết hạt giống chính với một phần cứng duy nhất có nghĩa là phần cứng đó trở thành một điểm lỗi duy nhất trong hệ thống – mất quyền truy cập vào HSM hoặc TPM sẽ có nghĩa là mất vĩnh viễn hạt giống chính. Rủi ro mất hạt giống trong những trường hợp này là quá cao đối với máy chủ salt của chúng tôi, vì vậy chúng tôi cần thứ gì đó đánh đổi tính bảo mật tuyệt đối của phần cứng đáng tin cậy để có thêm tính linh hoạt. Giải pháp chúng tôi đưa ra là sử dụng môi trường tính toán đáng tin cậy, nơi chúng tôi có thể chạy máy chủ trong môi trường bị cô lập với chứng thực container và chỉ cho phép truy cập qua TCP trực tiếp đến các điểm cuối của dịch vụ.
Cả ba nhà cung cấp đám mây lớn đều cung cấp các giải pháp điện toán đáng tin cậy; Azure Confidential Computing, GCP Confidential VM và AWS Nitro Enclaves đều là các môi trường cho phép điện toán biệt lập. Chúng tôi đã chọn sử dụng Nitro Enclaves trên EC2. Với Nitro Enclaves, chúng tôi có thể mang hình ảnh container và công cụ xây dựng hiện có của riêng mình và thêm lớp Enclave lên trên.
Tạo giống
Vì hạt giống chính là vĩnh viễn và không thể xoay vòng, nên việc tạo chỉ diễn ra một lần. Hạt giống có thể là bất kỳ chuỗi byte nào vì tính ngẫu nhiên là tất cả những gì quan trọng. Tuy nhiên, nếu, ví dụ, chính tôi tạo ra hạt giống chính thì nó sẽ dễ bị tấn công. Ngay cả khi tôi không tiết lộ hạt giống chính cho bất kỳ người nào khác, tôi vẫn là lỗ hổng cơ bản đối với chức năng của triển khai zkLogin của Mysten Labs và bất kỳ ứng dụng nào được xây dựng trên đó vì tôi biết về hạt giống chính. Thay vào đó, chúng tôi thích tạo khóa theo cách tự động.
Việc tạo hạt giống trên một máy không có khoảng cách không khí sẽ tạo ra thêm các lỗ hổng vì nó bị lộ ra với phần còn lại của hệ thống và có thể là cả internet. Nitro Enclaves được sử dụng để tạo ra một môi trường biệt lập, nơi chúng tôi có thể tiến hành tạo khóa cho khóa chính của zkLogin một cách an toàn.
Bên trong enclave, chúng tôi tạo ra hạt giống chính từ sự ngẫu nhiên. Chúng tôi mã hóa hạt giống bằng khóa mã hóa và lưu trữ khóa trong kho lưu trữ bí mật. Kho lưu trữ bí mật được cấu hình sao cho chỉ enclave mới có thể lấy được bí mật và ngay cả quản trị viên cũng không thể truy cập vào bí mật dạng văn bản thuần túy. Chúng tôi cũng chia khóa và lưu trữ các phân đoạn như mô tả trong phần “Khôi phục hạt giống” bên dưới.
Tập lệnh shell chạy bên trong Nitro Enclave tương đối đơn giản.
./generate-random-seed > seed.json secrets-store đặt --tên SEED --tệp seed.json
Sử dụng hạt giống
Bí mật hạt giống chính có chính sách chỉ cho phép danh tính enclave truy cập vào nó, nghĩa là ngay cả quản trị viên cũng không thể đọc được nó một cách tình cờ. Chúng tôi cũng duy trì một tài khoản nhà cung cấp đám mây riêng cho các bí mật máy chủ salt để tách quyền truy cập của quản trị viên khỏi các dự án Mysten Labs khác và giới hạn số lượng người có quyền truy cập.
Khi khóa được máy chủ salt trong Nitro Enclave đọc, nó được lưu trong bộ nhớ dưới dạng văn bản thuần túy. Chúng tôi dựa vào các biện pháp bảo vệ của môi trường bị cô lập để ngăn chặn truy cập trên cùng một máy chủ và do đó sẽ không có lợi ích gì khi mã hóa hạt giống ở trạng thái nghỉ và giải mã nó cho mỗi yêu cầu. Hạt giống được sử dụng cho mọi yêu cầu, do đó lưu lượng truy cập thông thường sẽ làm suy yếu khả năng bảo vệ mà mã hóa ở trạng thái nghỉ cung cấp.
Để dịch vụ vẫn nhận được lưu lượng truy cập, chúng tôi phải cho phép một tập hợp con hẹp của quyền truy cập mạng thông qua môi trường enclave máy chủ salt. Chúng tôi sử dụng proxy vsock để giới hạn lưu lượng truy cập vào qua cổng ứng dụng đơn lẻ và lưu lượng truy cập ra các nhà cung cấp OAuth để xác minh JWT và đến một địa chỉ cổng để xuất bản khả năng quan sát. Điều này cho phép máy chủ salt thực hiện công việc xác minh và tạo salt và cho phép chúng tôi theo dõi dịch vụ trong khi không cho phép tất cả các quyền truy cập mạng khác.
Sau đây là một số mã mẫu minh họa cách chúng tôi cung cấp enclave bằng Pulumi và khởi tạo enclave.
def get_enclave_instances(args: EnclaveInstanceArgs) -> List[aws.ec2.Instance]: instances = [] cho chỉ mục trong phạm vi(args.instance_count): name = f"{pulumi.get_stack()}-salt-server-ec2-{index}" instance = aws.ec2.Instance( name, tags={ "Name": name, }, instance_type="m5.xlarge", subnet_id=args.network.subnets[0].id, vpc_security_group_ids=[ args.security_group.id ], ami="ami-mysten123", user_data=get_startup_script( args.role_name, args.role_arn, args.image_name, index ), user_data_replace_on_change=True, iam_instance_profile=args.instance_profile.name, enclave_options=aws.ec2.InstanceEnclaveOptionsArgs(enabled=True), opts=ResourceOptions(depends_on=[args.ecr_image]), ) pulumi.export(f"publicIp-{index}", instance.public_ip) pulumi.export(f"publicHostName-{index}", instance.public_dns) instances.append(instance) return instances def get_startup_script( role_name: str, role_arn: Output[str], image_name: Output[str], index: int ): aws_config = pulumi.Config("aws") return Output.all(role_arn, image_name).apply( lambda args: f"""#!/bin/bash # in từng lệnh set -o xtrace yum install awscli aws-nitro-enclaves-cli-devel aws-nitro-enclaves-cli docker nano socat -y nitro-cli kết thúc-enclave --tất cả giết tất cả socat nitro-cli xây dựng-enclave --docker-uri '{args[1]}' --tệp đầu ra salt.eif EIF_SIZE=$(du -b --block-size=1M "salt.eif" | cắt -f 1) ENCLAVE_MEMORY_SIZE=$(((($EIF_SIZE * 4 + 1024 - 1)/1024) * 1024)) cat >> /etc/nitro_enclaves/vsock-proxy.yaml <<EOF - {{địa chỉ: accounts.google.com, cổng: 443}} - {{địa chỉ: secretsmanager.us-west-2.amazonaws.com, cổng: 443}} - {{địa chỉ: kms.us-west-2.amazonaws.com, cổng: 443}} EOF # nhà cung cấp vsock-proxy 8001 accounts.google.com 443 --config /etc/nitro_enclaves/vsock-proxy.yaml & # kms vsock-proxy 8101 secretsmanager.us-west-2.amazonaws.com 443 --config /etc/nitro_enclaves/vsock-proxy.yaml & vsock-proxy 8102 kms.us-west-2.amazonaws.com 443 --config /etc/nitro_enclaves/vsock-proxy.yaml & nitro-cli run-enclave --cpu-count 2 --memory $ENCLAVE_MEMORY_SIZE --eif-path muối.eif ENCLAVE_ID=$(nitro-cli describe-enclaves | jq -r ".[0].EnclaveID") ENCLAVE_CID=$(nitro-cli describe-enclaves | jq -r ".[0].EnclaveCID") sleep 5 unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN # Gửi thông tin xác thực từ phiên bản ec2 đến enclave TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \ && curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/{role_name} > assume-role.json # Phân tích cú pháp đầu ra JSON và đặt các biến môi trường cat assume-role.json | socat - VSOCK-CONNECT:$ENCLAVE_CID:7777 # Lệnh này được chạy sau khi enclave hoạt động để lưu lượng truy cập từ cổng 8888 -> có thể chuyển hướng đến vsock # Lắng nghe tất cả các Cổng 8888 để chuyển tiếp từ bên ngoài vào ENCLAVE CID->Port socat TCP4-LISTEN:8888,reuseaddr,fork VSOCK-CONNECT:$ENCLAVE_CID:3000 & """ )
Mã Python Pulumi này tạo một phiên bản EC2 cho mỗi bản sao dịch vụ của chúng tôi, đính kèm nó vào mạng chúng tôi thiết lập và kích hoạt Nitro Enclaves cho nó. User_data chúng tôi chèn sẽ xây dựng enclave, thiết lập proxy vsock và khởi động enclave.
Chúng tôi nỗ lực hết sức để bảo vệ thành công việc sử dụng hạt giống chính, nhưng vẫn có rủi ro khi để lại bí mật của chúng tôi cho một nhà cung cấp đám mây trong một dịch vụ duy nhất. Một kế hoạch khôi phục hạt giống được triển khai đảm bảo rằng chúng tôi có nhiều cách để khôi phục hạt giống chính trong trường hợp thảm họa.
Phục hồi hạt giống
Một phần trong quy trình tạo hạt giống ban đầu của chúng tôi bao gồm việc chia hạt giống thành nhiều mảnh được mã hóa để cho phép nhóm người tham gia thiết kế hệ thống máy chủ salt khôi phục. Chúng tôi đã sử dụng tiện ích Horcrux của Unit 410 để thực hiện việc này.
Horcrux sử dụng Shamir’s Secret Sharing để tạo ra nhiều phần được mã hóa của hạt giống và cho phép giải mã với một tập hợp con được chỉ định của các mảnh vỡ. Mỗi mảnh vỡ được mã hóa bằng một khóa phần cứng do mỗi cá nhân trong nhóm sở hữu, tăng thêm mức độ bảo mật phân tán theo địa lý.
Các mảnh được mã hóa được lưu trữ dự phòng trong nhiều máy chủ từ xa. Vì chúng được mã hóa, chúng tôi lưu trữ chúng cùng nhau và thêm dự phòng để tránh một điểm lỗi duy nhất. Trong trường hợp khóa bị mất khỏi máy chủ, việc khôi phục được thực hiện nhanh chóng và tính bảo mật được duy trì thông qua Horcrux.
Sự đánh đổi
Hệ thống sản xuất máy chủ salt của chúng tôi trông khá khác biệt so với nhiều dịch vụ khác mà chúng tôi chạy. Các hạn chế bảo mật mà chúng tôi đặt ra cho dịch vụ bằng cách chạy nó trong Nitro Enclaves khiến việc vận hành máy chủ salt trở thành thách thức riêng.
Mỗi proxy mạng bổ sung mà chúng tôi thực hiện cho enclave là một bề mặt tiềm năng bổ sung để xâm nhập hạt giống chính. Miễn là chúng tôi tiếp tục tuân theo các thông lệ tương tự cho mỗi nhà cung cấp OAuth mới, chúng tôi mong đợi bề mặt tấn công sẽ vẫn như vậy. Chúng tôi không dự đoán cần thêm lưu lượng mạng vào và ra khỏi chính enclave.
Máy chủ salt phải luôn đơn giản; việc giao tiếp với các dịch vụ Mysten Labs khác và tích hợp với công cụ mới theo thời gian có thể sẽ yêu cầu cân nhắc cụ thể cho các đánh đổi bảo mật liên quan. Chúng tôi sẽ duy trì hệ thống trong một môi trường bị hạn chế nghiêm ngặt trong nỗ lực duy trì phần cuối cùng là phần quan trọng của hệ thống đối với các ứng dụng được xây dựng trên triển khai zkLogin của chúng tôi.
An ninh là trên hết
Tại Mysten Labs, chúng tôi tập trung vào việc giải quyết các vấn đề cơ bản và zkLogin là bằng chứng cho thấy sự tập trung đó trong hành động. Khi chúng tôi tiếp tục xây dựng các cấu trúc mới khác tương tự và trên zkLogin, chúng tôi sẽ giữ cho hệ thống của mình đạt tiêu chuẩn bảo mật cao nhất theo những cách có thể chứng minh được bằng mật mã. Việc triển khai của chúng tôi, kết hợp với sức mạnh của Nitro Enclaves và Horcrux, thể hiện cam kết đối với các tiêu chuẩn đó và mang lại lợi ích của Web3 cho mọi người.