先聲明,雖然端午節假期將至,但咱們今天聊的真不是破解12306的驗證碼,緣由嘛你懂的。編程
咱們今天 以破解世界上最流行的WordPress驗證碼插件爲例。安全
每一個人都很討厭驗證碼吧?這些煩人的小照片裏有不少文本信息,只有輸入它們後才能訪問網站。人們設計驗證碼系統的初衷是爲了驗證訪問網站的用戶是一個真實的人。但隨着深度學習和計算機視覺技術的進步,咱們很容易就能戰勝這些驗證碼系統。(除非你遇到 12306 那種騷騷的圖片識別驗證,有時真的會陷入絕望)bash
我(本文做者 Adam Geitgey——譯者注)最近讀了一本很棒的書,Adrian Rosebrock 寫的《Deep Learning for Computer Vision with Python 》,在書裏 Adrian 詳述了他怎樣用機器學習繞開了 E-Zpass New York 網站的驗證碼:Adrian 沒有訪問網站生成驗證碼照片的工具的源代碼,因此爲了破解驗證碼,他必須下載幾百個示例圖像,而後手動用它們訓練本身建立的機器學習系統。網絡
但若是咱們想破解一個咱們能訪問源代碼的開源驗證碼系統呢?架構
我去 WordPress 的插件註冊網站上搜了一下「captcha」,第一條搜索結果是「Really Simple CAPTCHA」,有超過1百萬的活動安裝量:框架
最棒的是它提供了源代碼。由於咱們能獲取生成驗證碼的源代碼,那破解它就比較容易了。咱們能夠再提升點難度,變得更有挑戰性一點,好比在限定時間內完成破解。咱們能在15分鐘內徹底破解這個驗證碼系統嗎?試試看!dom
特此聲明:這麼作徹底沒有批評「Really Simple CAPTCHA」插件及其做者的意思。插件做者本身也曾說過這款插件已經不是很安全了,建議換用其它插件。所以這純屬一次好玩的快速技術挑戰。不過,若是你也是這款插件的用戶,或許你真的該換其它的了。機器學習
在「發動進攻」前,咱們先看看「Really Simple CAPTCHA」能生成什麼樣的驗證碼照片。在演示網站上,咱們看到這樣:編程語言
OK,那麼驗證碼彷佛是4個字母和數字的組合形式。咱們在PHP源代碼中驗證一下:ide
public function __construct() {
/* Characters available in images */
$this->chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
/* Length of a word in an image */
$this->char_length = 4;
/* Array of fonts. Randomly picked up per character */
$this->fonts = array(
dirname( __FILE__ ) . '/gentium/GenBkBasR.ttf',
dirname( __FILE__ ) . '/gentium/GenBkBasI.ttf',
dirname( __FILE__ ) . '/gentium/GenBkBasBI.ttf',
dirname( __FILE__ ) . '/gentium/GenBkBasB.ttf',
);
複製代碼
沒錯,它以隨機混合 4 個不一樣字體的形式生成 4 個字的驗證碼。咱們也能發現它從不用字母「O」和「I」,由於這倆字母比較容易被用戶搞混。因此咱們須要識別 24 個英文字母和 10 個阿拉伯數字,也就是 32 個字混合組成的驗證碼。沒問題!
迄今用時:2 分鐘
在正式開始挑戰前,先講一下咱們會用到的工具:
Python 3
Python 是一種頗有意思的編程語言,有不少用於機器學習和計算機視覺的很不錯的程序庫。
OpenCV
OpenCV 是計算機視覺和圖像處理中一個很流行的框架。咱們會用 OpenCV 處理驗證碼照片。它有一個 Python API,因此咱們能夠直接從 Python 中使用它。
Keras
Keras 是一個用 Python 編寫的深度學習框架。用 Keras 能夠只需編寫少許代碼就能很容易地定義、訓練和使用深度神經網絡。
TensorFlow
TensorFlow 是谷歌出品的一款用於機器學習的程序庫。咱們會在 Keras 上的編程,但 Keras 本身並不會實際使用神經網絡邏輯,相反它會在幕後使用谷歌的 TensorFlow 程序庫挑起重擔。
OK,咱們回到挑戰中!
不論是訓練什麼機器學習系統,咱們都要有訓練數據。要破解一個驗證碼系統,咱們但願能有這樣的訓練數據:
如圖示:輸入驗證碼照片用以訓練模型,而後模型可以輸出正確的答案。
由於咱們有這款 WordPress 插件的源代碼,咱們能夠對其修改保存出 1 萬張驗證碼照片,以及每張照片的預期答案。
在花了幾分鐘修改代碼和添加一個簡單的 for 循環後,我得到了一個訓練數據文件夾,包含了 1 萬張 PNG 照片,每張照片都有正確答案做爲照片的文件名:
這是本文惟一一部分沒有給出個人工做示例代碼的地方,由於我考慮再三後以爲,這篇教程純粹出於一個好玩的點子,我不但願有人真的用垃圾信息去刷爆 WordPress 網站。但我會在文末提供我上面生成的這1萬張照片,你們能夠拿去用。
迄今用時:5分鐘
如今,咱們已經獲取了所需的訓練數據,能夠用它們直接訓練一個神經網絡:
有了足夠的訓練數據,這種方法應該能湊效了,但咱們可讓問題更簡單些。問題越簡單,解決問題所需的訓練數據和計算力就越少。畢竟咱們只有 15 分鐘啊!!
幸虧,這款插件生成的驗證碼照片都是隻有 4 個字,因此咱們能夠以某種方式將照片分拆,每一個字做爲一張單獨的小照片,這樣咱們只需訓練神經網絡每次識別一個單獨的字:
我沒時間從頭至尾看一遍這 1 萬張訓練照片,而後用 Photoshop 手動把它們分紅單獨的照片。這要花好幾天功夫,而我只剩下 10 分鐘了。咱們不能僅僅將照片分紅 4 個相同大小的圖塊,由於驗證碼爲了不以下狀況會隨機將字母和數字放在不一樣的水平位置: 幸運的是,咱們依然能將其自動化。在照片處理過程當中,咱們經常須要檢測相同顏色像素的「斑點」(blobs)。圍繞這些連續的像素斑點的界線被稱爲輪廓線。OpenCV 有個內置的findContours()函數,咱們能夠用它檢測這些連續區域。所以咱們以一張原始驗證碼圖像開始:
而後咱們將其轉爲純黑純白的照片(這步叫作闕值化),這樣就能比較容易地發現照片中的連續區域了:
接着,咱們用 OpenCV 的 findContours() 函數檢測照片的單獨部分,它們包含了相同顏色像素的連續斑點: 那麼,把每一個區域保存爲單獨的照片文件就是一件比較簡單的工做了。由於咱們知道每張照片驗證碼應該自左至右包含 4 個字母,咱們能夠根據這點在保存這些字的時候給它們打上標籤。在按這種順序保存字母時,咱們應該以相應的字母名保存每一個字母照片,好比以字母 a 做爲照片 的名字。可是等等,我發現了一個問題!有時驗證碼會出現字母重疊的狀況,好比這樣:
這意味着咱們有可能把兩個字母提取爲一個區域:
若是咱們不解決這個問題,咱們的訓練數據質量會很糟糕。咱們須要解決這個麻煩,但額外再教機器將這兩個壓在一塊兒的字幕識別爲一個字母,會比較麻煩。這裏有個簡單的技巧,若是一個輪廓線區域的寬度遠大於其高度,這意味着可能有兩個字母相互重疊了。在這種狀況下,咱們只需從中間將它們切分,做爲兩個分開的字母:
如今咱們能準確地獲取單個字母了,那就把全部的驗證碼照片過一遍吧。目標是收集每一個字母的不一樣變體。爲了容易整理,咱們能夠將每一個字母保存在其自身文件夾內。
好比,下面是我提取全部字母后,字母「W」的文件夾情況:
迄今用時:10分鐘
由於咱們只需識別單個字母和數字,咱們不須要用很是複雜的神經網絡架構。識別字母比識別阿狗阿貓這樣的複雜照片要容易的多。 咱們會用到一個簡單的卷積神經網絡,它有兩個卷積層和兩個徹底相連的層:
若是你想了解更多卷積神經網絡工做原理的知識,以及爲什麼它們是用於照片識別理想工具,能夠翻閱 Adrian 的書籍《Deep Learning for Computer Vision with Python》。
使用 Keras 只需幾行代碼就能定義這個神經網絡架構:
# 搭建神經網絡!
model = Sequential()
# 第一個卷積層並最大池化
model.add(Conv2D(20, (5, 5), padding="same", input_shape=(20, 20, 1), activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
# 第二個卷積層並最大池化
model.add(Conv2D(50, (5, 5), padding="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
# 包含500個節點的隱藏層
model.add(Flatten())
model.add(Dense(500, activation="relu"))
# 包含32個節點的輸出層 (每一個節點對應咱們預測的可能的字母或數字)
model.add(Dense(32, activation="softmax"))
# 用Keras搭建TensorFlow模型
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
複製代碼
如今能夠訓練它了!
# 訓練神經網絡
model.fit(X_train, Y_train, validation_data=(X_test, Y_test), batch_size=32, epochs=10, ver
複製代碼
在用訓練數據集訓練 10 次後,咱們達到了接近 100% 的準確率。這時,咱們就能隨時自動經過這款工具的驗證碼了!完成任務!
迄今用時:15分鐘(Bingo!)
如今咱們有了一個訓練後的神經網絡,用它破解真正的驗證碼很是簡單:
從使用文中這款WordPress插件的網站中抓取一張真正的驗證碼照片。
使用咱們在建立訓練數據集時所用的方式,將驗證碼照片分紅4個單獨的字母照片。
讓咱們的神經網絡爲每張字母照片作出獨立的預測。
使用4個預測的字母填寫驗證碼。
歡呼吧!
這是咱們的模型破解真正的驗證碼系統時的樣子:
或以命令行模式:若是你想本身動手嘗試,能夠點擊這裏獲取代碼,包含了本文所用的1萬張示例照片和每一步中全部的代碼。查看文件夾中的 README.md 文件,獲取運行代碼的說明。
可是若是你真的想學習每行代碼的運行知識,我仍是強烈建議你看看《Deep Learning for Computer Vision with Python》這本書,講了不少細節知識,還有大量的詳細示例。這是我迄今看到的惟一一本既講解了原理又介紹了怎樣應用於解決實際問題的書籍,去看看吧!
歡迎關注咱們,學習資源,AI教程,論文解讀,趣味項目,你想看的都在這裏!