国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

首頁 後端開發(fā) Golang 揭秘 OTP:離線產(chǎn)生代幣背後的邏輯

揭秘 OTP:離線產(chǎn)生代幣背後的邏輯

Dec 12, 2024 pm 10:23 PM

你好!另一個(gè)晚上,在回家的路上,我決定檢查一下郵箱。我指的不是我的電子郵件收件箱,而是郵差放置實(shí)際信件的老式實(shí)際盒子。令我驚訝的是,我在那裡發(fā)現(xiàn)了一個(gè)信封,裡面裝著一些東西!當(dāng)我打開它時(shí),我花了一些時(shí)間希望這是來自霍格華茲的遲來了幾十年的信。但當(dāng)我注意到這是一封來自銀行的無聊的「成人」信時(shí),我不得不回到現(xiàn)實(shí)。我瀏覽了一下文字,意識(shí)到我的「酷孩子純數(shù)字」銀行已被當(dāng)?shù)厥袌?chǎng)上最大的玩家收購。作為新開始的象徵,他們?cè)谛欧馍咸砑恿艘韵聝?nèi)容:

Demystifying OTPs: the logic behind the offline generation of tokens

以及如何使用它的說明。

如果你像我一樣,從來沒有遇到過這樣的技術(shù)創(chuàng)新,讓我分享一下我從信中學(xué)到的東西:新所有者決定執(zhí)行他們公司的安全策略,這意味著所有用戶從現(xiàn)在開始,帳戶將啟用MFA(順便說一句,這是值得稱讚的)。您在上面看到的裝置會(huì)產(chǎn)生 6 位數(shù)字長的一次性令牌,在登入您的銀行帳戶時(shí)用作第二因素。基本上,與 Authy、Google Authenticator 或 2FAS 等應(yīng)用程式的工作方式相同,但採用物理形狀。

所以,我嘗試了一下,登入過程很順利:設(shè)備向我顯示了一個(gè) 6 位元代碼,我在我的銀行應(yīng)用程式中輸入了它,這讓我進(jìn)入了。萬歲!但後來我突然意識(shí)到:這東西是如何運(yùn)作的?它無法以某種方式連接到互聯(lián)網(wǎng),但它設(shè)法產(chǎn)生我的銀行伺服器接受的正確代碼。嗯...裡面有SIM卡或類似的東西嗎?沒辦法!

意識(shí)到我的生活將永遠(yuǎn)不一樣,我開始想知道我上面提到的應(yīng)用程式(Authy 和朋友)?我內(nèi)心的研究員被喚醒了,所以我將手機(jī)切換到飛行模式,令我大吃一驚的是,我意識(shí)到它們?cè)陔x線狀態(tài)下工作得非常好:它們不斷生成被應(yīng)用程式伺服器接受的程式碼。有趣!

不確定你的看法,但我一直認(rèn)為一次性代幣流是理所當(dāng)然的,並且從未真正認(rèn)真考慮過它(特別是因?yàn)楝F(xiàn)在我的手機(jī)很少?zèng)]有互聯(lián)網(wǎng),除非我正在做一些戶外探險(xiǎn)),所以這是我驚訝的根本原因。否則,從安全的角度來看,以這種方式工作是完全有意義的,因?yàn)樯蛇^程純粹是本地的,因此對(duì)於外部參與者來說是安全的。但它是如何運(yùn)作的呢?

嗯,像 Google 或 ChatGPT 這樣的現(xiàn)代技術(shù)可以讓您輕鬆找到答案。但這個(gè)技術(shù)問題對(duì)我來說似乎很有趣,所以我決定先嘗試一下並自己解決。

要求

讓我們從我們擁有的開始:

  • 可產(chǎn)生 6 位元代碼的離線設(shè)備
  • 伺服器接受這些程式碼,驗(yàn)證它們,如果正確則發(fā)出綠色訊號(hào)

