我如何防止私鑰從程式碼中外流?

看到寶博士錢包私鑰外流事件後,來分享一點我的心得

動機

前幾天 寶博士 葛如鈞 的其中一個以太坊錢包的私鑰被學生意外上傳到 GitHub,
並且被專門在 GitHub 中搜索私鑰的攻擊者發現,
導致錢包中的 ETH 被攻擊者取走。

幸運的是,
在智能合約大神 Jeff Hu 與 Lee Ting Ting 的協助下,
成功救回了錢包中珍貴的 CryptoKitties,
讓損失沒有擴大。

事件的過程可以參閱 寶博士 與 Jeff 的文章:

我學習開發以太坊智能合約、DApp 至今大約一年多,
曾經針對 CryptoKitties 和 Fomo3D 寫過幾個 bot 來自動發送交易,
過程中也遇過差點洩漏私鑰的情況,
以下我會總結我防止私鑰外流的方法,
也歡迎大家留言交流想法!

如果不得已要在程式中引入私鑰,可以如何防止私鑰外流?

1. 讓私鑰從一開始就不可能被放入 git repo (程式庫)

有些人為求方便,
會在程式中開一個變數就把私鑰放進去。

const privateKey = "xxx";

他們可能會說:
「這個程式不會公開的,不用擔心!」
「就算要公開,也會先刪掉私鑰再上傳啦,不用擔心!」

但我對自己沒有自信,
我無法保證自己永遠都記得這些規定,
所以我這樣做:

  1. 把私鑰獨立放在一個檔案(例如 config.js 或 .env 或寫進 environment variable 或放在你認為系統內安全的地方),在主程式中 import 這個檔案/變數來取得私鑰。
  2. 就算還沒有打算用 git,也先開一個 .gitignore 把上述的檔案 ignore 掉,可完全避免未來將含有私鑰的檔案誤加進 commits。

如此可以讓任何對這個 project 沒有記憶的人也不會誤傳私鑰上 GitHub。

如果你已經不小心將私鑰 commit 進 local git repo,
只發新的 commit 把含有私鑰的檔案修改或刪掉是不夠的,
你可以參考 GitHub Help — Removing sensitive data from a repository
在 push 到 public GitHub repo 之前把私鑰從 git 的歷史中移除,
或是乾脆砍掉 .git/ 重新 git init。

2. 私鑰先加密過再存放

如果你直接將私鑰以明文(未加密)的形式存放在檔案中,
那麼一旦攻擊者取得了瀏覽這個檔案的權限,
他就能直接看到你的私鑰了。

所以更安全的做法是:
先將私鑰加密過再存進檔案
在程式執行時再輸入密碼來解密取得私鑰
如此就能避免私鑰直接從檔案中暴露了。

在 web3 中有實作 encrypt function 可以將私鑰以你自訂的密碼加密並輸出成 keystore object,
也有 decrypt function 可將 keystore object 解密並輸出私鑰。
這兩個 functions 可以協助你實現上述的安全做法。

雖然 keystore object 暴露也不會立刻導致私鑰暴露,
但如果你使用的密碼長度不夠,
攻擊者還是可以暴力破解出你的私鑰,
所以還是該以對待私鑰的態度來對待 keystore object。

3. 同一個私鑰不要在多個地方使用

我不建議把已經在其他地方(例如 MetaMask)使用的私鑰複製到你的程式裡使用,
不只因為這樣會增加這個私鑰外流的機率,
也因為當你在兩個地方同時發送交易時,
如果沒設定好 nonce 會害其中一邊的交易失敗。

我建議的做法是:
為這個 project 產生一個新的私鑰,
再從別的錢包把 ETH 傳進來。
同時遵守一個原則:
私鑰越容易外流的錢包裡應該放越少資產

以 2018 Q4 的情況,
鏈上傳送 ETH 的成本通常都能低於 0.02 USD,
所以不用怕費用昂貴。

如果你只是希望在程式裡或其他錢包 App 中可以查看某一個地址裡面的資產,
那通常也不需要把私鑰到處傳,
只需要導入地址就能檢視裡面的資產了。

如果你覺得錢包裡的資產很少,
就算全部遺失也沒關係,
那你要違反這篇說的全部原則也是可以啦 XD

4. 在程式中用過的私鑰用完即丟

當一個 project 不再運作的時候,
就應該把私鑰從檔案中刪除以免將來外流,
並且最好把這個錢包中的資產全部轉移出來,
這個私鑰就不再使用,
永絕後患。

定期檢查一下是不是有私鑰殘留在已經不用的程式碼或 App 裡,
現在就是你檢查的時機。

如何避免在程式中引入私鑰?

怕私鑰從程式中外流,
最好的方法就是讓你的程式根本碰不到私鑰。

你可以用一個有提供 API 的硬體錢包(例如:Trezor, Ledger),
讓「用私鑰簽署交易」全程都在硬體錢包裡做。

API 的用法可參考:

最後只需要把硬體錢包卸除,
就能完全避免你的私鑰外流了!

如何在自己的錢包被攻擊時第一時間收到通知?

Etherscan 有提供追蹤錢包的功能,
你可以在 Etherscan 上註冊一個帳號
登入後可按 My Address -> Watch list -> Add New Address,
增加你要追蹤的錢包地址。

完成後點 Edit

選擇你想要追蹤的交易形式並 Save Changes

這樣當有任何交易進出這個地址時,
你就會收到 email 通知了!

結語

如果你跟我一樣相信以下敘述:

  • 我的記性不好
  • 意外總是有機會發生
  • 用一時的麻煩換來長久的安全,非常划算

你就自然會知道該怎麼避免意外、減少損失了。

如果你有更安全的保護私鑰的做法,
歡迎留言讓大家都能受惠!


如果你喜歡這篇文章,
除了給我 Medium 式的拍手,
也歡迎透過下方的 LikeButton 給我最多 5 個 Like 拍手,
我將能獲得來自 LikeCoin 的獎勵!