【Web安全】通过机器学习破解验证码图片
背景
機器學習,即Machine Learning,屬于AI范疇,是深度學習的父集。 通過如何用機器學習(ML)在15分鐘內破解圖片驗證碼的一篇文章,看到了solving-captchas-code-examples項目。作者通過神經網絡訓練簡單的model來破解了形如下圖的圖片驗證碼:
正文
根據該example,打算拿來練練手。當然不能止步于示例中的簡單驗證碼,隨手打開了幾個網頁,搜集了下如圖所示的彩色的圖片驗證碼:
選定了上述的帶數學算數的圖形驗證碼,接下來開始上路了。 大致的思路是:識別圖片->訓練模型(model)->生產驗證
一、識別圖片
這個識別圖片不是OCR的意思,是相當于你教會計算機去認識圖片中的數字。 比如,你拿一張寫著數字1的圖片,然后告訴計算機,這是數字1。
這些基礎數據,是作為下一步訓練模型的基礎的,大家都知道,時下人工智能里,訓練個好的模型至關重要。我曾一度認為,源代碼是否暴露或者開源已無關緊要,但是經過了大數據的神經網絡模型,才是真正的’核心源碼’。
所以,我們要獲取的驗證碼圖片的基礎數據當然越多越好。這里我的初衷是簡單實驗一下,也不是打造一個專業的破解系統,所以通過爬蟲簡單保存了二三十張圖片,并按照圖片內容手動重命名:
接下來,按照各個基礎數據圖片的文件名,識別、拆分圖片中的各個字符,來分類。這里沒有照搬example中的代碼,通過循環各個圖片,來拆分圖片并分類存儲:
上述是主函數,我又寫了遍歷基礎圖片目錄的方法,來循環調用它:
dicT = {} for (i, captcha_image_file) in enumerate(captcha_image_files):a = main(dicT, captcha_image_file)a = list(a)try:# 這里做個打印if len(a)>=3:if a[1] == 'x':print(a[0]+'*'+a[2]+'='+str((int(a[0])*int(a[2]))))else:print(a[0]+'+'+a[2]+'='+str((int(a[0])+int(a[2]))))except:raise執行后,將基礎數據分門別類到result目錄:
上圖即按照各個字符,拆分圖片,每個子文件夾下,是該字符的各種樣子。 比如./result/9/目錄下,即各個形態的數字9。
二、訓練模型
訓練模型這里,使用的是keras庫。摘一下文檔中的簡述:
Keras 是一個用 Python 編寫的高級神經網絡 API,它能夠以 TensorFlow, CNTK, 或者 Theano
作為后端運行。Keras 的開發重點是支持快速的實驗。能夠以最小的時延把你的想法轉換為實驗結果,是做好研究的關鍵。
如果你在以下情況下需要深度學習庫,請使用 Keras:
- 允許簡單而快速的原型設計(由于用戶友好,高度模塊化,可擴展性)。
- 同時支持卷積神經網絡和循環神經網絡,以及兩者的組合。
- 在 CPU 和 GPU 上無縫運行
該步驟處理的就是./result/下的各個形態的字符文件了。 其大致思路是,先將各個圖片統一大小,然后加入到keras的model進行訓練并生成一個model文件。 該部分代碼同example類似,可以當做utils來使用。
LETTER_IMAGES_FOLDER = "result" MODEL_FILENAME = "captcha_model.hdf5" MODEL_LABELS_FILENAME = "model_labels.dat"# 初始化 data = [] labels = []# 循環result中的圖片 for image_file in paths.list_images(LETTER_IMAGES_FOLDER):# 讀取圖片轉灰度image = cv2.imread(image_file)image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 重置圖片大小,統一為20x20 pixelimage = resize_to_fit(image, 20, 20)# 在原image數組的3位置添加數據,是為了給keras用image = np.expand_dims(image, axis=2)# 獲取文件名label = image_file.split(os.path.sep)[-2]# 加入到數組以備后續訓練模型data.append(image)labels.append(label)# 下述模型訓練的代碼未做改動 data = np.array(data, dtype="float") / 255.0 labels = np.array(labels) (X_train, X_test, Y_train, Y_test) = train_test_split(data, labels, test_size=0.25, random_state=0) lb = LabelBinarizer().fit(Y_train) Y_train = lb.transform(Y_train) Y_test = lb.transform(Y_test) # one-hot編碼保存映射文件 with open(MODEL_LABELS_FILENAME, "wb") as f:pickle.dump(lb, f)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))) model.add(Flatten()) model.add(Dense(500, activation="relu")) model.add(Dense(13, activation="softmax")) model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"]) model.fit(X_train, Y_train, validation_data=(X_test, Y_test), batch_size=13, epochs=10, verbose=1)model.save(MODEL_FILENAME)運行后輸出的captcha_model.hdf5文件即所需的model模型文件。
三、開始驗證
驗證是,首先按照第一步開頭的方式,載入圖片。因為第一步我做了些改動來識別彩色的數字驗證碼,所以此刻也需將要破解的圖片,做相同處理:
MODEL_FILENAME = "captcha_model.hdf5" MODEL_LABELS_FILENAME = "model_labels.dat" # 要破解的圖片文件夾所在目錄 CAPTCHA_IMAGE_FOLDER = "sc"# 載入映射文件和模型 with open(MODEL_LABELS_FILENAME, "rb") as f:lb = pickle.load(f) model = load_model(MODEL_FILENAME)接下里使用模型來識別目標圖片:
captcha_image_files = list(paths.list_images(CAPTCHA_IMAGE_FOLDER)) captcha_image_files = np.random.choice(captcha_image_files, size=(1,), replace=False) print("要識別的圖:\n"+str(captcha_image_files)) # loop over the image paths for image_file in captcha_image_files:# Load the image and convert it to grayscaleimage = cv2.imread(image_file)image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)image = cv2.copyMakeBorder(image, 1, 1, 1, 1, cv2.BORDER_REPLICATE)# 轉換第一次,有淺色情況所以下面轉第二次thresh = cv2.threshold(image, 200, 255, cv2.THRESH_TOZERO)[1]# 將圖片轉為黑白thresh = cv2.threshold(thresh, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]# 找到圖像的輪廓(連續像素塊)contours = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# OpenCV版本適應contours = contours[0] if imutils.is_cv2() else contours[1]# 遍歷四個輪廓中的每一個并提取每個輪廓中的字母,這里封裝統一函數,不作顯示,詳見exampleletter_image_regions = contours_regions(contrours)# 輸出demo,做輪廓的標記output = cv2.merge([image] * 3)predictions = []for letter_bounding_box in letter_image_regions:x, y, w, h = letter_bounding_boxletter_image = image[y - 2:y + h + 2, x - 2:x + w + 2]# 同樣的resizeletter_image = resize_to_fit(letter_image, 20, 20)letter_image = np.expand_dims(letter_image, axis=2)letter_image = np.expand_dims(letter_image, axis=0)prediction = model.predict(letter_image)letter = lb.inverse_transform(prediction)[0]predictions.append(letter)cv2.rectangle(output, (x - 2, y - 2), (x + w + 4, y + h + 4), (0, 255, 0), 1)cv2.putText(output, letter, (x - 5, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.55, (0, 255, 0), 2)# 至此predictions中即為破解解析后的各個字符的list了,接下來是一些便利性的打印,不作展示 print(predictions)效果如圖:
總結
- 通過cv2讀入并轉換圖片,這部分在blog中有不少示例了,所以用的相對熟練。這也是能通過示例example的黑白字母驗證碼引申到彩色的算式驗證碼上的原因所在;
- keras是第一次使用,基本上是照搬的示例了,用的還比較順手。雖不是第一次訓練model,但也是第一次這么流程清晰的使用神經網絡;
【網絡安全學習攻略】
總結
以上是生活随笔為你收集整理的【Web安全】通过机器学习破解验证码图片的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【网络安全】无需SOCKS支持,帮助广大
- 下一篇: 【Web安全】Web开发中常见的安全误区