機器學習的「反噬」:當 ML 用於密碼破解,成功率竟然這麼高

雷鋒網 AI 開發者按:過去,讓計算機區分貓和狗被認為是最先進的研究;而現在,圖像分類就像是機器學習(ML)的「Hello World」,可以使用 TensorFlow 在幾行代碼中實現上。在短短的幾年內,機器學習領域已經取得了很大的進展,以至於現在,開發者們可以輕鬆地構建潛在「造福」或「致命」的應用程序。

因此,一位好奇的學者 Tikeswar Naik,通過簡單的實驗和我們討論了這項技術的某一潛在濫用情況——使用 ML 來破解密碼,希望通過這一介紹能夠讓更多人保持警惕,並找到減輕或防止濫用的方法。雷鋒網 AI 開發者將其具體研究內容編譯如下。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

敲鍵盤的,你已經暴露了!

在文章開頭,作者提出了一個大膽的想法:我們能不能僅僅通過聽鍵盤敲擊就知道某人在輸入什麼?而如果這一操作真的可以實現,那它背後的潛在應用,例如:黑客密碼破譯,是否將是非常嚴重的安全隱患呢?(如圖 1 所示)

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 1:聆聽擊鍵(圖片來源:rawpixel.com;eacs.com)

因此,作者參與了一個名為 kido(擊鍵解碼)的項目,來探索這是否可能實現(https://github.com/tikeswar/kido)。

我們將這樣做

作者提出可以將這個問題,作為一個監督的機器學習問題來處理,然後再逐一完成以下所有步驟:

  • 數據收集和準備

  • 訓練與評估

  • 測試和誤差分析(提高模型精度)

  • 結論;GitHub 鏈接

注:在這個項目中用到了 Python、Keras 和 TensorFlow。

1. 數據收集

有很多方法可以收集得到敲擊鍵盤的音頻數據,在這個實驗中,作者為了更好的證明機器學習破譯密碼在日常生活中的可行性,使用了日常使用的鍵盤進行打字,並通過內置麥克風 QuickTime Player 錄製了打字的音頻(圖 2)。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 2:使用筆記本鍵盤製作訓練數據

這種方法有兩個優點:一是數據的可變性較小;而正因數據可變性小,它將有助於我們集中注意力去證明(或反證)這個想法,而無須考慮更多變量。

2. 數據準備

明確了數據來源後,下一步是準備數據,這樣我們就可以把它輸入神經網絡(NN)進行訓練。

QuickTime 將錄製的音頻保存為 MP4。首先我們需要將 mp4 轉換為 wav,因為有很好的 Python 庫可以處理 wav 文件。圖 3 右上角子圖中的每個峰值對應於一個擊鍵)。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 3:將 mp4 轉換為 wav,然後拆分

然後我們使用靜音檢測將音頻分割成單獨的塊,這樣每個塊只包含一個字母。這之後,我們就可以將這些單獨的塊輸入到神經網絡中。

但作者想到了一個更好的方法,他選擇將單個色塊轉換成頻譜圖(圖 4)。現在,我們有了使用卷積神經網絡(CNN),則可以提供更多信息且更易於使用的圖像。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 4:將單個塊轉換為頻譜圖

為了訓練網絡,作者收集了上面描述的 16000 個樣本,確保每個字母至少有 600 個樣本(圖 5)。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 5:數據樣本

然後將數據重新整理,並分成訓練集和驗證集。每個字母有大約 500 個訓練樣本以及 100 個驗證樣本(圖 6)。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 6:訓練-驗證拆分

簡而言之,這就是我們遇到的最大似然比問題,見圖 7。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 7:機器學習問題表示

3. 訓練和驗證

