


Hello! Petang lain, dalam perjalanan pulang ke rumah, saya memutuskan untuk menyemak peti surat. Saya tidak maksudkan peti masuk e-mel saya, tetapi kotak sebenar sekolah lama di mana posmen meletakkan huruf fizikal. Dan yang sangat mengejutkan saya, saya menjumpai sampul surat di sana dengan sesuatu di dalamnya! Semasa membukanya, saya meluangkan beberapa saat berharap bahawa ia adalah surat tertangguh selama beberapa dekad daripada Hogwarts. Tetapi kemudian saya terpaksa turun semula ke Bumi, sebaik sahaja saya menyedari bahawa ia adalah surat "dewasa" yang membosankan daripada bank. Saya membaca sekilas teks dan menyedari bahawa bank "digital sahaja" saya untuk kanak-kanak hebat telah diperoleh oleh pemain terbesar di pasaran tempatan. Dan sebagai tanda permulaan baharu, mereka menambahkan ini pada sampul surat:
Bersama dengan arahan tentang cara menggunakannya.
Jika anda seperti saya, dan tidak pernah menjumpai sekeping inovasi teknologi sedemikian, izinkan saya berkongsi apa yang saya pelajari daripada surat itu: pemilik baharu memutuskan untuk menguatkuasakan dasar keselamatan daripada syarikat mereka, yang bermaksud bahawa semua pengguna akaun mulai sekarang akan mendayakan MFA (pujian untuk itu, btw). Dan peranti yang anda boleh lihat di atas menjana token sekali 6 digit panjang yang digunakan sebagai faktor kedua semasa log masuk ke akaun bank anda. Pada asasnya, cara yang sama seperti apl seperti Authy, Google Authenticator atau 2FAS berfungsi, tetapi dalam bentuk fizikal.
Jadi, saya mencubanya dan proses log masuk berjalan lancar: peranti menunjukkan kepada saya kod 6 digit, saya memasukkannya dalam apl perbankan saya, dan ini membuatkan saya masuk. Hooray! Tetapi kemudian sesuatu menarik perhatian saya: bagaimana perkara ini berfungsi? Tidak ada cara ia disambungkan ke internet entah bagaimana, tetapi ia berjaya menjana kod yang betul yang diterima oleh pelayan bank saya. Hm... Bolehkah ia mempunyai kad SIM atau sesuatu yang serupa di dalamnya? Tidak boleh!
Menyedari bahawa hidup saya tidak akan pernah sama, saya mula tertanya-tanya tentang aplikasi yang saya nyatakan di atas (Authy dan rakan-rakan)? Penyelidik dalaman saya telah disedarkan, jadi saya menukar telefon saya ke dalam mod kapal terbang dan, yang mengejutkan saya, menyedari bahawa ia berfungsi dengan baik di luar talian: mereka terus menjana kod yang diterima oleh pelayan aplikasi. Menarik!
Tidak pasti tentang anda, tetapi saya sentiasa mengambil mudah aliran token sekali sahaja dan tidak pernah benar-benar memikirkannya (terutamanya kerana hari ini jarang telefon saya tidak mempunyai internet melainkan Saya sedang melakukan beberapa pengembaraan luar), jadi itulah punca kejutan saya. Jika tidak, ia masuk akal dari sudut pandangan keselamatan untuk berfungsi dengan cara ini, kerana proses penjanaan adalah tempatan semata-mata, sangat selamat daripada pelakon luar. Tetapi bagaimana ia berfungsi?
Nah, teknologi moden seperti Google atau ChatGPT memudahkan untuk mencari jawapan dengan mudah. Tetapi masalah teknikal ini kelihatan menyeronokkan kepada saya, jadi memutuskan untuk mencubanya dan menyelesaikannya sendiri terlebih dahulu.
Keperluan
Mari kita mulakan dengan apa yang kita ada:
- peranti luar talian yang menjana kod 6 digit
- pelayan yang menerima kod ini, mengesahkannya dan memberi isyarat hijau jika ia betul
Bahagian pengesahan pelayan membayangkan bahawa pelayan mesti dapat menjana kod yang sama seperti peranti luar talian untuk membandingkannya. Hm..itu boleh membantu.
Pemerhatian lanjut saya terhadap "mainan" baharu saya membawa lebih banyak penemuan:
- jika saya mematikannya dan kemudian mematikannya, biasanya saya dapat melihat kod yang sama seperti sebelum ini
- namun, kadangkala, ia berubah
Satu-satunya penjelasan logik yang boleh saya hasilkan ialah kod ini mempunyai jangka hayat tertentu. Saya ingin menceritakan kisah saya cuba mengira tempohnya dalam fesyen "1-2-3-...-N", tetapi ia tidak benar: Saya mendapat petunjuk besar daripada apl seperti Authy and Co, tempat saya melihat TTL 30 saat. Temuan yang bagus, mari tambahkan ini pada senarai fakta yang diketahui.
Mari kita ringkaskan keperluan yang kita ada setakat ini:
- penjanaan kod boleh diramal (bukan rawak) dalam format 6 digit
- logik penjanaan harus boleh dihasilkan semula, yang membolehkan mendapatkan hasil yang sama tanpa mengira platform
- jangka hayat kod ialah 30 saat, yang bermaksud bahawa dalam jangka masa ini algoritma penjanaan menghasilkan nilai yang sama
Soalan besar
Baiklah, tetapi persoalan utama masih belum terjawab: bagaimana mungkin apl luar talian boleh menjana nilai yang sepadan dengan apl lain? Apakah persamaan mereka?
Jika anda menyukai alam semesta Lord of the Rings, anda mungkin masih ingat bagaimana Bilbo bermain teka-teki dengan Gollum, dan menyelesaikannya:
Perkara ini dimakan semua benda:
Burung, binatang, pokok, bunga;
Menggigit besi, menggigit keluli;
Mengisar batu keras untuk dimakan;
Membunuh raja, merosakkan bandar,
Dan mengalahkan gunung yang tinggi ke bawah.
Amaran spoiler, tetapi En. Baggins bernasib baik dan mendapat jawapan yang betul secara tidak sengaja - "Masa!". Percaya atau tidak, tetapi ini adalah jawapan kepada teka-teki kami juga: mana-mana 2 (atau lebih) apl mempunyai akses kepada masa yang sama selagi apl tersebut mempunyai jam terbenam di dalamnya. Yang terakhir tidak menjadi masalah pada hari ini, dan peranti yang dimaksudkan cukup besar untuk memuatkannya. Lihat sekeliling, dan kemungkinan masa pada jam tangan anda, telefon bimbit, TV, ketuhar dan jam di dinding adalah sama. Kami menyukai sesuatu di sini, nampaknya kami telah menemui asas untuk pengkomputeran OTP (kata laluan satu kali)!
Cabaran
Bergantung pada masa mempunyai set cabarannya sendiri:
- zon waktu - yang manakah hendak digunakan?
- jam cenderung tidak segerak, dan ini merupakan cabaran besar dalam sistem yang diedarkan
Mari kita atasinya satu persatu:
- zon waktu: penyelesaian paling mudah di sini ialah memastikan semua peranti bergantung pada zon yang sama dan UTC boleh menjadi calon agnostik lokasi yang baik
- mengenai jam yang tidak segerak: sebenarnya, kita mungkin tidak perlu menyelesaikannya malah menerima sebagai sesuatu yang tidak dapat dielakkan, selagi hanyut berada dalam satu atau dua saat, yang mungkin boleh diterima memandangkan TTL 30 saat. Pengeluar perkakasan peranti seharusnya dapat meramalkan bila hanyut tersebut akan dicapai, maka peranti akan menggunakannya sebagai tarikh tamat tempohnya, dan bank hanya akan menggantikannya dengan yang baharu, atau akan mempunyai cara untuk menyambungkannya ke rangkaian untuk menentukur jam. Sekurang-kurangnya, itulah pemikiran saya di sini.
Perlaksanaan
Ok, ini telah diselesaikan, jadi mari cuba laksanakan versi pertama algoritma kami menggunakan masa sebagai asas. Memandangkan kami berminat dengan keputusan 6 digit, nampaknya pilihan bijak untuk bergantung pada cap masa dan bukannya tarikh yang boleh dibaca manusia. Jom mulakan dari situ:
// gets current timestamp: current := time.Now().Unix() fmt.Println("Current timestamp: ", current)
Menurut dokumen Go, .Unix() kembali
bilangan saat berlalu sejak 1 Januari 1970 UTC.
Ini yang dicetak ke terminal:
Current timestamp: 1733691162
Itu permulaan yang baik, tetapi jika kita menjalankan semula kod itu, nilai cap masa akan berubah, sementara kita ingin memastikan ia stabil selama 30 saat. Nah, sekeping kek, mari bahagikannya dengan 30 dan gunakan nilai itu sebagai asas:
// gets current timestamp current := time.Now().Unix() fmt.Println("Current timestamp: ", current) // gets a number that is stable within 30 seconds base := current / 30 fmt.Println("Base: ", base)
Jom jalankan:
Current timestamp: 1733691545 Base: 57789718
Dan sekali lagi:
Current timestamp: 1733691552 Base: 57789718
Nilai asas kekal sama. Mari tunggu sebentar, dan jalankan semula:
Current timestamp: 1733691571 Base: 57789719
Nilai asas telah berubah, apabila tetingkap 30 saat telah berlalu - bagus!
Jika logik "bahagi dengan 30" tidak masuk akal, izinkan saya menerangkannya dengan contoh mudah:
- bayangkan bahawa cap masa kami mengembalikan 1
- jika kita membahagi 1 dengan 30, hasilnya akan menjadi 0, seperti apabila kita menggunakan bahasa pengaturcaraan yang ditaip ketat, membahagikan integer dengan integer mengembalikan integer lain, yang tidak mengambil berat tentang bahagian titik terapung
- ini bermakna untuk 30 saat seterusnya kita akan mendapat 0 manakala cap masa antara 0 dan 29
- apabila cap masa mencapai nilai 30, hasil pembahagian ialah 1, sehingga 60 (di mana ia menjadi 2), dan seterusnya
Saya harap ia lebih masuk akal sekarang.
Walau bagaimanapun, belum semua keperluan dipenuhi, kerana kami memerlukan hasil 6 digit, manakala asas semasa mempunyai 8 digit pada hari ini, tetapi pada satu ketika pada masa hadapan ia mungkin mencapai 9 titik digit, dan seterusnya . Baiklah, mari kita gunakan satu lagi helah matematik mudah: biar bahagikan asas dengan 1 000 000, dan dapatkan bakinya, yang akan sentiasa mempunyai tepat 6 digit, kerana peringatan boleh berupa sebarang nombor dari 0 hingga 999 999, tetapi tidak lebih besar:
// gets current timestamp: current := time.Now().Unix() fmt.Println("Current timestamp: ", current)
Bahagian fmt.Sprintf("d", kod) menambahkan sifar pendahuluan sekiranya nilai kod kami mempunyai kurang daripada 6 digit. Sebagai contoh, 1234 akan ditukar kepada 001234.
Keseluruhan kod untuk siaran ini boleh didapati di sini.
Mari jalankan kod ini:
Current timestamp: 1733691162
Baiklah, kami mendapat kod 6 digit kami, hore! Tetapi ada sesuatu yang tidak sesuai di sini, bukan? Jika saya memberi anda kod ini, dan anda akan menjalankannya pada masa yang sama seperti yang saya lakukan, anda akan mendapat kod yang sama, seperti saya. Ini tidak menjadikannya kata laluan sekali sahaja yang selamat, bukan? Inilah keperluan baharu:
- hasilnya harus berbeza untuk pengguna yang berbeza
Sudah tentu, beberapa perlanggaran tidak dapat dielakkan, jika kami mempunyai melebihi 1 juta pengguna, kerana ini adalah nilai unik maksimum yang mungkin bagi setiap 6 digit. Tetapi ini adalah perlanggaran yang jarang berlaku dan tidak dapat dielakkan secara teknikal, bukan kecacatan reka bentuk algoritma seperti yang kita ada sekarang.
Saya tidak fikir sebarang helah matematik yang bijak akan membantu kami di sini sendiri: jika kami memerlukan hasil yang berasingan bagi setiap pengguna, kami memerlukan keadaan khusus pengguna untuk merealisasikannya. Sebagai jurutera dan, pada masa yang sama, pengguna banyak perkhidmatan, kami tahu bahawa untuk memberikan akses kepada API mereka, perkhidmatan bergantung pada kunci peribadi, yang unik bagi setiap pengguna. Mari perkenalkan kunci peribadi untuk kes penggunaan kami juga untuk membezakan antara pengguna.
Kunci peribadi
Logik mudah untuk menjana kunci peribadi sebagai integer antara 1 000 000 dan 999 999 999:
// gets current timestamp current := time.Now().Unix() fmt.Println("Current timestamp: ", current) // gets a number that is stable within 30 seconds base := current / 30 fmt.Println("Base: ", base)
Kami menggunakan peta pkDb sebagai cara untuk menghalang pendua antara kunci peribadi, dan jika pendua telah dikesan, kami menjalankan logik penjanaan sekali lagi sehingga kami mendapat hasil yang unik.
Mari jalankan kod ini untuk mendapatkan sampel kunci peribadi:
Current timestamp: 1733691545 Base: 57789718
Mari kita gunakan kunci peribadi ini dalam logik penjanaan kod kami untuk memastikan kami mendapat hasil yang berbeza bagi setiap kunci peribadi. Memandangkan kunci persendirian kami adalah daripada jenis integer, perkara paling mudah yang boleh kami lakukan ialah menambahkannya pada nilai asas dan mengekalkan algoritma yang tinggal seperti sedia ada:
Current timestamp: 1733691552 Base: 57789718
Mari pastikan ia menghasilkan hasil yang berbeza untuk kunci peribadi yang berbeza:
Current timestamp: 1733691571 Base: 57789719
Hasilnya kelihatan seperti yang kami mahu dan jangkakan:
// gets current timestamp: current := time.Now().Unix() fmt.Println("Current timestamp: ", current) // gets a number that is stable within 30 seconds: base := current / 30 fmt.Println("Base: ", base) // makes sure it has only 6 digits: code := base % 1_000_000 // adds leading zeros if necessary: formattedCode := fmt.Sprintf("%06d", code) fmt.Println("Code: ", formattedCode)
Berfungsi seperti daya tarikan! Ini bermakna kunci persendirian harus disuntik ke dalam peranti yang menjana kod sebelum ia dihantar kepada pengguna seperti saya: itu tidak sepatutnya menjadi masalah sama sekali bagi bank.
Sudahkah kita selesai sekarang? Nah, hanya jika kita berpuas hati dengan senario buatan yang kita gunakan. Jika anda pernah mendayakan MFA untuk mana-mana perkhidmatan / tapak web yang anda gunakan akaun, anda mungkin perasan bahawa sumber web meminta anda mengimbas kod QR dengan apl faktor kedua pilihan anda (Authy, Google Authenticator, 2FAS, dsb. ) yang akan memasukkan kod rahsia ke dalam apl anda dan mula menjana kod 6 digit mulai saat itu. Sebagai alternatif, anda boleh memasukkan kod secara manual.
Saya membawa perkara ini untuk menyebut bahawa adalah mungkin untuk melihat format kunci peribadi sebenar yang digunakan dalam industri. Biasanya rentetan berkod Base32 sepanjang 16-32 aksara yang kelihatan seperti ini:
// gets current timestamp: current := time.Now().Unix() fmt.Println("Current timestamp: ", current)
Seperti yang anda lihat, ini agak berbeza daripada kunci peribadi integer yang kami gunakan dan pelaksanaan semasa algoritma kami tidak akan berfungsi jika kami ingin menukar kepada format ini. Bagaimanakah kita boleh menyesuaikan logik kita?
Kunci peribadi sebagai rentetan
Mari kita mulakan dengan pendekatan mudah: kod kami tidak akan dikompil, kerana baris ini:
Current timestamp: 1733691162
kerana pk adalah daripada jenis rentetan mulai sekarang. Jadi mengapa kita tidak menukarnya kepada integer? Walaupun terdapat cara yang lebih elegan dan berprestasi untuk melakukannya, berikut adalah perkara paling mudah yang saya hasilkan:
// gets current timestamp current := time.Now().Unix() fmt.Println("Current timestamp: ", current) // gets a number that is stable within 30 seconds base := current / 30 fmt.Println("Base: ", base)
Ini sangat diilhamkan oleh pelaksanaan Java hashCode() untuk jenis data String, yang menjadikannya cukup baik untuk senario kami.
Berikut ialah logik yang dilaraskan:
Current timestamp: 1733691545 Base: 57789718
Berikut ialah output terminal:
Current timestamp: 1733691552 Base: 57789718
Kod 6 digit yang bagus, bagus. Mari tunggu untuk sampai ke tetingkap kali seterusnya dan jalankannya semula:
Current timestamp: 1733691571 Base: 57789719
Hm...ia berfungsi, tetapi kod itu, pada asasnya adalah kenaikan nilai sebelumnya, yang tidak baik, kerana dengan cara ini OTP boleh diramal, dan mempunyai nilainya serta mengetahui masanya, ia sangat mudah untuk mula menjana nilai yang sama tanpa perlu mengetahui kunci peribadi. Berikut ialah pseudokod mudah untuk penggodaman ini:
// gets current timestamp: current := time.Now().Unix() fmt.Println("Current timestamp: ", current) // gets a number that is stable within 30 seconds: base := current / 30 fmt.Println("Base: ", base) // makes sure it has only 6 digits: code := base % 1_000_000 // adds leading zeros if necessary: formattedCode := fmt.Sprintf("%06d", code) fmt.Println("Code: ", formattedCode)
di mana keepWithinSixDigits akan memastikan bahawa selepas 999 999 nilai seterusnya ialah 000 000 dan seterusnya untuk mengekalkan nilai dalam kemungkinan had 6 digit.
Seperti yang anda lihat, ia adalah kecacatan keselamatan yang serius. Mengapa ia berlaku? Jika kita melihat logik pengiraan asas, kita akan melihat bahawa ia bergantung pada 2 faktor:
- cap masa semasa dibahagikan dengan 30
- cincang kunci persendirian
Cincang menghasilkan nilai yang sama untuk kunci yang sama, jadi nilainya adalah malar. Bagi semasa / 30 , ia mempunyai nilai yang sama selama 30 saat, tetapi apabila tetingkap telah berlalu, nilai seterusnya akan menjadi kenaikan yang sebelumnya. Kemudian asas % 1_000_000 berkelakuan seperti yang kita lihat. Pelaksanaan kami sebelum ini (dengan kunci peribadi sebagai integer) mempunyai kelemahan yang sama, tetapi kami tidak menyedarinya - kekurangan ujian untuk dipersalahkan.
Kita perlu mengubah arus / 30 menjadi sesuatu untuk menjadikan perubahan nilainya lebih ketara.
Nilai OTP teragih
Terdapat pelbagai cara untuk mencapainya, dan beberapa helah matematik yang hebat wujud di luar sana, tetapi untuk tujuan pendidikan mari kita utamakan kebolehbacaan penyelesaian yang akan kita gunakan: mari kita ekstrak semasa / 30 ke dalam pangkalan pembolehubah yang berasingan dan masukkan ia ke dalam logik pengiraan cincang:
// gets current timestamp: current := time.Now().Unix() fmt.Println("Current timestamp: ", current)
Dengan cara ini, walaupun asas akan berubah dengan 1 setiap 30 saat, selepas digunakan dalam logik fungsi hash(), berat beza akan meningkat disebabkan oleh siri pendaraban yang dilakukan.
Berikut ialah contoh kod yang dikemas kini:
Current timestamp: 1733691162
Jom jalankan:
// gets current timestamp current := time.Now().Unix() fmt.Println("Current timestamp: ", current) // gets a number that is stable within 30 seconds base := current / 30 fmt.Println("Base: ", base)
Boom! Bagaimanakah kita mendapat nilai tolak di sini? Nah, nampaknya kita kehabisan julat int64, jadi ia mengehadkan nilai kepada tolak dan bermula semula - rakan Java saya sudah biasa dengan ini daripada tingkah laku hashCode(). Penyelesaiannya mudah: mari kita ambil nilai mutlak daripada hasilnya, maka tanda tolak diabaikan:
Current timestamp: 1733691545 Base: 57789718
Berikut ialah keseluruhan sampel kod dengan pembetulan:
Current timestamp: 1733691552 Base: 57789718
Jom jalankan:
Current timestamp: 1733691571 Base: 57789719
Mari kita jalankan sekali lagi untuk memastikan bahawa nilai OTP diedarkan sekarang:
// gets current timestamp: current := time.Now().Unix() fmt.Println("Current timestamp: ", current) // gets a number that is stable within 30 seconds: base := current / 30 fmt.Println("Base: ", base) // makes sure it has only 6 digits: code := base % 1_000_000 // adds leading zeros if necessary: formattedCode := fmt.Sprintf("%06d", code) fmt.Println("Code: ", formattedCode)
Bagus, akhirnya penyelesaian yang baik!
Sebenarnya, itulah saat saya menghentikan proses pelaksanaan manual saya, kerana saya berseronok dan mempelajari sesuatu yang baharu. Walau bagaimanapun, ia bukan penyelesaian terbaik mahupun penyelesaian yang saya akan buat secara langsung. Antara lain, ia mempunyai kelemahan yang besar: seperti yang anda lihat, logik kami sentiasa berurusan dengan nombor yang besar disebabkan oleh logik pencincangan dan nilai cap masa, yang bermaksud bahawa sangat tidak mungkin kami dapat menjana hasil yang bermula dengan 1 atau lebih sifar: cth., 012345 , 001234, dsb., walaupun ia sah sepenuhnya. Disebabkan itu, kami adalah 100 000 nilai kemungkinan pendek, iaitu 10% daripada bilangan kemungkinan hasil algoritma - kemungkinan perlanggaran adalah lebih tinggi dengan cara ini. Tidak hebat!
Ke mana hendak pergi dari sini
Saya tidak akan mendalami pelaksanaan yang digunakan dalam aplikasi sebenar, tetapi bagi mereka yang ingin tahu, saya akan berkongsi dua RFC yang patut dilihat:
- HOTP: Algoritma Kata Laluan Satu Masa Berasaskan HMAC
- TOTP: Algoritma Kata Laluan Satu Masa Berasaskan Masa
Dan berikut ialah pelaksanaan pseudokod yang akan berfungsi dengan cara yang dimaksudkan berdasarkan RFC di atas:
Current timestamp: 1733692423 Base: 57789747 Code: 789747
Seperti yang anda lihat, kami sangat hampir dengan itu, tetapi algoritma asal menggunakan pencincangan yang lebih maju (HMAC-SHA1 dalam contoh ini) dan melakukan beberapa operasi bitwise untuk menormalkan output.
Pertimbangan keselamatan: gunakan semula dan bukannya bina sendiri
Walau bagaimanapun, ada satu lagi perkara yang ingin saya bincangkan sebelum kita menyebutnya sehari: keselamatan. Saya amat menggalakkan anda supaya tidak melaksanakan logik penjanaan OTP sendiri, kerana terdapat banyak perpustakaan di luar sana yang telah melakukannya untuk kami. Ruang untuk kesilapan adalah besar, dan ia adalah jarak yang dekat dengan kelemahan yang akan ditemui dan dieksploitasi oleh pelakon jahat di luar sana.
Walaupun anda mendapat logik penjanaan dengan betul dan akan menutupnya dengan ujian, terdapat perkara lain yang boleh menjadi salah. Sebagai contoh, pada pendapat anda, berapa banyak yang diperlukan untuk memaksa kod 6 digit? Mari bereksperimen:
// gets current timestamp: current := time.Now().Unix() fmt.Println("Current timestamp: ", current)
Mari jalankan kod ini:
Current timestamp: 1733691162
Dan sekali lagi:
// gets current timestamp current := time.Now().Unix() fmt.Println("Current timestamp: ", current) // gets a number that is stable within 30 seconds base := current / 30 fmt.Println("Base: ", base)
Seperti yang anda lihat, ia mengambil masa kira-kira 70 ms untuk meneka kod melalui gelung for-forcing yang mudah. Itu 400 kali lebih cepat daripada seumur hidup OTP! Pelayan apl/tapak web yang menggunakan mekanisme OTP perlu menghalangnya dengan, sebagai contoh, tidak menerima kod baharu untuk 5 atau 10 saat seterusnya selepas 3 percubaan yang gagal. Dengan cara ini penyerang hanya mendapat 18 atau 9 percubaan yang sepadan dalam tetingkap 30 saat, yang tidak mencukupi untuk kumpulan 1 juta nilai yang mungkin.
Dan ada lagi perkara seperti ini yang mudah terlepas pandang. Jadi, izinkan saya ulangi: jangan bina ini dari awal, tetapi bergantung pada penyelesaian sedia ada.
Apa pun, saya harap anda mempelajari sesuatu yang baharu hari ini, dan logik OTP tidak akan menjadi misteri untuk anda mulai saat ini. Selain itu, jika pada satu ketika dalam hidup, anda perlu menjadikan peranti luar talian anda menjana beberapa nilai menggunakan algoritma yang boleh dihasilkan semula, anda mempunyai idea yang baik untuk bermula.
Terima kasih atas masa yang anda luangkan membaca siaran ini, dan bergembiralah! =)
P.S. Terima e-mel setelah saya menerbitkan siaran baharu - langgan di sini
P.P.S. Seperti kanak-kanak lain yang hebat, saya telah mencipta akaun Bluesky sejak kebelakangan ini, jadi tolong bantu saya untuk menjadikan suapan saya lebih menyeronokkan =)
Atas ialah kandungan terperinci Menyahmistikan OTP: logik di sebalik penjanaan token luar talian. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

OpenSSL, sebagai perpustakaan sumber terbuka yang digunakan secara meluas dalam komunikasi yang selamat, menyediakan algoritma penyulitan, kunci dan fungsi pengurusan sijil. Walau bagaimanapun, terdapat beberapa kelemahan keselamatan yang diketahui dalam versi sejarahnya, yang sebahagiannya sangat berbahaya. Artikel ini akan memberi tumpuan kepada kelemahan umum dan langkah -langkah tindak balas untuk OpenSSL dalam sistem Debian. Debianopenssl yang dikenal pasti: OpenSSL telah mengalami beberapa kelemahan yang serius, seperti: Kerentanan Pendarahan Jantung (CVE-2014-0160): Kelemahan ini mempengaruhi OpenSSL 1.0.1 hingga 1.0.1f dan 1.0.2 hingga 1.0.2 versi beta. Penyerang boleh menggunakan kelemahan ini untuk maklumat sensitif baca yang tidak dibenarkan di pelayan, termasuk kunci penyulitan, dll.

Artikel ini menerangkan cara menggunakan alat PPROF untuk menganalisis prestasi GO, termasuk membolehkan profil, mengumpul data, dan mengenal pasti kesesakan biasa seperti CPU dan isu memori.

Artikel ini membincangkan ujian unit menulis di GO, meliputi amalan terbaik, teknik mengejek, dan alat untuk pengurusan ujian yang cekap.

Artikel ini menunjukkan penciptaan dan stub di GO untuk ujian unit. Ia menekankan penggunaan antara muka, menyediakan contoh pelaksanaan mengejek, dan membincangkan amalan terbaik seperti menjaga mocks fokus dan menggunakan perpustakaan penegasan. Articl

Artikel ini meneroka kekangan jenis adat Go untuk generik. Ia memperincikan bagaimana antara muka menentukan keperluan jenis minimum untuk fungsi generik, meningkatkan keselamatan jenis dan kebolehgunaan semula kod. Artikel ini juga membincangkan batasan dan amalan terbaik

Artikel ini membincangkan pakej GO's Reflect, yang digunakan untuk manipulasi kod runtime, bermanfaat untuk siri, pengaturcaraan generik, dan banyak lagi. Ia memberi amaran tentang kos prestasi seperti pelaksanaan yang lebih perlahan dan penggunaan memori yang lebih tinggi, menasihati penggunaan yang bijak dan terbaik

Artikel ini membincangkan menggunakan ujian yang didorong oleh jadual di GO, satu kaedah yang menggunakan jadual kes ujian untuk menguji fungsi dengan pelbagai input dan hasil. Ia menyoroti faedah seperti kebolehbacaan yang lebih baik, penurunan duplikasi, skalabiliti, konsistensi, dan a

Artikel ini meneroka menggunakan alat pengesanan untuk menganalisis aliran pelaksanaan aplikasi GO. Ia membincangkan teknik instrumentasi manual dan automatik, membandingkan alat seperti Jaeger, Zipkin, dan OpenTelemetry, dan menonjolkan visualisasi data yang berkesan


Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Dreamweaver Mac版
Alat pembangunan web visual

DVWA
Damn Vulnerable Web App (DVWA) ialah aplikasi web PHP/MySQL yang sangat terdedah. Matlamat utamanya adalah untuk menjadi bantuan bagi profesional keselamatan untuk menguji kemahiran dan alatan mereka dalam persekitaran undang-undang, untuk membantu pembangun web lebih memahami proses mengamankan aplikasi web, dan untuk membantu guru/pelajar mengajar/belajar dalam persekitaran bilik darjah Aplikasi web keselamatan. Matlamat DVWA adalah untuk mempraktikkan beberapa kelemahan web yang paling biasa melalui antara muka yang mudah dan mudah, dengan pelbagai tahap kesukaran. Sila ambil perhatian bahawa perisian ini

Dreamweaver CS6
Alat pembangunan web visual

EditPlus versi Cina retak
Saiz kecil, penyerlahan sintaks, tidak menyokong fungsi gesaan kod

SublimeText3 Linux versi baharu
SublimeText3 Linux versi terkini