【Web安全】通过机器学习破解验证码图片
背景
機(jī)器學(xué)習(xí),即Machine Learning,屬于AI范疇,是深度學(xué)習(xí)的父集。 通過(guò)如何用機(jī)器學(xué)習(xí)(ML)在15分鐘內(nèi)破解圖片驗(yàn)證碼的一篇文章,看到了solving-captchas-code-examples項(xiàng)目。作者通過(guò)神經(jīng)網(wǎng)絡(luò)訓(xùn)練簡(jiǎn)單的model來(lái)破解了形如下圖的圖片驗(yàn)證碼:
正文
根據(jù)該example,打算拿來(lái)練練手。當(dāng)然不能止步于示例中的簡(jiǎn)單驗(yàn)證碼,隨手打開(kāi)了幾個(gè)網(wǎng)頁(yè),搜集了下如圖所示的彩色的圖片驗(yàn)證碼:
選定了上述的帶數(shù)學(xué)算數(shù)的圖形驗(yàn)證碼,接下來(lái)開(kāi)始上路了。 大致的思路是:識(shí)別圖片->訓(xùn)練模型(model)->生產(chǎn)驗(yàn)證
一、識(shí)別圖片
這個(gè)識(shí)別圖片不是OCR的意思,是相當(dāng)于你教會(huì)計(jì)算機(jī)去認(rèn)識(shí)圖片中的數(shù)字。 比如,你拿一張寫(xiě)著數(shù)字1的圖片,然后告訴計(jì)算機(jī),這是數(shù)字1。
這些基礎(chǔ)數(shù)據(jù),是作為下一步訓(xùn)練模型的基礎(chǔ)的,大家都知道,時(shí)下人工智能里,訓(xùn)練個(gè)好的模型至關(guān)重要。我曾一度認(rèn)為,源代碼是否暴露或者開(kāi)源已無(wú)關(guān)緊要,但是經(jīng)過(guò)了大數(shù)據(jù)的神經(jīng)網(wǎng)絡(luò)模型,才是真正的’核心源碼’。
所以,我們要獲取的驗(yàn)證碼圖片的基礎(chǔ)數(shù)據(jù)當(dāng)然越多越好。這里我的初衷是簡(jiǎn)單實(shí)驗(yàn)一下,也不是打造一個(gè)專業(yè)的破解系統(tǒng),所以通過(guò)爬蟲(chóng)簡(jiǎn)單保存了二三十張圖片,并按照?qǐng)D片內(nèi)容手動(dòng)重命名:
接下來(lái),按照各個(gè)基礎(chǔ)數(shù)據(jù)圖片的文件名,識(shí)別、拆分圖片中的各個(gè)字符,來(lái)分類。這里沒(méi)有照搬example中的代碼,通過(guò)循環(huán)各個(gè)圖片,來(lái)拆分圖片并分類存儲(chǔ):
上述是主函數(shù),我又寫(xiě)了遍歷基礎(chǔ)圖片目錄的方法,來(lái)循環(huán)調(diào)用它:
dicT = {} for (i, captcha_image_file) in enumerate(captcha_image_files):a = main(dicT, captcha_image_file)a = list(a)try:# 這里做個(gè)打印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執(zhí)行后,將基礎(chǔ)數(shù)據(jù)分門(mén)別類到result目錄:
上圖即按照各個(gè)字符,拆分圖片,每個(gè)子文件夾下,是該字符的各種樣子。 比如./result/9/目錄下,即各個(gè)形態(tài)的數(shù)字9。
二、訓(xùn)練模型
訓(xùn)練模型這里,使用的是keras庫(kù)。摘一下文檔中的簡(jiǎn)述:
Keras 是一個(gè)用 Python 編寫(xiě)的高級(jí)神經(jīng)網(wǎng)絡(luò) API,它能夠以 TensorFlow, CNTK, 或者 Theano
作為后端運(yùn)行。Keras 的開(kāi)發(fā)重點(diǎn)是支持快速的實(shí)驗(yàn)。能夠以最小的時(shí)延把你的想法轉(zhuǎn)換為實(shí)驗(yàn)結(jié)果,是做好研究的關(guān)鍵。
如果你在以下情況下需要深度學(xué)習(xí)庫(kù),請(qǐng)使用 Keras:
- 允許簡(jiǎn)單而快速的原型設(shè)計(jì)(由于用戶友好,高度模塊化,可擴(kuò)展性)。
- 同時(shí)支持卷積神經(jīng)網(wǎng)絡(luò)和循環(huán)神經(jīng)網(wǎng)絡(luò),以及兩者的組合。
- 在 CPU 和 GPU 上無(wú)縫運(yùn)行
該步驟處理的就是./result/下的各個(gè)形態(tài)的字符文件了。 其大致思路是,先將各個(gè)圖片統(tǒng)一大小,然后加入到keras的model進(jìn)行訓(xùn)練并生成一個(gè)model文件。 該部分代碼同example類似,可以當(dāng)做utils來(lái)使用。
LETTER_IMAGES_FOLDER = "result" MODEL_FILENAME = "captcha_model.hdf5" MODEL_LABELS_FILENAME = "model_labels.dat"# 初始化 data = [] labels = []# 循環(huán)result中的圖片 for image_file in paths.list_images(LETTER_IMAGES_FOLDER):# 讀取圖片轉(zhuǎn)灰度image = cv2.imread(image_file)image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 重置圖片大小,統(tǒng)一為20x20 pixelimage = resize_to_fit(image, 20, 20)# 在原image數(shù)組的3位置添加數(shù)據(jù),是為了給keras用image = np.expand_dims(image, axis=2)# 獲取文件名label = image_file.split(os.path.sep)[-2]# 加入到數(shù)組以備后續(xù)訓(xùn)練模型data.append(image)labels.append(label)# 下述模型訓(xùn)練的代碼未做改動(dòng) 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)運(yùn)行后輸出的captcha_model.hdf5文件即所需的model模型文件。
三、開(kāi)始驗(yàn)證
驗(yàn)證是,首先按照第一步開(kāi)頭的方式,載入圖片。因?yàn)榈谝徊轿易隽诵└膭?dòng)來(lái)識(shí)別彩色的數(shù)字驗(yàn)證碼,所以此刻也需將要破解的圖片,做相同處理:
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)接下里使用模型來(lái)識(shí)別目標(biāo)圖片:
captcha_image_files = list(paths.list_images(CAPTCHA_IMAGE_FOLDER)) captcha_image_files = np.random.choice(captcha_image_files, size=(1,), replace=False) print("要識(shí)別的圖:\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)# 轉(zhuǎn)換第一次,有淺色情況所以下面轉(zhuǎn)第二次thresh = cv2.threshold(image, 200, 255, cv2.THRESH_TOZERO)[1]# 將圖片轉(zhuǎn)為黑白thresh = cv2.threshold(thresh, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]# 找到圖像的輪廓(連續(xù)像素塊)contours = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# OpenCV版本適應(yīng)contours = contours[0] if imutils.is_cv2() else contours[1]# 遍歷四個(gè)輪廓中的每一個(gè)并提取每個(gè)輪廓中的字母,這里封裝統(tǒng)一函數(shù),不作顯示,詳見(jiàn)exampleletter_image_regions = contours_regions(contrours)# 輸出demo,做輪廓的標(biāo)記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中即為破解解析后的各個(gè)字符的list了,接下來(lái)是一些便利性的打印,不作展示 print(predictions)效果如圖:
總結(jié)
- 通過(guò)cv2讀入并轉(zhuǎn)換圖片,這部分在blog中有不少示例了,所以用的相對(duì)熟練。這也是能通過(guò)示例example的黑白字母驗(yàn)證碼引申到彩色的算式驗(yàn)證碼上的原因所在;
- keras是第一次使用,基本上是照搬的示例了,用的還比較順手。雖不是第一次訓(xùn)練model,但也是第一次這么流程清晰的使用神經(jīng)網(wǎng)絡(luò);
【網(wǎng)絡(luò)安全學(xué)習(xí)攻略】
總結(jié)
以上是生活随笔為你收集整理的【Web安全】通过机器学习破解验证码图片的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【网络安全】无需SOCKS支持,帮助广大
- 下一篇: 【Web安全】Web开发中常见的安全误区