伺服器驗(yàn)證部分提示伺服器必須能夠產(chǎn)生與離線設(shè)備相同的程式碼來比較它們。嗯..這會(huì)很有幫助。

對(duì)我的新「玩具」的進(jìn)一步觀察帶來了更多發(fā)現(xiàn):

  • 如果我將其關(guān)閉然後再關(guān)閉,通常我可以看到與之前相同的程式碼
  • 然而,偶爾,它會(huì)改變

我能想到的唯一邏輯解釋是這些程式碼有一定的生命週期。我想講述一個(gè)我試圖以“1-2-3-...-N”方式計(jì)算它的持續(xù)時(shí)間的故事,但這不會(huì)是真的:我從像這樣的應(yīng)用程式中得到了一個(gè)很大的提示Authy and Co,我在那裡看到了30 秒的TTL。很好的發(fā)現(xiàn),讓我們將其添加到已知事實(shí)列表中。

讓我們總結(jié)一下到目前為止我們的要求:

  • 以 6 位數(shù)字格式產(chǎn)生可預(yù)測(cè)(而非隨機(jī))的代碼
  • 生成邏輯應(yīng)該是可重現(xiàn)的,這樣無論平臺(tái)如何,都可以得到相同的結(jié)果
  • 程式碼生命週期為 30 秒,這表示在這段時(shí)間內(nèi)產(chǎn)生演算法會(huì)產(chǎn)生相同的值

大問題

好吧,但主要問題仍然沒有得到解答:離線應(yīng)用程式如何產(chǎn)生與其他應(yīng)用程式中的值相符的值?他們有什麼共同點(diǎn)?

如果您喜歡《魔戒》宇宙,您可能還記得比爾博如何與咕嚕玩謎語遊戲,並解決了這個(gè)問題:

這個(gè)萬物吞噬之物:
鳥、獸、樹、花;
啃鐵咬鋼;
將堅(jiān)硬的石頭磨成粉;
殺死國王,摧毀城鎮(zhèn),
並擊敗高山。

劇透警告,但巴金斯先生很幸運(yùn),意外地得出了正確答案 - “時(shí)間!”。不管你相信與否,這也正是我們謎題的答案:任何 2 個(gè)(或更多)應(yīng)用程式都可以存取同一時(shí)間,只要它們內(nèi)部有嵌入式時(shí)鐘。如今,後者已不再是問題,而且所討論的設(shè)備足夠大,可以容納它。環(huán)顧四周,你的手錶、手機(jī)、電視、烤箱和牆上的時(shí)鐘上的時(shí)間很可能是相同的。我們?cè)谶@裡很感興趣,似乎我們已經(jīng)找到了 OTP(一次性密碼)計(jì)算的基礎(chǔ)!

挑戰(zhàn)

依賴時(shí)間有其自身的一系列挑戰(zhàn):

  • 時(shí)區(qū) - 使用哪一個(gè)?
  • 時(shí)鐘往往會(huì)不同步,這對(duì)分散式系統(tǒng)來說是一個(gè)巨大的挑戰(zhàn)

讓我們一一解決:

  • 時(shí)區(qū):這裡最簡(jiǎn)單的解決方案是確保所有設(shè)備都依賴同一區(qū)域,並且 UTC 可以是一個(gè)很好的與位置無關(guān)的候選
  • 至於時(shí)鐘不同步:實(shí)際上,我們甚至可能不需要解決它,而是接受不可避免的事情,只要漂移在一兩秒之內(nèi),考慮到 30 秒的 TTL,這可能是可以容忍的。設(shè)備的硬體生產(chǎn)商應(yīng)該能夠預(yù)測(cè)何時(shí)會(huì)實(shí)現(xiàn)這種漂移,因此設(shè)備將使用它作為其到期日期,而銀行將簡(jiǎn)單地用新的替換它們,或者將有辦法連接它們到網(wǎng)路來校準(zhǔn)時(shí)鐘。至少,這是我的想法。

執(zhí)行