作者使用了一個相當小的簡單網絡架構(基於 Laurence Moroney 的剪刀石頭布示例,https://www.coursera.org/learn/convolutional-neural-networks-tensorflow/),參見圖 8。

其中,輸入圖像被縮放到 150 x 150 像素,並且它有 3 個顏色通道。然後它經過一系列的卷積+合併層,變平(用於防止過度擬合的丟失),被饋送到完全連接的層,最後是輸出層。輸出層有 26 個類,對應於每個字母。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 8:網絡架構

在 TensorFlow 中,模型如下所示:

model = tf.keras.models.Sequential([

# 1st convolution

tf.keras.layers.Conv2D(64, (3,3), activation='relu', input_shape=(150, 150, 3)),

tf.keras.layers.MaxPooling2D(2, 2),


# 2nd convolution

tf.keras.layers.Conv2D(64, (3,3), activation='relu'),

tf.keras.layers.MaxPooling2D(2,2),


# 3rd convolution

tf.keras.layers.Conv2D(128, (3,3), activation='relu'),

tf.keras.layers.MaxPooling2D(2,2),


# 4th convolution

tf.keras.layers.Conv2D(128, (3,3), activation='relu'),

tf.keras.layers.MaxPooling2D(2,2),


# Flatten the results to feed into a DNN

tf.keras.layers.Flatten(),

tf.keras.layers.Dropout(0.5),


# FC layer

tf.keras.layers.Dense(512, activation='relu'),


# Output layer

tf.keras.layers.Dense(26, activation='softmax')

])

以及模型摘要:

___________________________________________________________

Layer (type) Output Shape Param #

====================================

conv2d_4 (Conv2D) (None, 148, 148, 64) 1792

___________________________________________________________

max_pooling2d_4 (MaxPooling2 (None, 74, 74, 64) 0

___________________________________________________________

conv2d_5 (Conv2D) (None, 72, 72, 64) 36928

___________________________________________________________

max_pooling2d_5 (MaxPooling2 (None, 36, 36, 64) 0

___________________________________________________________

conv2d_6 (Conv2D) (None, 34, 34, 128) 73856

___________________________________________________________

max_pooling2d_6 (MaxPooling2 (None, 17, 17, 128) 0

___________________________________________________________

conv2d_7 (Conv2D) (None, 15, 15, 128) 147584

___________________________________________________________

max_pooling2d_7 (MaxPooling2 (None, 7, 7, 128) 0

___________________________________________________________

flatten_1 (Flatten) (None, 6272) 0

___________________________________________________________

dropout_1 (Dropout) (None, 6272) 0

___________________________________________________________

dense_2 (Dense) (None, 512) 3211776

___________________________________________________________

dense_3 (Dense) (None, 26) 13338

====================================

Total params: 3,485,274

Trainable params: 3,485,274

Non-trainable params: 0

訓練結果如圖 9 所示。在大約 13 個 epochs 內,它收斂到 80% 的驗證精度和 90% 的訓練精度。考慮到問題的複雜性和所使用的簡單網絡架構,所得較高的準確性確實也令人感到驚訝。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 9:訓練和驗證準確性

目前的結果看起來很有希望,但這只是字符級的準確性,而不是單詞級的準確性。如要猜測密碼,我們必須正確預測每個字符,而不僅僅是大多數字符!參見圖 10。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 10:猜測密碼需預測每個字符

4. 測試

為了測試這個模型,作者從 rockyou.txt 列表中數字化了另外 200 個不同的密碼,然後嘗試使用我們剛剛訓練的模型預測單詞(圖 11)。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 11:測試模型

圖 12 顯示了測試精度;其中,條形圖顯示了字符級精度(左邊的圖表顯示正確和錯誤的數目,右邊的圖表顯示相同的百分比)。

可以看到,字符級的測試準確率為 49%,而單詞級的測試準確率為 1.5%(即神經網絡在 200 個測試詞中能完全預測正確 3 個單詞)。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 12:測試精度

不過鑑於任務的複雜性,1.5% 字級精度也不算差,不過作者也思考了提高精度的一些方法。

怎樣提高預測精度呢?

首先,作者對測試結果中個別的誤差進行了分析。圖 13 顯示了一些示例測試結果,其中:

  • 第一列包含實際的測試單詞;

  • 第二列包含相應的預測單詞,其中各個字符用顏色編碼以顯示正確(綠色)和錯誤(紅色)預測;

  • 第三列只顯示正確預測的字符,錯誤預測的字符替換為下劃線(以便於可視化)。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 13:數據測試結果

對於「aaron」這個單詞,所使用的模型只得到了一個正確字符;對於「canada」一詞,預測結果有大多數字符是正確的;而對於「lokita」,它的所有字符預測均是正確的。正如圖 12 所示,詞級準確率僅為 1.5%。

但反觀測試示例(圖 14),特別是「canada」,我們意識到它可以正確處理大多數字符,並且非常接近實際單詞。那麼,如果我們把 CNN 的結果通過拼寫檢查呢?

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 14:測試結果展示

這正是作者所做的(圖 15),使用了拼寫檢查器之後,它確實將精確度從 1.5% 提高到了 8%。這也意味著,通過一個相當簡單的模型架構+拼寫檢查器,我們可以正確預測 100 個密碼中的 8 個!

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 15:使用拼寫檢查器後,精確度提高

作者提出進一步假設,如果採用序列模型(RNN?Transformer?),而不是一個簡單的拼寫檢查器,是否我們可以得到單詞檢測層面更高的準確性呢?

但通過仔細查看測試結果(圖 16),可以注意到「a」被預測為「s」,「n」被預測為「b」,等等。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 16:測試示例細節放大

這不禁讓人想到我們在鍵盤上的映射誤差,而且大部分映射誤差(參見圖 17)都與鄰近度相關。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 17:在鍵盤上映射誤差

接下來,作者量化了這種相關性與鄰近性的誤差。圖 18 顯示了麥克風與鍵盤之間按一定比例繪製的按鍵位置。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 18:麥克風和按鍵位置按比例繪製的鍵盤

圖 19 顯示了一些示例字母在數字化鍵盤上的錯誤類比圖。圖中,左上角的圖顯示「a」被錯誤地預測為「z」、「x」、「y」、「k」、「s」、「w」或「q」。其他子圖的解釋類似。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 19:樣本字母的誤差圖

從圖 19 中,我們可以清晰看到,該預測誤差與臨近度相關。然而,我們能否得到一個更為量化的衡量標準呢?

為了得到這一量化標準,作者將 d_ref 設為參考字母與 mic 的距離,d_predicted 為預測字母與 mic 的距離,d 為 d_ref 與 d_predicted 之差的絕對值(見圖 20)。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 20:一些參量定義

圖 21 為所得誤差直方圖。我們可以看到一個非常明顯的趨勢,即大多數誤差來自臨近處。這也意味著我們可以通過更多的數據、更大的網絡或能夠更好地捕獲這些數據的網絡架構來提高模型的準確性。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 21:誤差相關的直方圖

但是麥克風的位置是否也是誤差的來源之一呢?誤差與按鍵離麥克風的距離有關嗎?

為了研究這一點,作者也繪製了關於圖 12 中的誤差圖,使得 X 軸上的字母與 MIC 的距離增加(參見圖 22)。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 22:麥克風位置與誤差之間關係的直方圖

從圖中,我們可以發現誤差與按鍵離麥克風的位置之間並沒有很強的相關性,這也可以證明誤差與麥克風位置基本是無關的。

不過通過圖 22 展示的結果,作者也發現一個非常重要信息,即一個人可以把麥克風放在任何地方監聽擊鍵,然後進行黑客攻擊。這一發現確實令人毛骨悚然!

模型存在的一些小 BUG

在這項研究中,作者因為只是想驗證是否能僅通過聽鍵盤敲擊聲音,從而進行黑客攻擊的想法,因此在具體實驗中做了很多簡化。

下面是作者提出的一些關於改進模型以處理更復雜和真實的場景的建議:

  • 正常的打字速度→具有挑戰性的信號處理(隔離單個擊鍵)。因為在這項研究中,作者使用了較慢的速度敲寫數據內容。

  • 任何按鍵→具有挑戰性的信號處理(大小寫?Shift 功能鍵?…)。因為在這項研究中,作者只使用了小寫字母(不包括大寫字母、數字、特殊字符、特殊擊鍵等)。

  • 背景噪聲→添加噪聲。因為在本研究的記錄數據時,只有一些車輛經過時會出現部分簡單和輕微的背景噪聲,但沒有複雜的背景噪聲(例如:餐廳背景噪聲等)。

  • 不同的鍵盤和麥克風設置+不同的人打字→更多的數據+數據增強+更大的網絡+不同的網絡架構可能有助於改進模型。

最後,作者還提出「我們是否能採用其他振動信號代替音頻信號」一有趣的想法。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

圖 23:其它振動信號

最終我們得到這樣的結論

考慮到這項研究的簡化,作者得出了這樣兩個結論:

  • 通過擊鍵聲音破解敲寫內容是有可能實現的;

  • 通過少量的數據和簡單的 CNN 架構+拼寫檢查,我們可以獲得不錯的單詞級準確率(本研究中為 8%);

  • 簡單的拼寫檢查可以提高單詞級別的準確性(在本例中從 1.5% 提高到 8%);

  • 誤差與其他鍵的接近相關;

  • 誤差似乎與麥克風位置無關。

机器学习的「反噬」:当 ML 用于密码破解,成功率竟然这么高

原文鏈接:

https://towardsdatascience.com/clear-and-creepy-danger-of-machine-learning-hacking-passwords-a01a7d6076d5

GitHub 鏈接:

https://github.com/tikeswar/kido

雷鋒網 AI 開發者


分享到:


相關文章: