zkLogin adalah primitif Sui yang merupakan yang pertama dalam jenisnya di Web3—mekanisme autentikasi yang benar-benar aman, mudah digunakan, dan tidak memerlukan kepercayaan. Dengan zkLogin, pengembang dapat menciptakan pengalaman onboarding yang lancar yang memungkinkan pengguna untuk masuk dengan kredensial Web2 yang sudah dikenal, seperti Google atau Facebook, untuk membuat dan mengelola alamat Sui dengan mudah.
Saat menandatangani transaksi untuk suatu alamat menggunakan zkLogin, nilai salt unik harus diberikan untuk mewakili kredensial OAuth, atau Web2, yang terkait dengan alamat Sui. Nilai salt ini penting untuk memastikan bahwa alamat onchain tidak dapat dilacak kembali ke kredensial Web2 pengguna. Server salt bertanggung jawab untuk menghasilkan, menyimpan, dan memasok salt secara terprediksi setiap kali transaksi dimulai. Pengembang memiliki beberapa opsi untuk menghasilkan dan menyimpan nilai salt ini, baik di sisi klien maupun sisi server.
Di Mysten Labs, kami mengoperasikan server salt yang menggunakan master seed yang dikombinasikan dengan JSON Web Token (JWT) milik pengguna untuk memperoleh nilai salt yang dapat direproduksi per pengguna per aplikasi. Proses ini mencakup verifikasi JWT terhadap penyedia. Mengingat sensitivitas master seed, menghosting server salt di lingkungan komputasi yang umum akan menjadi tindakan yang tidak bertanggung jawab. Melindungi master seed sangat penting untuk menjaga pemisahan identitas Web2 dari alamat Sui.
Untuk melindungi identitas pengguna pelanggan dan mitra kami, server salt kami beroperasi dalam lingkungan komputasi yang aman, yang menjamin perlindungan dari paparan yang tidak disengaja atau berbahaya. Kami akan menguraikan pendekatan kami di sini sebagai referensi bagi orang lain yang ingin menerapkan solusi serupa.
zkLogin dan server garam
Seperti yang dibahas di atas, server salt memainkan peran penting dalam menjaga privasi dan keamanan kredensial Web2 pengguna saat menggunakan zkLogin. Dengan menggunakan master seed rahasia dan JWT pengguna, server salt menghasilkan nilai salt yang unik bagi pengguna tersebut untuk aplikasi tersebut, tetapi menyembunyikan koneksi dari identitas pengguna ke aktivitas Sui mereka, yang secara kriptografis memastikan privasi. Nilai salt diperlukan sebelum menghasilkan bukti zkLogin dan oleh karena itu sebelum menerbitkan transaksi onchain.
Ketika seseorang menggunakan aplikasi yang didukung oleh server salt Mysten Labs, mereka memasukkan kredensial Web2 mereka dan aplikasi tersebut meminta JWT dari penyedia autentikasi. Aplikasi tersebut kemudian mengirimkan JWT ke server salt untuk mendapatkan nilai salt. Setiap kali alamat Sui diambil dari identitas pengguna, termasuk menghitung bukti asli untuk mendapatkan tanda tangan zkLogin pengguna, salt digunakan untuk memastikan bahwa alamat pengguna selalu dapat dihitung secara deterministik dari token mereka tanpa mengungkapkan ikatan antara keduanya.
Menyelami server garam
Ada tiga tujuan utama dalam melindungi master seed yang digunakan oleh server salt. Master seed harus dibuat dengan aman, dilindungi dari paparan siapa pun secara internal di Mysten Labs, dan dilindungi dari paparan eksternal ke internet melalui layanan atau melalui serangan side channel di penyedia cloud kami. Jika tidak ada orang atau sistem yang melihat kunci tersebut kecuali server salt, kami dapat yakin akan kerahasiaannya dan dengan demikian validitas pemetaan hash dari JWT ke alamat onchain.
Sistem komputasi tepercaya
Terdapat berbagai pilihan untuk menghosting infrastruktur komputasi tepercaya. Dalam dunia yang ideal, semua komputasi hash akan terjadi dalam modul perangkat keras tepercaya seperti Modul Keamanan Perangkat Keras (HSM) atau Modul Platform Tepercaya (TPM).
Namun, mengikat master seed ke satu perangkat keras berarti bahwa perangkat keras tersebut menjadi satu titik kegagalan dalam sistem – kehilangan akses ke HSM atau TPM akan berarti kehilangan master seed secara permanen. Risiko kehilangan seed dalam keadaan ini terlalu tinggi untuk server salt kami, jadi kami memerlukan sesuatu yang mengorbankan keamanan absolut perangkat keras tepercaya demi fleksibilitas yang lebih baik. Solusi yang kami pilih adalah menggunakan lingkungan komputasi tepercaya, tempat kami dapat menjalankan server dalam lingkungan terisolasi dengan pengesahan kontainer dan mengizinkan akses hanya melalui TCP secara langsung ke titik akhir layanan.
Ketiga penyedia cloud utama menawarkan solusi komputasi tepercaya; Azure Confidential Computing, GCP Confidential VMs, dan AWS Nitro Enclaves semuanya merupakan lingkungan yang memungkinkan komputasi terisolasi. Kami memilih untuk menggunakan Nitro Enclaves pada EC2. Dengan Nitro Enclaves, kami dapat menggunakan citra kontainer dan perkakas build yang ada serta menambahkan lapisan Enclave di atasnya.
Generasi benih
Karena master seed bersifat permanen dan tidak dapat diputar, pembuatan hanya terjadi satu kali. Seed dapat berupa urutan byte apa pun karena yang penting adalah keacakan. Namun, jika, misalnya, saya sendiri yang membuat master seed, maka seed tersebut akan rentan. Bahkan jika saya tidak mengungkapkan master seed kepada orang lain, saya merupakan kerentanan mendasar terhadap fungsionalitas implementasi Mysten Labs zkLogin dan aplikasi apa pun yang dibangun di atasnya karena saya mengetahui master seed tersebut. Sebaliknya, kami lebih suka membuat kunci secara otomatis.
Pembuatan benih pada mesin yang tidak memiliki celah udara akan menimbulkan kerentanan tambahan karena benih tersebut terpapar ke seluruh sistem dan mungkin internet. Nitro Enclaves digunakan untuk menghasilkan lingkungan terisolasi tempat kami dapat melakukan pembuatan kunci untuk kunci induk zkLogin dengan aman.
Di dalam enclave, kami menghasilkan master seed dari keacakan. Kami mengenkripsi seed dengan kunci enkripsi dan menyimpan kunci tersebut di penyimpanan rahasia. Penyimpanan rahasia dikonfigurasikan sehingga hanya enclave yang dapat memperoleh rahasia, dan bahkan administrator tidak memiliki akses ke rahasia teks biasa. Kami juga membagi kunci dan menyimpan pecahan seperti yang dijelaskan di bagian “Pemulihan Seed” di bawah ini.
Skrip shell yang berjalan di dalam Nitro Enclave relatif sederhana.
./generate-random-seed > seed.json rahasia-simpan taruh --nama SEED --file seed.json
Penggunaan benih
Rahasia master seed memiliki kebijakan yang hanya mengizinkan identitas enclave untuk mengaksesnya, yang berarti bahwa bahkan seorang administrator tidak dapat membacanya secara tidak sengaja. Kami juga memelihara akun penyedia cloud terpisah untuk rahasia server salt guna memisahkan akses administrator dari proyek Mysten Labs lainnya dan membatasi jumlah orang yang memiliki akses.
Ketika kunci dibaca oleh server salt di Nitro Enclave, kunci tersebut disimpan dalam memori dalam bentuk teks biasa. Kami mengandalkan perlindungan lingkungan yang terisolasi untuk mencegah akses pada host yang sama dan oleh karena itu tidak akan ada manfaat dalam mengenkripsi seed saat tidak digunakan dan mendekripsinya untuk setiap permintaan. Seed digunakan pada setiap permintaan, jadi lalu lintas reguler akan merusak perlindungan yang ditawarkan enkripsi saat tidak digunakan.
Agar layanan tetap menerima lalu lintas, kami harus mengizinkan sebagian kecil akses jaringan melalui lingkungan enklave server salt. Kami menggunakan proksi vsock untuk membatasi lalu lintas masuk melalui port aplikasi tunggal dan lalu lintas keluar ke penyedia OAuth untuk verifikasi JWT dan ke alamat gateway untuk penerbitan observabilitas. Hal ini memungkinkan server salt melakukan tugasnya dalam verifikasi dan pembuatan salt serta memungkinkan kami memantau layanan sambil melarang semua akses jaringan lainnya.
Berikut adalah beberapa contoh kode yang menunjukkan cara kami menyediakan enclave menggunakan Pulumi dan menginisialisasi enclave.
def get_enclave_instances(args: EnclaveInstanceArgs) -> List[aws.ec2.Instance]: instances = [] untuk indeks dalam rentang(args.instance_count): nama = f"{pulumi.get_stack()}-salt-server-ec2-{index}" instance = aws.ec2.Instance( nama, tag={ "Nama": nama, }, instance_type="m5.xlarge", subnet_id=args.network.subnets[0].id, vpc_security_group_ids=[ args.security_group.id ], ami="ami-mysten123", data_pengguna=get_startup_script( args.role_name, args.role_arn, args.image_name, index ), data_pengguna_ganti_saat_berubah=Benar, 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 # cetak setiap perintah set -o xtrace yum install Bahasa Indonesia: awscli aws-nitro-enclaves-cli-devel aws-nitro-enclaves-cli docker nano socat -y nitro-cli terminate-enclave --all killall socat nitro-cli build-enclave --docker-uri '{args[1]}' --file-keluaran salt.eif UKURAN EIF=$(du -b --ukuran-blok=1M "salt.eif" | Bahasa Indonesia: potong -f 1) UKURAN_MEMORY_ENCLAVE=$(((($EIF_SIZE * 4 + 1024 - 1)/1024) * 1024)) cat >> /etc/nitro_enclaves/vsock-proxy.yaml <<EOF - {{alamat: accounts.google.com, porta: 443}} - {{alamat: secretsmanager.us-west-2.amazonaws.com, porta: 443}} - {{alamat: kms.us-west-2.amazonaws.com, porta: 443}} EOF # penyedia 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 salt.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 # Mengirim kredensial dari instans ec2 ke 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} > assumption-role.json # Parsing output JSON dan tetapkan variabel lingkungan cat assumption-role.json | socat - VSOCK-CONNECT:$ENCLAVE_CID:7777 # Ini dijalankan setelah enclave aktif sehingga lalu lintas dari port 8888 -> dapat dialihkan ke vsock # Mendengarkan semua Port 8888 untuk meneruskan dari luar ke ENCLAVE CID->Port socat TCP4-LISTEN:8888,reuseaddr,fork VSOCK-CONNECT:$ENCLAVE_CID:3000 & """ )
Kode Python Pulumi ini membuat instans EC2 untuk setiap replika layanan kita, memasangnya ke jaringan yang kita siapkan, dan mengaktifkan Nitro Enclaves untuknya. User_data yang kita masukkan membangun enclave, menyiapkan proksi vsock, dan memulai enclave.
Kami berupaya keras untuk berhasil melindungi penggunaan master seed, tetapi tetap ada risiko jika meninggalkan rahasia kami dengan penyedia cloud dalam satu layanan. Rencana pemulihan seed yang ada memastikan bahwa kami memiliki beberapa cara untuk memulihkan master seed dalam skenario bencana.
Pemulihan benih
Bagian dari proses pembuatan benih awal kami melibatkan pemisahan benih menjadi beberapa pecahan terenkripsi untuk memungkinkan pemulihan oleh sekelompok orang yang terlibat dalam desain sistem server garam. Kami menggunakan utilitas Horcrux Unit 410 untuk menyelesaikannya.
Horcrux menggunakan Shamir's Secret Sharing untuk menghasilkan beberapa bagian terenkripsi dari benih dan memungkinkan dekripsi dengan subset pecahan tertentu. Setiap pecahan dienkripsi dengan kunci perangkat keras yang dimiliki oleh setiap individu dalam kelompok, yang menambahkan tingkat keamanan yang terdistribusi secara geografis.
Pecahan terenkripsi disimpan secara redundan di beberapa server jarak jauh. Karena dienkripsi, kami menyimpannya bersama-sama dan menambahkan redundansi untuk menghindari satu titik kegagalan. Dalam skenario di mana kunci hilang dari server, pemulihan dilakukan dengan cepat dan kerahasiaan dipertahankan melalui Horcrux.
Kompromi
Sistem produksi server salt kami terlihat sangat berbeda dari banyak layanan lain yang kami jalankan. Kendala keamanan yang kami terapkan pada layanan dengan menjalankannya di Nitro Enclaves membuat operasionalisasi server salt menjadi tantangan tersendiri.
Setiap penambahan proksi jaringan yang kami buat ke enclave merupakan permukaan potensial tambahan untuk eksfiltrasi master seed. Selama kami terus mengikuti praktik yang sama untuk setiap penyedia OAuth baru, kami perkirakan permukaan serangan akan tetap sama. Kami tidak mengantisipasi perlunya lebih banyak lalu lintas jaringan masuk dan keluar dari enclave itu sendiri.
Server salt harus tetap sederhana; komunikasi dengan layanan Mysten Labs lainnya dan integrasi dengan perkakas baru dari waktu ke waktu kemungkinan akan memerlukan pertimbangan khusus untuk kompromi keamanan yang terlibat. Kami akan mempertahankan sistem dalam lingkungan yang sangat terbatas dalam upaya mempertahankan apa yang pada akhirnya merupakan bagian penting dari sistem untuk aplikasi yang dibangun pada implementasi zkLogin kami.
Keamanan adalah yang utama
Di Mysten Labs, kami berfokus pada penyelesaian masalah mendasar dan zkLogin adalah bukti dari fokus tersebut dalam tindakan. Saat kami terus membangun konstruksi baru lainnya yang serupa dengan dan di atas zkLogin, kami akan menjaga sistem kami pada standar keamanan tertinggi dengan cara yang dapat dibuktikan secara kriptografi. Implementasi kami, dikombinasikan dengan kekuatan Nitro Enclaves dan Horcrux, menunjukkan komitmen terhadap standar tersebut dan menghadirkan manfaat Web3 bagi semua orang.