好的,這件事已經(jīng)解決了,所以讓我們嘗試以時(shí)間為基礎(chǔ)來實(shí)現(xiàn)我們演算法的第一個(gè)版本。由於我們對(duì) 6 位數(shù)字結(jié)果感興趣,因此依賴時(shí)間戳而不是人類可讀的日期聽起來是一個(gè)明智的選擇。讓我們從這裡開始:

// gets current timestamp:
current := time.Now().Unix()
fmt.Println("Current timestamp: ", current)

根據(jù) Go 文檔,.Unix() 返回

自 UTC 1970 年 1 月 1 日以來經(jīng)過的秒數(shù)。

這是終端列印的內(nèi)容:

Current timestamp:  1733691162

這是一個(gè)好的開始,但是如果我們重新運(yùn)行該程式碼,時(shí)間戳值將會(huì)改變,而我們希望保持它穩(wěn)定 30 秒。好吧,小菜一碟,我們將其除以 30 並使用該值作為基數(shù):

// 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)

讓我們運(yùn)行它:

Current timestamp:  1733691545
Base:  57789718

再說一次:

Current timestamp:  1733691552
Base:  57789718

基礎(chǔ)值維持不變。讓我們稍等一下,然後再次運(yùn)行:

Current timestamp:  1733691571
Base:  57789719

隨著 30 秒視窗的過去,基礎(chǔ)值已更改 - 幹得好!

如果「除以30」的邏輯沒有意義,讓我用一個(gè)簡(jiǎn)單的例子來解釋:

  • 想像一下我們的時(shí)間戳回 1
  • 如果我們將 1 除以 30,結(jié)果將為 0,就像當(dāng)我們使用嚴(yán)格類型程式語言時(shí),整數(shù)除以整數(shù)會(huì)傳回另一個(gè)整數(shù),該整數(shù)與浮點(diǎn)部分無關(guān)
  • 這意味著在接下來的 30 秒內(nèi),當(dāng)時(shí)間戳介於 0 到 29 之間時(shí),我們將得到 0
  • 一旦時(shí)間戳達(dá)到30,除法的結(jié)果就是1,直到60(變成2),依此類推

我希望它現(xiàn)在更有意義。

但是,還沒有滿足所有要求,因?yàn)槲覀冃枰?6 位數(shù)字的結(jié)果,而當(dāng)前基數(shù)截至今天是 8 位數(shù)字,但在未來的某個(gè)時(shí)間點(diǎn)可能會(huì)達(dá)到 9 位數(shù)字點(diǎn),依此類推。好吧,讓我們使用另一個(gè)簡(jiǎn)單的數(shù)學(xué)技巧:將基數(shù)除以1 000 000,並得到餘數(shù),餘數(shù)始終為6 位數(shù)字,因?yàn)樘嵝芽梢允? 到999 999 之間的任何數(shù)字,但不能更大:

// gets current timestamp:
current := time.Now().Unix()
fmt.Println("Current timestamp: ", current)

fmt.Sprintf(" d", code) 部分會(huì)附加前導(dǎo)零,以防我們的程式碼值少於 6 位元。例如,1234 將轉(zhuǎn)換為 001234。
這篇文章的完整程式碼可以在這裡找到。

讓我們執(zhí)行此程式碼:

Current timestamp:  1733691162

好的,我們得到了 6 位元程式碼,萬歲!但這裡感覺有些不對(duì)勁,不是嗎?如果我給您這個(gè)程式碼,並且您將與我同時(shí)運(yùn)行它,您將獲得與我相同的程式碼。這並不意味著它是一個(gè)安全的一次性密碼,對(duì)吧?新的要求來了:

  • 不同使用者的結(jié)果應(yīng)該不同

當(dāng)然,如果我們的用戶超過 100 萬,一些衝突是不可避免的,因?yàn)檫@是每 6 位數(shù)字的最大可能唯一值。但這些都是罕見的,技術(shù)上不可避免的碰撞,而不是像我們現(xiàn)在這樣的演算法設(shè)計(jì)缺陷。

