這些流行的StackOverflow加密代碼片段,很可能會給你的項目帶來災難

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"安全代碼審查是我每天都要做的一項任務,在過去的十三年半中,我一直在做這項任務。在這期間,我審查了幾百個代碼庫,並多次遇到加密代碼。"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"我審查過的加密代碼,經常存在安全問題。我追溯這些僞造的代碼片段,經常會追溯到在StackOverflow上得到高票支持的答案。"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"在本博文中,我會指出這些糟糕的代碼片段,並解釋爲什麼它們是錯誤的。我還會就此給出正確代碼的建議。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我這樣做不是爲了羞辱那些犯了錯誤的人,相反,我想盡自己的一份力量來幫助修復這些問題。作爲一名應用程序安全(AppSec)專家,我真的厭倦了一遍又一遍討論相同的問題。我非常努力地想讓人們做正確的事情:我給他們指出可以安全使用的代碼,例如Luke Park的"},{"type":"link","attrs":{"href":"https:\/\/github.com\/luke-park\/SecureCompatibleEncryptionExamples","title":null,"type":null},"content":[{"type":"text","text":"安全的兼容的加密示例(Secure Compatible Encryption Examples)"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。儘管如此,偶爾還會有團隊進行抵制,甚至在代碼進入生產之前,而這往往是修復這個問題的最佳時機。因此,我不得不花費時間來向他們解釋爲什麼這些代碼是錯誤的,因爲一旦糟糕的加密技術投入生產,就需要一個遷移計劃來修復它。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我相信未來的加密安全問題會少很多。許多加密實現都有改進的API,並在很大程度上由"},{"type":"link","attrs":{"href":"https:\/\/nacl.cr.yp.to\/features.html","title":null,"type":null},"content":[{"type":"text","text":"Dan Bernstein’s NaCl"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"驅動。此外,"},{"type":"link","attrs":{"href":"https:\/\/meta.stackoverflow.com\/questions\/411352\/outdated-answers-accepted-answer-is-now-unpinned-on-stack-overflow","title":null,"type":null},"content":[{"type":"text","text":"StackOverflow不再將選中接受的答案作爲置頂的答案"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":",這使人們有機會投票選出比最初接受的答案更好的答案。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"現在讓我們步入正題。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"示例 1:JAVA中的AES-128 CBC模式"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"鏈接"},{"type":"link","attrs":{"href":"https:\/\/stackoverflow.com\/a\/22445878\/3823831","title":null,"type":null},"content":[{"type":"text","text":"在此"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。在撰寫本文時,這個答案有248個贊成票:它既是最受歡迎的答案,也是被選中的答案。要理解它爲什麼是錯誤的,請查看key和initVector的類型:它們是字符串。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.infoq.cn\/resource\/image\/8b\/6a\/8be3796cdbcb68e615c4c4884785546a.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#333333","name":"user"}}],"text":"密鑰(Keys)和初始化向量(IVs)應該是字節數組,而不是字符串。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"這也是我經常會遇到的問題。"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"如果你使用一個字符串,那麼你就有了一個密碼。密碼不是加密的密鑰,但它們可以使用一個基於密碼的密鑰派生函數來轉換成加密密鑰"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。這裏的做法正是應該被避免的做法:將密碼字符串(被錯誤地標記爲一個“密鑰”)複製到SecretKeySpec結構中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"初始化向量(IV)是字符串的錯誤是一個不那麼常見的錯誤,但它仍然是錯誤的。在我解釋修復方法之前,讓我們先看看調用函數:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.infoq.cn\/resource\/image\/42\/95\/42ee0f98813759776c814f36e8812795.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"硬編碼的密碼(錯誤地標記爲一個“密鑰(key)”)和硬編碼的初始化向量(IV)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"這裏的問題是:"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"硬編碼的密碼(錯誤地標記爲一個密鑰)。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"硬編碼的初始化向量(IV)是字符串類型。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我知道有些人會爭辯說,這只是一個概念證據,任何理智的人都知道如何設置正確的密碼和初始化向量。我的回答是,這些人顯然不以審查代碼爲生,因爲"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"我在著名的地方看到過這樣的代碼,你絕對不會想到這些地方也會犯這樣的錯誤。這是一個真正的問題,並且非常普遍"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"爲了說明密鑰和密碼之間的區別:128位密鑰應該有128位的熵,因此破解它需要"},{"type":"katexinline","attrs":{"mathString":"2^{128}"}},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"次嘗試。這裏的解決方案是從大寫字母、小寫字母和數字集中選擇了密碼。如果他們從這組集合中選擇了一個完全隨機的密碼,那麼這有"},{"type":"katexinline","attrs":{"mathString":"66^{16}"}},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"種可能性,這是"},{"type":"katexinline","attrs":{"mathString":"2^{96}"}},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"量級。這意味着破解的次數最多爲"},{"type":"katexinline","attrs":{"mathString":"2^{96}"}},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"次,但實際上情況更糟,因爲人們不會隨機選擇密碼。我經常看到用於加密的密碼是非常可預測的,後面跟着類似“123!”的字符。令人遺憾的是,人們已經習慣於相信,遵循不推薦的密碼安全指南(“"},{"type":"link","attrs":{"href":"https:\/\/pages.nist.gov\/800-63-FAQ\/#q-b06","title":null,"type":null},"content":[{"type":"text","text":"密碼組合規則"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"”)會使密碼變得安全。事實並非如此,不要這樣做。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"很重要的一點是:不要使用同一個初始化向量IV兩次——這會破壞安全屬性。這在我的博客《"},{"type":"link","attrs":{"href":"https:\/\/littlemaninmyhead.wordpress.com\/2017\/04\/22\/top-10-developer-crypto-mistakes\/","title":null,"type":null},"content":[{"type":"text","text":"開發者十大加密錯誤(Top 10 Developer Crypto Mistakes)"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"》中有解釋。關於這件事,我爭論過很多次了。特別是當有人回答說“沒關係,我們會把IV放到保險庫”時,我的沮喪程度如火箭般沖天而起。不,這並不好:IV並不是設計爲保密的,即使它們被隱藏,也不能修復安全問題。停止使用你自己的加密程序!不幸的是,這麼多人不明白他們正在推出他們自己的加密程序。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"這種代碼還有另一個問題:它使用未經驗證的加密程序。在我的《"},{"type":"link","attrs":{"href":"https:\/\/littlemaninmyhead.wordpress.com\/2017\/04\/22\/top-10-developer-crypto-mistakes\/","title":null,"type":null},"content":[{"type":"text","text":"開發者十大加密錯誤(Top 10 Developer Crypto Mistakes)"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"》博客中,我列舉的第7條就是“假設加密提供了消息的完整性”。我現在接受"},{"type":"link","attrs":{"href":"https:\/\/nacl.cr.yp.to\/secretbox.html","title":null,"type":null},"content":[{"type":"text","text":"NaCl"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"設計中使用的哲學建議:開發者不需要知道兩者的區別,而應該始終使用經過驗證的加密程序,這隱藏了這兩個基礎。在這種情況下,GCM模式下的AES解決了這個問題,CBC模式則沒有。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"用戶"},{"type":"link","attrs":{"href":"https:\/\/stackoverflow.com\/users\/774398\/patrick-favre","title":null,"type":null},"content":[{"type":"text","text":"Patrick Favre"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"在同一個帖子中提供了一個更好的"},{"type":"link","attrs":{"href":"https:\/\/stackoverflow.com\/a\/53051612\/3823831","title":null,"type":null},"content":[{"type":"text","text":"答案"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。你可以自己看一下,如果你像我一樣覺得這是一個好答案,那麼就給它投票吧。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"示例 2:C#中的AES-256 CBC模式"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"代碼在"},{"type":"link","attrs":{"href":"https:\/\/stackoverflow.com\/a\/27484425\/3823831","title":null,"type":null},"content":[{"type":"text","text":"此"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。在撰寫本文時,這是第二受歡迎的答案,擁有117個投票。它不是被選中的答案,但是仍然很受歡迎。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"代碼中的第一個問題是很明顯的,其它問題可能不太明顯。截圖如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.infoq.cn\/resource\/image\/b1\/f7\/b1000a7e45c6b55647e33cabd2yyd3f7.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"一個硬編碼的密碼(錯誤地標記爲密鑰),但IV有什麼問題呢?請往下看。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"是的,另一個硬編碼密碼的例子,它被錯誤地標記爲一個密鑰。但好消息是,他們使用了基於密碼的密鑰派生函數("},{"type":"link","attrs":{"href":"https:\/\/docs.microsoft.com\/en-us\/dotnet\/api\/system.security.cryptography.rfc2898derivebytes?view=net-5.0","title":null,"type":null},"content":[{"type":"text","text":"Rfc2898DeriveBytes"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":",這是使用HMAC_SHA1的PBKDF2),來將其轉換爲真正的密鑰!這很好,但是"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"因爲他們沒有指定迭代次數"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"(你需要在StackOverflow頁面上向右滾動才能看到),"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"使用的默認值1000按照現代標準非常低"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"(即不是很安全)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"現在,讓我們向右滾動,我們看到他們爲Rfc2898DeriveBytes輸入的加鹽內容:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.infoq.cn\/resource\/image\/3c\/78\/3ca270ef5b1a6fd8ed9d574a46958a78.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"某人的名字被用作硬編碼的加鹽(salt)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"硬編碼的加鹽!加鹽不需要保密,但在許多情況下,你不應該使用同一個加鹽兩次。無論如何,最好不要把加鹽硬編碼。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"真實故事:我在一個客戶端的代碼審查中看到了這個片段。我記得,看着加鹽,我想“這對我來說看起來非常有趣”。因此我用C寫了一個程序,將它打印成字符串,結果是“Ivan Medvedev.”。然後我用谷歌搜索了IV,在StackOverflow上找到了這個代碼片段!我只是想知道這個可憐的Ivan Medvedev是誰,他的名字永遠刻在不安全的密碼裏!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"那麼讓我們進入最後一個問題:IV有什麼問題?如果加鹽和密鑰是常量輸入,那麼"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"你總是得到相同的IV輸出"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。因此,你會多次使用相同的IV,這破壞了CBC模式下任何區塊加密的安全性。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"如果作者只是簡單地複製"},{"type":"link","attrs":{"href":"https:\/\/docs.microsoft.com\/en-us\/dotnet\/api\/system.security.cryptography.rfc2898derivebytes?view=net-5.0","title":null,"type":null},"content":[{"type":"text","text":"Microsoft Rfc2898DeriveBytes示例"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":",那麼他們將更接近一個好的答案。但是CBC仍然存在未經驗證的加密問題,微軟的例子迭代次數也太少。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"好一點的消息是,StackOverflow上被選中的答案更好,且擁有更多的投票。但是它也存在問題:Rfc2898DeriveBytes( )的迭代次數太小,並且它們使用未經驗證的加密(CBC模式)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"什麼是好的迭代次數不是一成不變的。"},{"type":"link","attrs":{"href":"https:\/\/pages.nist.gov\/800-63-3\/sp800-63b.html#sec5","title":null,"type":null},"content":[{"type":"text","text":"NIST說"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"“迭代次數應與驗證服務器性能允許的次數相同,通常至少爲10000次迭代。”"},{"type":"link","attrs":{"href":"https:\/\/cheatsheetseries.owasp.org\/cheatsheets\/Password_Storage_Cheat_Sheet.html","title":null,"type":null},"content":[{"type":"text","text":"OWASP說"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"至少爲720000次迭代。 這兩者之間有很大的差距:你可能想"},{"type":"link","attrs":{"href":"https:\/\/security.stackexchange.com\/a\/3993","title":null,"type":null},"content":[{"type":"text","text":"看看Thomas Pornin怎麼說"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。無論如何,以現代標準衡量,任何低於10000的數字都絕對太低了。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"示例 3:JAVA中的TRIPLE DES"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"代碼在"},{"type":"link","attrs":{"href":"https:\/\/stackoverflow.com\/a\/20670\/3823831","title":null,"type":null},"content":[{"type":"text","text":"此"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。這個問題是在2008年提出的,所以你可以原諒其中的一些問題。此時,"},{"type":"link","attrs":{"href":"https:\/\/csrc.nist.gov\/news\/2005\/withdrawal-of-fips-46-3-fips-74-and-fips-81","title":null,"type":null},"content":[{"type":"text","text":"NIST正在推薦AES,但仍在某些情況下允許Triple DES"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"現在,triple DES完全不被推薦"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":",因爲塊太小了,但有時我仍然在代碼中看到它。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"讓我們仔細看看在撰寫本文時獲得68個贊成票的最佳答案:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.infoq.cn\/resource\/image\/f7\/7c\/f7423749b15c9bda8c421a21aaefa87c.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"永遠不要使用MD5,尤其是這裏使用的方式。此外,硬編碼密碼和zero IV也是問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"同樣,這是一個硬編碼的密碼,但這個密碼是使用MD5轉換成密鑰的,"},{"type":"link","attrs":{"href":"https:\/\/en.wikipedia.org\/wiki\/MD5#History_and_cryptanalysis","title":null,"type":null},"content":[{"type":"text","text":"MD5自1996年以來就被棄用了"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。然而,另一個問題是,"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"MD5不是一個基於密碼的密鑰派生函數"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":",因此它不應該在這裏被這樣使用。"},{"type":"link","attrs":{"href":"https:\/\/datatracker.ietf.org\/doc\/html\/rfc2898","title":null,"type":null},"content":[{"type":"text","text":"PBKDF2自2000年以來就成爲標準"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":",本來應該使用它。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"這段代碼使用了一個zero IV,這是我在許多代碼庫中看到的一個非常常見的問題。它也是未經驗證的,但這可能是情有可原的,因爲未經驗證的加密概念在當時並不廣爲人知。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"請不要使用這樣的代碼。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"示例 4:JAVA中的AES"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"代碼在"},{"type":"link","attrs":{"href":"https:\/\/stackoverflow.com\/a\/20796446\/3823831","title":null,"type":null},"content":[{"type":"text","text":"此"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。在撰寫本文時,這個答案有15個贊成票。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.infoq.cn\/resource\/image\/7y\/10\/7yya2b782f3d468c3cb1f442b14a8210.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"你可能注意到,他沒有指定IV。這可能是因爲他"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"沒有指定操作模式"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":",對於大多數加密提供者來說,這意味着使用默認的ECB操作模式。"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"你永遠不應該使用ECB"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":":還記得"},{"type":"link","attrs":{"href":"https:\/\/littlemaninmyhead.wordpress.com\/2017\/04\/22\/top-10-developer-crypto-mistakes\/","title":null,"type":null},"content":[{"type":"text","text":"加密的企鵝圖片"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"嗎?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"在這個帖子中,一個"},{"type":"link","attrs":{"href":"https:\/\/stackoverflow.com\/a\/20796213\/3823831","title":null,"type":null},"content":[{"type":"text","text":"更好的答案"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"有11個贊成票。他選擇了CBC模式和恰當的IV。這不是經過驗證的加密,但這是一個相當合理的答案。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"示例 5:請不要這樣做!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"答案在"},{"type":"link","attrs":{"href":"https:\/\/stackoverflow.com\/a\/1211117","title":null,"type":null},"content":[{"type":"text","text":"此"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。我不打算截圖:這張太糟糕了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"問題是如何在Java中加密一個字符串。在撰寫本文時,被選中的答案有23個贊成票,它試圖實現one-time-pad。在答案的頂部貼了一條警告,建議永遠不要使用它。這是100%正確的:one-time-pads的問題是,實際上它們往往是n-time-pads,其中n > 1。使用pad多次會很容易破解加密。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"這是一個很好的例子,StackOverflow使得票最高的問題置頂的改變取得成效。在撰寫本文時,"},{"type":"link","attrs":{"href":"https:\/\/stackoverflow.com\/a\/43779197","title":null,"type":null},"content":[{"type":"text","text":"目前得票最多"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"的問題有187票。這個答案很好地講解了如何正確進行加密,絕對值得一讀。我唯一要指出的是SecureRandom()混淆,作者知道這是不對的。這裏的風險非常小,但"},{"type":"link","attrs":{"href":"https:\/\/tersesystems.com\/blog\/2015\/12\/17\/the-right-way-to-use-securerandom\/","title":null,"type":null},"content":[{"type":"text","text":"使用SecureRandom()的正確方法非常簡單"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我是在故意挑錯嗎?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"你可能會說我在找的是老代碼,但老實說,這些代碼片段很好地代表了我在日常工作中經常看到的問題。我很少看到加密做得正確的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"你可以通過通過投票給更好的答案來改進加密現狀"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。這比否定上面強調的壞示例更可取,讓我們以友好的方式而不是卑鄙的方式解決這個問題。StackOverflow已經做出更改,來允許我們這樣做。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"爲什麼會有這麼多糟糕的加密實現?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"爲什麼會有這麼多糟糕的加密例子,可以歸爲歷史原因。歷史上,加密社區和開發者社區之間存在很大的脫節。當免費提供的加密庫從1990年代開始可用時,API假定開發者知道如何安全地使用它們。這當然是一個錯誤的假設,再加上使用的複雜性,開發人員花費了大量的精力來實現這些功能。一旦他們有了可用的代碼,他們非常慷慨地與其他人分享——而沒有意識到他們是在一個雷區裏。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"加密的實現的未來看起來很好,但實現的第一步是提高對好答案的認識,並非常清楚哪些答案是無效的。這篇博文是我嘗試成爲幫助做出這種改變的一個小聲音的幾個方面之一。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"附言"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我想感謝reddit用戶cym13"},{"type":"link","attrs":{"href":"https:\/\/www.reddit.com\/r\/crypto\/comments\/pop3ay\/if_you_copied_any_of_these_popular_stackoverflow\/hcy3idx\/","title":null,"type":null},"content":[{"type":"text","text":"對這篇博文的寶貴反饋"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":",這有助於改進最終的結果。我還要感謝"},{"type":"link","attrs":{"href":"https:\/\/cryptohack.org\/","title":null,"type":null},"content":[{"type":"text","text":"cryptohack.org"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"的作者指出本文先前版本中的一個錯誤:對於示例 3,我曾說當時還沒有經過驗證的加密。"},{"type":"link","attrs":{"href":"https:\/\/csrc.nist.rip\/groups\/ST\/toolkit\/BCM\/documents\/proposedmodes\/gcm\/gcm-revised-spec.pdf","title":null,"type":null},"content":[{"type":"text","text":"我錯了"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。所以更新了博客,說它在當時並不廣爲人知。我還要感謝Ivan Medvedev對本博客的回覆。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"StackOverflow上有許多加密義務警員,他們經常就安全問題以及如何解決這些問題發表評論,如"},{"type":"link","attrs":{"href":"https:\/\/stackoverflow.com\/users\/589259\/maarten-bodewes","title":null,"type":null},"content":[{"type":"text","text":"Maarten Bodewes"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"和"},{"type":"link","attrs":{"href":"https:\/\/stackoverflow.com\/users\/1816580\/artjom-b","title":null,"type":null},"content":[{"type":"text","text":"ArtjomB"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。他們是這方面的專家。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"在發佈本博客的第一天,就取得了一個預期的結果:在上面的示例 4中,較好的答案被提升到足以超過較差的答案。感謝幫助實現這一目標的社區讀者。在示例 1的更好的答案也有大量的贊成票,但要超過另一個答案還有很長的路要走。無論如何,我們已經取得了進步!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"原文鏈接"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/littlemaninmyhead.wordpress.com\/2021\/09\/15\/if-you-copied-any-of-these-popular-stackoverflow-encryption-code-snippets-then-you-did-it-wrong\/","title":null,"type":null},"content":[{"type":"text","text":"IF YOU COPIED ANY OF THESE POPULAR STACKOVERFLOW ENCRYPTION CODE SNIPPETS, THEN YOU CODED IT WRONG"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章