我認(rèn)為任何聰明的數(shù)學(xué)技巧本身都不會(huì)幫助我們:如果我們需要每個(gè)使用者單獨(dú)的結(jié)果,我們需要一個(gè)特定於使用者的狀態(tài)來實(shí)現(xiàn)它。作為工程師,同時(shí)也是許多服務(wù)的用戶,我們知道要授予對(duì)其 API 的存取權(quán)限,服務(wù)依賴私鑰,而私鑰對(duì)於每個(gè)用戶來說都是唯一的。讓我們?yōu)槲覀兊挠美胍粋€(gè)私鑰,以區(qū)分用戶。

私鑰

產(chǎn)生 1 000 000 到 999 999 999 之間整數(shù)的私鑰的簡(jiǎn)單邏輯:

// 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)

我們使用 pkDb 映射作為防止私鑰之間重複的方法,如果檢測(cè)到重複,我們將再次運(yùn)行生成邏輯,直到獲得唯一的結(jié)果。

讓我們執(zhí)行此程式碼來取得私鑰範(fàn)例:

Current timestamp:  1733691545
Base:  57789718

讓我們?cè)诔淌酱a產(chǎn)生邏輯中使用此私鑰,以確保每個(gè)私鑰得到不同的結(jié)果。由於我們的私鑰是整數(shù)類型,所以我們能做的最簡(jiǎn)單的事情就是將其添加到基值上,並保持其餘演算法不變:

Current timestamp:  1733691552
Base:  57789718

讓我們確保它對(duì)於不同的私鑰產(chǎn)生不同的結(jié)果:

Current timestamp:  1733691571
Base:  57789719

結(jié)果看起來符合我們的期望:

// 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)

魅力十足!這意味著私鑰應(yīng)該先註入生成程式碼的裝置中,然後再發(fā)送給像我這樣的用戶:這對(duì)銀行來說根本不應(yīng)該是問題。

我們現(xiàn)在完成了嗎?好吧,前提是我們對(duì)我們使用的人工場(chǎng)景感到滿意。如果您曾經(jīng)為您擁有帳戶的任何服務(wù)/網(wǎng)站啟用過 MFA,您可能會(huì)注意到網(wǎng)路資源要求您使用您選擇的第二因素應(yīng)用程式(Authy、Google Authenticator、2FAS 等)掃描 QR 碼。 ),它將把密碼輸入到您的應(yīng)用程式中,並從那時(shí)起開始產(chǎn)生 6 位數(shù)字的代碼?;蛘?,也可以手動(dòng)輸入代碼。

我提出這個(gè)是為了一睹業(yè)界使用的真實(shí)私鑰的格式。它們通常是 16-32 個(gè)字元長的 Base32 編碼字串,如下所示:

// gets current timestamp:
current := time.Now().Unix()
fmt.Println("Current timestamp: ", current)

如您所見,這與我們使用的整數(shù)私鑰有很大不同,如果我們要切換到這種格式,我們演算法的當(dāng)前實(shí)作將無法運(yùn)作。我們?nèi)绾握{(diào)整我們的邏輯?

私鑰作為字串

讓我們從一個(gè)簡(jiǎn)單的方法開始:我們的程式碼將無法編譯,因?yàn)檫@一行:

Current timestamp:  1733691162

因?yàn)?pk 從現(xiàn)在開始是字串型。那我們?yōu)槭颤N不把它轉(zhuǎn)換成整數(shù)呢?雖然有更優(yōu)雅和更有效率的方法可以做到這一點(diǎn),但這是我想到的最簡(jiǎn)單的方法:

// 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)

這很大程度上是受到 String 資料類型的 Java hashCode() 實(shí)作的啟發(fā),這使得它足以滿足我們的場(chǎng)景。

調(diào)整後的邏輯如下:

Current timestamp:  1733691545
Base:  57789718

這是終端輸出:

Current timestamp:  1733691552
Base:  57789718

很好,有 6 位元程式碼,幹得好。讓我們等待到達(dá)下一個(gè)時(shí)間窗口並再次運(yùn)行它:

Current timestamp:  1733691571
Base:  57789719

嗯...它可以工作,但是程式碼基本上是前一個(gè)值的增量,這不好,因?yàn)檫@樣OTP 是可預(yù)測(cè)的,並且擁有它的值並知道它屬於什麼時(shí)間,這是非常好的無需知道私鑰即可開始產(chǎn)生相同的值。這是此駭客攻擊的簡(jiǎn)單偽代碼:

// 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)

其中 keepWithinSixDigits 將確保在 999 999 之後下一個(gè)值是 000 000 等等,以將該值保持在 6 位數(shù)字的限制範(fàn)圍內(nèi)。

如您所見,這是一個(gè)嚴(yán)重的安全漏洞。為什麼會(huì)發(fā)生這種情況?如果我們看一下基本計(jì)算邏輯,我們會(huì)發(fā)現(xiàn)它依賴兩個(gè)因素:

  • 當(dāng)前時(shí)間戳記除以 30
  • 私鑰的雜湊值

雜湊對(duì)於相同的鍵產(chǎn)生相同的值,因此它的值是恆定的。至於當(dāng)前的 / 30 ,它在 30 秒內(nèi)具有相同的值,但是一旦視窗過去,下一個(gè)值將是前一個(gè)值的增量。然後 base % 1_000_000 的行為就像我們看到的那樣。我們之前的實(shí)作(使用私鑰作為整數(shù))也有同樣的漏洞,但我們沒有註意到這一點(diǎn) - 缺乏測(cè)試。

我們需要將 current / 30 轉(zhuǎn)換成某些東西,使其值的變化更加明顯。

分佈式 OTP 值

有多種方法可以實(shí)現(xiàn)這一點(diǎn),並且存在一些很酷的數(shù)學(xué)技巧,但出於教育目的,讓我們優(yōu)先考慮我們將採用的解決方案的可讀性:讓我們將current / 30 提取到一個(gè)單獨(dú)的變數(shù)基數(shù)中並包含進(jìn)入雜湊計(jì)算邏輯:

// gets current timestamp:
current := time.Now().Unix()
fmt.Println("Current timestamp: ", current)

這樣,即使底數(shù)每 30 秒變化 1,但在 hash() 函數(shù)邏輯中使用後,diff 的權(quán)重會(huì)因?yàn)橐幌盗谐朔ǖ膱?zhí)行而增加。

這是更新後的程式碼範(fàn)例:

Current timestamp:  1733691162

讓我們運(yùn)行它:

// 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)

繁榮!我們?cè)觞N會(huì)在這裡得到負(fù)值呢?好吧,看起來我們已經(jīng)超出了 int64 範(fàn)圍,因此它將值限制為負(fù)數(shù)並重新開始 - 我的 Java 同事透過 hashCode() 行為對(duì)此很熟悉。 解決方法很簡(jiǎn)單:讓我們從結(jié)果中取絕對(duì)值,這樣減號(hào)就被忽略:

Current timestamp:  1733691545
Base:  57789718

這是修復(fù)後的完整程式碼範(fàn)例:

Current timestamp:  1733691552
Base:  57789718

讓我們運(yùn)行它:

Current timestamp:  1733691571
Base:  57789719

讓我們?cè)俅芜\(yùn)行它以確保 OTP 值現(xiàn)在已分發(fā):

// 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)

很好,終於有一個(gè)不錯(cuò)的解決方案了!

實(shí)際上,那是我停止手動(dòng)實(shí)施過程的那一刻,因?yàn)槲蚁硎艿搅藰啡K學(xué)到了新東西。然而,這既不是最好的解決方案,也不是我願(yuàn)意接受的解決方案。除此之外,它還有一個(gè)很大的缺陷:如您所見,由於雜湊邏輯和時(shí)間戳記值,我們的邏輯總是處理大數(shù)字,這意味著我們不太可能產(chǎn)生以1 或1 開頭的結(jié)果。更多零:例如 012345 、 001234 等,即使它們完全有效。因此,我們還缺少 100 000 個(gè)可能的值,這比演算法的可能結(jié)果數(shù)量少了 10% - 這樣碰撞的可能性會(huì)更高。不酷!

從這裡到哪裡去

我不會(huì)深入探討實(shí)際應(yīng)用程式中使用的實(shí)現(xiàn),但對(duì)於那些好奇的人,我將分享兩個(gè)值得一看的 RFC:

  • HOTP:一種基於 HMAC 的一次性密碼演算法
  • TOTP:基於時(shí)間的一次性密碼演算法

這是偽代碼實(shí)現(xiàn),它將根據(jù)上述 RFC 以預(yù)期方式工作:

Current timestamp:  1733692423
Base:  57789747
Code:  789747

如您所見,我們已經(jīng)非常接近了,但原始演算法使用更高級(jí)的雜湊(本例中為 HMAC-SHA1),並執(zhí)行一些位元運(yùn)算來標(biāo)準(zhǔn)化輸出。

安全考慮:重複使用而不是自己構(gòu)建

但是,在我們結(jié)束之前我還想講一件事:安全性。我強(qiáng)烈建議您不要自行實(shí)作產(chǎn)生 OTP 的邏輯,因?yàn)橛性S多函式庫已經(jīng)為我們完成了這項(xiàng)工作。犯錯(cuò)的空間是巨大的,而且離不良行為者發(fā)現(xiàn)和利用的漏洞只有很短的距離。

即使您的生成邏輯正確並通過測(cè)試覆蓋它,也可能會(huì)出現(xiàn)其他問題。例如,您認(rèn)為暴力破解 6 位數(shù)代碼需要花費(fèi)多少時(shí)間?讓我們來實(shí)驗(yàn)一下:

// gets current timestamp:
current := time.Now().Unix()
fmt.Println("Current timestamp: ", current)

讓我們執(zhí)行此程式碼:

Current timestamp:  1733691162

再一次:

// 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)

如您所見,透過簡(jiǎn)單的暴力 for 迴圈猜測(cè)程式碼大約需要 70 毫秒。這比 OTP 的壽命快 400 倍!使用 OTP 機(jī)制的應(yīng)用程式/網(wǎng)站的伺服器需要透過例如在 3 次失敗嘗試後的接下來 5 或 10 秒內(nèi)不接受新程式碼來防止這種情況。這樣,攻擊者在 30 秒的視窗內(nèi)只能相應(yīng)地獲得 18 或 9 次嘗試,這對(duì)於 100 萬個(gè)可能值的池來說是不夠的。

還有其他類似的事情很容易被忽略。所以,讓我再說一次:不要從頭開始建立它,而是依賴現(xiàn)有的解決方案。

無論如何,我希望你今天學(xué)到了一些新東西,從現(xiàn)在開始 OTP 邏輯對(duì)你來說不再是一個(gè)謎。此外,如果在生活中的某個(gè)時(shí)刻,您需要使用可重現(xiàn)的演算法讓離線設(shè)備產(chǎn)生一些值,那麼您很清楚從哪裡開始。

感謝您花時(shí)間閱讀這篇文章,祝您玩得開心! =)

P.S.我發(fā)布新帖子後會(huì)收到一封電子郵件 - 在此訂閱

P.P.S.和其他酷孩子一樣,我最近創(chuàng)建了一個(gè) Bluesky 帳戶,所以請(qǐng)幫助我讓我的 Feed 變得更有趣 =)

以上是揭秘 OTP:離線產(chǎn)生代幣背後的邏輯的詳細(xì)內(nèi)容。更多資訊請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願(yuàn)投稿,版權(quán)歸原作者所有。本站不承擔(dān)相應(yīng)的法律責(zé)任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請(qǐng)聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)程式碼編輯軟體(SublimeText3)

默認(rèn)情況下,GO靜態(tài)鏈接的含義是什麼? 默認(rèn)情況下,GO靜態(tài)鏈接的含義是什麼? Jun 19, 2025 am 01:08 AM

Go默認(rèn)將程序編譯為獨(dú)立二進(jìn)製文件,主要原因是靜態(tài)鏈接。 1.部署更簡(jiǎn)單:無需額外安裝依賴庫,可直接跨Linux發(fā)行版運(yùn)行;2.二進(jìn)制體積更大:包含所有依賴導(dǎo)致文件尺寸增加,但可通過構(gòu)建標(biāo)誌或壓縮工具優(yōu)化;3.更高的可預(yù)測(cè)性與安全性:避免外部庫版本變化帶來的風(fēng)險(xiǎn),增強(qiáng)穩(wěn)定性;4.運(yùn)行靈活性受限:無法熱更新共享庫,需重新編譯部署以修復(fù)依賴漏洞。這些特性使Go適用於CLI工具、微服務(wù)等場(chǎng)景,但在存儲(chǔ)受限或依賴集中管理的環(huán)境中需權(quán)衡取捨。

如何在GO中創(chuàng)建緩衝頻道? (例如,make(chan int,10)) 如何在GO中創(chuàng)建緩衝頻道? (例如,make(chan int,10)) Jun 20, 2025 am 01:07 AM

在Go中創(chuàng)建緩衝通道只需在make函數(shù)中指定容量參數(shù)即可。緩衝通道允許發(fā)送操作在沒有接收者時(shí)暫存數(shù)據(jù),只要未超過指定容量,例如ch:=make(chanint,10)創(chuàng)建了一個(gè)可存儲(chǔ)最多10個(gè)整型值的緩衝通道;與無緩衝通道不同,發(fā)送數(shù)據(jù)時(shí)不會(huì)立即阻塞,而是將數(shù)據(jù)暫存於緩衝區(qū)中,直到被接收者取走;使用時(shí)需注意:1.容量設(shè)置應(yīng)合理以避免內(nèi)存浪費(fèi)或頻繁阻塞;2.需防止緩衝區(qū)無限堆積數(shù)據(jù)導(dǎo)致內(nèi)存問題;3.可用chanstruct{}類型傳遞信號(hào)以節(jié)省資源;常見場(chǎng)景包括控制並發(fā)數(shù)量、生產(chǎn)者-消費(fèi)者模型及異

在沒有C中的手動(dòng)內(nèi)存管理的情況下,如何確保內(nèi)存安全性? 在沒有C中的手動(dòng)內(nèi)存管理的情況下,如何確保內(nèi)存安全性? Jun 19, 2025 am 01:11 AM

Goensuresmemorysafetywithoutmanualmanagementthroughautomaticgarbagecollection,nopointerarithmetic,safeconcurrency,andruntimechecks.First,Go’sgarbagecollectorautomaticallyreclaimsunusedmemory,preventingleaksanddanglingpointers.Second,itdisallowspointe

如何使用GO進(jìn)行系統(tǒng)編程任務(wù)? 如何使用GO進(jìn)行系統(tǒng)編程任務(wù)? Jun 19, 2025 am 01:10 AM

Go是系統(tǒng)編程的理想選擇,因?yàn)樗Y(jié)合了C等編譯型語言的性能與現(xiàn)代語言的易用性和安全性。 1.文件與目錄操作方面,Go的os包支持創(chuàng)建、刪除、重命名及檢查文件和目錄是否存在,使用os.ReadFile可一行代碼讀取整個(gè)文件,適用於編寫備份腳本或日誌處理工具;2.進(jìn)程管理方面,通過os/exec包的exec.Command函數(shù)可執(zhí)行外部命令、捕獲輸出、設(shè)置環(huán)境變量、重定向輸入輸出流以及控制進(jìn)程生命週期,適合用於自動(dòng)化工具和部署腳本;3.網(wǎng)絡(luò)與並發(fā)方面,net包支持TCP/UDP編程、DNS查詢及原始套

如何在GO中的結(jié)構(gòu)實(shí)例上調(diào)用方法? 如何在GO中的結(jié)構(gòu)實(shí)例上調(diào)用方法? Jun 24, 2025 pm 03:17 PM

在Go語言中,調(diào)用結(jié)構(gòu)體方法需先定義結(jié)構(gòu)體和綁定接收者的方法,使用點(diǎn)號(hào)訪問。定義結(jié)構(gòu)體Rectangle後,可通過值接收者或指針接收者聲明方法;1.使用值接收者如func(rRectangle)Area()int,通過rect.Area()直接調(diào)用;2.若需修改結(jié)構(gòu)體,應(yīng)使用指針接收者如func(r*Rectangle)SetWidth(...),Go會(huì)自動(dòng)處理指針與值的轉(zhuǎn)換;3.嵌入結(jié)構(gòu)體時(shí),內(nèi)嵌結(jié)構(gòu)體的方法會(huì)被提升,可直接通過外層結(jié)構(gòu)體調(diào)用;4.Go無需強(qiáng)制使用getter/setter,字

GO中的接口是什麼?如何定義它們? GO中的接口是什麼?如何定義它們? Jun 22, 2025 pm 03:41 PM

在Go語言中,接口是一種定義行為而不指定實(shí)現(xiàn)方式的類型。接口由方法簽名組成,任何實(shí)現(xiàn)這些方法的類型都自動(dòng)滿足該接口。例如,定義一個(gè)Speaker接口包含Speak()方法,則所有實(shí)現(xiàn)該方法的類型均可視為Speaker。接口適用於編寫通用函數(shù)、抽象實(shí)現(xiàn)細(xì)節(jié)和測(cè)試中使用mock對(duì)象。定義接口使用interface關(guān)鍵字並列出方法簽名,無需顯式聲明類型實(shí)現(xiàn)了接口。常見用例包括日誌、格式化、不同數(shù)據(jù)庫或服務(wù)的抽象,以及通知系統(tǒng)等。例如,Dog和Robot類型均可實(shí)現(xiàn)Speak方法,並傳遞給同一個(gè)Anno

如何在GO中使用字符串軟件包中的字符串函數(shù)? (例如len(),strings.contains(),strings.index(),strings.replaceall()) 如何在GO中使用字符串軟件包中的字符串函數(shù)? (例如len(),strings.contains(),strings.index(),strings.replaceall()) Jun 20, 2025 am 01:06 AM

在Go語言中,字符串操作主要通過strings包和內(nèi)置函數(shù)實(shí)現(xiàn)。 1.strings.Contains()用於判斷字符串是否包含子串,返回布爾值;2.strings.Index()可查找子串首次出現(xiàn)的位置,若不存在則返回-1;3.strings.ReplaceAll()能替換所有匹配的子串,還可通過strings.Replace()控制替換次數(shù);4.len()函數(shù)用於獲取字符串字節(jié)數(shù)長度,但處理Unicode時(shí)需注意字符與字節(jié)的區(qū)別。這些功能常用於數(shù)據(jù)過濾、文本解析及字符串處理等場(chǎng)景。

如何使用IO軟件包在GO中使用輸入和輸出流? 如何使用IO軟件包在GO中使用輸入和輸出流? Jun 20, 2025 am 11:25 AM

TheGoiopackageprovidesinterfaceslikeReaderandWritertohandleI/Ooperationsuniformlyacrosssources.1.io.Reader'sReadmethodenablesreadingfromvarioussourcessuchasfilesorHTTPresponses.2.io.Writer'sWritemethodfacilitateswritingtodestinationslikestandardoutpu

See all articles