AI時代驗證碼的攻與防

導讀:科學技術是第一輩子產力,技術的演進會很大程度上推進業務的升級,同時業務的演進進一步促進技術往更高的層面發展,智能驗證碼的技術發展一樣相似。css

首先,很是高興和你們來分享下我在驗證碼攻防方面的一些實踐和探索。我主要從事反欺詐服務的相關工做,最近一段時間接觸到OpenCV、Tensorflow、Tesseract、ThreeJS等相關技術,在一次分享會上聽到Puppeteer的介紹,通過半年研究將這些技術整合起來,在Node中對市面主流驗證碼作了一輪攻防演練。html

一、CAPTCHA

全自動區分計算機和人類的公開圖靈測試(英語:Completely Automated Public Turing test to tell Computers and Humans Apart,簡稱CAPTCHA),俗稱驗證碼,是一種區分用戶是計算機或人的公共全自動程序。在CAPTCHA測試中,做爲服務器的計算機會自動生成一個問題由用戶來解答。這個問題能夠由計算機生成並評判,可是必須只有人類才能解答。因爲計算機沒法解答CAPTCHA的問題,因此回答出問題的用戶就能夠被認爲是人類。前端

二、簡介

CAPTCHA這個詞最先是在2002年由卡內基梅隆大學的路易斯·馮·安、Manuel Blum、Nicholas J.Hopper以及IBM的John Langford所提出。卡內基梅隆大學曾試圖申請此詞使其成爲註冊商標, 但該申請於2008年4月21日被拒絕。一種經常使用的CAPTCHA測試是讓用戶輸入一個扭曲變形的圖片上所顯示的文字或數字,扭曲變形是爲了不被光學字符識別(OCR, Optical Character Recognition)之類的計算機程序自動識別出圖片上的文數字而失去效果。因爲這個測試是由計算機來考人類,而不是標準圖靈測試中那樣由人類來考計算機,人們有時稱CAPTCHA是一種反向圖靈測試。node

爲了沒法看到圖像的身心障礙者,替代的方法是改用語音讀出文數字,爲了防止語音識別分析聲音,聲音的內容會有雜音或仍能夠被人類接受的變聲。python

根據CAPTCHA測試的定義,產生驗證碼圖片的算法必須公開,即便該算法可能有專利保護。這樣作是證實想破解就須要解決一個不一樣的人工智能難題,而非僅靠發現原來的(祕密)算法,然後者能夠用逆向工程等途徑獲得。jquery

三、做用

防止惡意破解密碼、刷票、論壇灌水、刷頁。有效防止某個黑客對某一個特定註冊用戶用特定程序暴力破解方式進行不斷的登陸嘗試,實際上使用驗證碼是如今不少網站通行的方式(好比招商銀行的網上我的銀行,百度社區),咱們利用比較簡易的方式實現了這個功能。雖然登陸麻煩一點,可是對網友的密碼安全來講這個功能仍是頗有必要,也很重要。但咱們仍是 提醒你們要保護好本身的密碼 ,儘可能使用混雜了數字、字母、符號在內的6位以上密碼,不要使用諸如1234之類的簡單密碼或者與用戶名相同、相似的密碼 ,省得你的帳號被人盜用給本身帶來沒必要要的麻煩。git

驗證碼一般使用一些線條和一些不規則的字符組成,主要做用是爲了防止一些黑客把密碼數據化盜取。github

典型應用場景:web

網站安全:垃圾註冊、惡意登陸、帳號盜用算法

數據安全:數據爬取、數據破壞

運營安全:惡意刷單、虛假秒殺、虛假評論

交易安全:虛假交易、惡意套現、盜卡支付

四、工做原理

同盾智能驗證產品主要針對企業不一樣業務場景,利用生物行爲與機器學習方式提供人機驗證服務,防範非真實人類流量和惡意程序攻擊,幫您下降業務風險。

使用同盾智能驗證碼,告別煩躁脆弱的驗證碼,提高用戶體驗的同時加強安全防護能力。遠離垃圾帖、惡意註冊、垃圾短信、刷票等交互安全煩惱。

其工做流程以下圖所示:

工做流程

五、驗證碼分類

  • 字符型圖片驗證碼

    字符型圖片驗證碼是由阿拉伯數字,英文字母,中文漢字按照必定規律排列,加入干擾噪點以後生產的一張圖片。

  • 行爲式驗證碼

    行爲式驗證碼是一種較爲流行的驗證碼。從字面來理解,就是經過用戶的操做行爲來完成驗證,而無需去讀懂扭曲的圖片文字。常見的有兩種:拖動式與點觸式。

  • 智能驗證碼

    智能驗證碼是一種基於語言認知的人機區分,考驗機器語言認知能力的智能驗證碼,會是將來一段時間內的重要選擇。典型表明有語序點選和空間推理。

5.1使用到的相關技術

  • OpenCV
  • Tensorflow
  • Node
  • Tesseract
  • Python
  • node-tesseract & gm & node-cmd 庫使用
  • ThreeJs & Java 3D

六、字符型圖片驗證碼破解

圖像二值化( Image Binarization)就是將圖像上的像素點的灰度值設置爲0或255,也就是將整個圖像呈現出明顯的黑白效果的過程。

在數字圖像處理中,二值圖像佔有很是重要的地位,圖像的二值化使圖像中數據量大爲減小,從而能凸顯出目標的輪廓。

圖像二值化

6.1使用gm去噪處理

主要是去掉圖像裏的全部干擾信息,好比背景的點,線等。

/**
 * 對圖片進行閾值處理(默認55%)
 * thresholdValue,降噪值
 */
async function disposeImg(imgPath, newPath, thresholdValue) {
	return new Promise((resolve, reject) => {
		gm(imgPath).threshold(thresholdValue || '55%').write(newPath, (err) => {
			if (err) return reject(err);
			resolve(newPath);
		});
	});
}
複製代碼

6.2使用tesseract進行OCR識別

6.3Tesseract介紹

Tesseract(/‘tesərækt/) 這個詞的意思是」超立方體」,指的是幾何學裏的四維標準方體,又稱」正八胞體」,是一款被普遍使用的開源 OCR 工具。

Tesseract 已經有 30 年曆史,開始它是惠普實驗室於1985年開始研發的一款專利軟件,到1995年一件成爲OCR業界內最準確的識別引擎之一。然而,HP不久便決定放棄OCR業務Tesseract今後塵封。數年以後,HP意識到與其將Tesseract束之高閣,還不如貢獻給開源,讓其重煥新生。在 2005 年,Tesseract由美國內華達州信息技術研究所得到,並求助於Google對Tesseract進行改進、消除Bug、優化工做,並開源,其後一直由 Google 贊助進行後續的開發和維護。由於其免費與較好的效果,許多的我的開發者以及一些較小的團隊在使用着 Tesseract ,諸如驗證碼識別、車牌號識別等應用中,不難見到 Tesseract 的身影。

如今Tesseract託管在Github上,你們有興趣能夠上Github上Star或Frok該項目

所謂 OCR(Optical Character Recognition)是指對文本資料進行掃描,而後對圖像文件進行分析處理,獲取文字和版面信息的過程。OCR是圖像識別領域中的一個子領域,該領域專一於對圖片中的文字信息進行識別並轉換成能被常規文本編輯器編輯的文本。

使用Tesseract對降噪後的圖片進行OCR識別,Tesseract支持107種語言,能夠經過node-tesseract代理調用,也能夠直接經過node-cmd執行Tesseract命令進行調用。 node做爲中間層,能夠直接調用封裝好的node包,或者直接執行底層命令,或者調用Python腳本均可以。

經過node-tesseract進行OCR識別

async function recognizeImg(imgPath, options) {
	//tesseract --list-langs,語言選項
	options = Object.assign({
		psm: 7, //-psm 7 表示告訴tesseract code.jpg圖片是一行文本,這個參數能夠減小識別錯誤率,默認爲3
	}, options);

	//console.log(options);

	return new Promise((resolve, reject) => {
		tesseract.process(imgPath, options, (err, text) => {
			if (err) return reject(err);
			resolve(text.replace(/[\r\n\s]/gm, '')); // 去掉識別結果中的換行回車空格
		});
	});
}
複製代碼

6.4tesseract進行OCR識別

async function execute(imgPath) {
	return new Promise((resolve, reject) => {
		NodeCmd.get(`tesseract ${imgPath} stdout -l chi_sim`,
			function (err, data) {
				if (!err) {
					resolve(data);
				} else {
					reject(err);
				}
			},
		);
	});
}
複製代碼

6.5打碼平臺

機器自動識別圖片驗證碼,對簡單的狀況能有較高的準確率,但對干擾多,變形複雜的圖片驗證碼,其準確率會不好。因爲圖片驗證碼重要度增長,複雜的圖片驗證碼被大量使用,致使近年來出現了利用衆包力量實現的人工驗證碼識別平臺。 其工做原理圖下所示:

打碼平臺

字符型圖片驗證碼基本淪陷,驗證碼進入行爲式驗證時代。

七、行爲式驗證碼破解

行爲式驗證的核心思想是利用用戶的「行爲特徵」來作驗證安全判別。整個驗證框架採用高效的「行爲沙盒」主動框架, 這個框架會引導用戶在「行爲沙盒」內產生特定的行爲數據,利用「多重複合行爲判別」算法從特指、視覺、思考等多重行爲信息中辨識出生物個體的特徵, 從而準確快速的提供驗證結果。

可是隨着puppeteer的出現,行爲式驗證碼的防護不在奏效。Puppeteer 的 Logo 很形象,顧名思義像是一個被操控的傀儡、提線木偶。

Puppeteer

Puppeteer 是一個 Node 庫,它提供了高級的 API 並經過 DevTools 協議來控制 Chrome(或Chromium)。通俗來講就是一個 headless chrome 瀏覽器 (也能夠配置成有 UI 的,默認是沒有的)

Puppeteer2

經過puppetter的page.screenshot進行指定區域截屏,若是頁面上未引入jQuery經過page.addScriptTag引入,後面截屏處理須要使用到。利用resemblejs/compareImages進行圖片比對取得滑動距離的圖片,經過canvas將圖片讀入內存,取得最終滑動距離,調用puppetter加入人的行爲模擬,並最終驗證經過。

slider

Puppeteer-無頭瀏覽器簡介

7.1瀏覽器配置

const browser = await puppeteer.launch({
		args: ['--start-maximized'],//讓開啟來的瀏覽器預設最大
		executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
		//executablePath: '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',
		//executablePath: '/Applications/Chromium.app/Contents/MacOS/Chromium',
		//devtools: true,
		headless: false, //這裏我設置成false主要是爲了讓你們看到效果,設置爲true就不會打開瀏覽器
	});
複製代碼

7.2UA相關配置

// 設置瀏覽器信息
	const UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko)' +
		' Chrome/69.0.3497.100 Safari/537.36';

	await Promise.all([
		page.setUserAgent(UA),
		// 容許運行js
		page.setJavaScriptEnabled(true),
		// 設置瀏覽器視窗
		page.setViewport({
			width: 1280,
			height: 748,
		}),
	]);
複製代碼

7.3Puppeteer過人機檢測信息

await page.evaluateOnNewDocument(() => {
		Object.defineProperty(navigator, 'webdriver', {
			get: () => false,
		});

		Object.defineProperty(navigator, 'plugins', {
			get: () => [1, 2, 3, 4, 5],
		});

		const originalQuery = window.navigator.permissions.query;
		return window.navigator.permissions.query = (parameters) => (
			parameters.name === 'notifications' ?
				Promise.resolve({state: Notification.permission}) :
				originalQuery(parameters)
		);
	});
複製代碼

7.4注入jQuery腳本

await page.addScriptTag({url: 'https://cdn.bootcss.com/jquery/3.2.0/jquery.min.js'});
複製代碼

注入jQuery主要是爲了方便Dom操做,在滑動驗證的時候進行圖片截取處理。

7.5截屏處理

// 截屏
	await screenshot(captionPosition, './screenshots/xxx.png');
	await cropImage('./screenshots/xxx.png', './screenshots/xxx.png');
複製代碼

最終經過Puppetter開啓一個瀏覽器,實現自動截屏,自動模擬點擊,自動登陸功能。

行爲式驗證碼基本淪陷,驗證碼進入AI時代。

八、智能驗證碼破解

基於語言認知和結構化知識圖譜的驗證碼,能夠有效效避免攻擊,提升人機識別的準確率。這裏引入OpenCV和Tensorflow兩個工具,主要用於圖片識別和深度學習。

8.1Inception V1

GoogLeNet首次出如今2014年ILSVRC 比賽中得到冠軍。此次的版本一般稱其爲Inception V1。Inception V1有22層深,參數量爲5M。同一時期的VGGNet性能和Inception V1差很少,可是參數量也是遠大於Inception V1。

V1

Inception Module是GoogLeNet的核心組成單元,Inception Module基本組成結構有四個成分。1 1卷積,3 3卷積,5 5卷積,3 3最大池化。最後對四個成分運算結果進行通道上組合。這就是Inception Module的核心思想。經過多個卷積核提取圖像不一樣尺度的信息,最後進行融合,能夠獲得圖像更好的表徵。結構以下圖:

V5

8.2Inception V5圖片打標分類&人臉識別

最新的Inception V5訓練好的模型大概可與識別1000種類別的圖片,經過opencv4nodejs能夠調用訓練好的模型進行圖片分類打標,人臉檢測等各類圖片識別功能。

Google提供的inception5h模型介紹

8.3基於opencv4nodejs完成圖片打標和人臉識別

const cv = require('opencv4nodejs');
const fs = require('fs');
const path = require('path');
const gm = require('gm');
const imageMagick = gm.subClass({imageMagick: true});

const DIRECTION = {
	NorthWest: 'NorthWest',
	North: 'North',
	NorthEast: 'NorthEast',
	West: 'West',
	Center: 'Center',
	East: 'East',
	SouthWest: 'SouthWest',
	South: 'South',
	SouthEast: 'SouthEast',
};

if (!cv.xmodules.dnn) {
	throw new Error('exiting: opencv4nodejs compiled without dnn module');
}

// 載入模型
const inceptionModelPath = './models/tf-inception';
const modelFile = path.resolve(inceptionModelPath, 'tensorflow_inception_graph.pb');
const classNamesFile = path.resolve(inceptionModelPath, 'imagenet_comp_graph_label_strings_cn.txt');

/*const inceptionModelPath = './models/flower';
const modelFile = path.resolve(inceptionModelPath, 'retrained_graph.pb');
const classNamesFile = path.resolve(inceptionModelPath, 'retrained_labels.txt');*/

if (!fs.existsSync(modelFile) || !fs.existsSync(classNamesFile)) {
	console.log('exiting: could not find inception model');
	console.log('download the model from: https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip');
	return;
}
console.log('load models:' + inceptionModelPath);

// 模型和分類標籤
const classNames = fs.readFileSync(classNamesFile).toString().split('\n');
//const net = cv.readNetFromTensorflow(modelFile);
const net = cv.readNetFromTensorflow(modelFile);

const classifyImg = (img) => {
	// inception model works with 224 x 224 images, so we resize
	// our input images and pad the image with white pixels to
	// make the images have the same width and height
	const maxImgDim = 224;
	const white = new cv.Vec(255, 255, 255);
	const imgResized = img.resizeToMax(maxImgDim).padToSquare(white);
	// network accepts blobs as input
	const inputBlob = cv.blobFromImage(imgResized);
	net.setInput(inputBlob);
	// forward pass input through entire network, will return
	// classification result as 1xN Mat with confidences of each class
	const outputBlob = net.forward();
	// find all labels with a minimum confidence
	const minConfidence = 0.05;
	const locations = outputBlob.threshold(minConfidence, 1, cv.THRESH_BINARY).convertTo(cv.CV_8U).findNonZero();
	const result =
		locations.map(pt => ({
				confidence: parseInt(outputBlob.at(0, pt.x) * 100) / 100,
				className: classNames[pt.x],
			}))
			// sort result by confidence
			.sort((r0, r1) => r1.confidence - r0.confidence).map(res => {
			return `標籤:${res.className}、機率:${res.confidence}、百分比:${res.confidence * 100}%`;
		});
	return result;
};

const testData = [];

/**
 * 文件遍歷方法
 * @param filePath 須要遍歷的文件路徑
 */
function fileDisplay(filePath) {
	//根據文件路徑讀取文件,返回文件列表
	const tempFileDir = fs.readdirSync(filePath);

	tempFileDir.forEach(function (filename) {
		//獲取當前文件的絕對路徑
		const filedir = path.join(filePath, filename);
		//根據文件路徑獲取文件信息,返回一個fs.Stats對象
		let tempFile = fs.statSync(filedir);
		if (tempFile.isFile()) {
			let tempObj = {};
			tempObj['image'] = filedir;
			tempObj['label'] = filename;
			testData.push(tempObj);
		}
		if (tempFile.isDirectory()) {
			fileDisplay(filedir);//遞歸,若是是文件夾,就繼續遍歷該文件夾下面的文件
		}
	});
}

fileDisplay(path.resolve('./data'));

testData.forEach((data) => {
	const img = cv.imread(data.image);
	//console.log('%s,%s: ', data.image, data.label);
	//console.log('%s: ', data.image);

	const predictions = classifyImg(img);
	let tempText = '';
	predictions.forEach(p => {
		//console.log(JSON.stringify(p));
		tempText += p + '\n';
	});
	console.log(tempText);

	imageMagick(data.image).gravity(DIRECTION['NorthWest'])  //水印的位置
		.geometry('+10+10') //距離右下角右邊10px下邊10px
		//.fontSize(24)
		.fill('red')
		.pointSize(18)
		//.font('/Library/Fonts/Songti.ttc')
		.font('./font/msyh.ttf')//字體必須正確,不然亂碼或者不顯示中文
		.stroke('red')//文字顏色
		.drawText(15, 10, tempText) //15和10是位置信息   最後一個參數是文字信息
		.write(data.image.replace('/data/', '/process/'), function (err) {
			if (err) {
				return console.error('err--------', err);
			}
			console.log('%s:', data.image, tempText, '打標處理完成!');
		});
	//cv.imshowWait('img', img);
	console.log('---------finish---------');
});
複製代碼

8.4經過遷移訓練來定製 TensorFlow 模型

基於Google Inception-V3 模型,在Windows平臺經過TensorFlow 利用GTX1080進行並行計算學習,獲得本身想要的模型結果。

模型訓練

python訓練腳本

python retrain.py --bottleneck_dir=C:\Users\***\PycharmProjects\flower_photos\bottlenecks --how_many_training_steps=500 --model_dir=C:\Users\***\PycharmProjects\flower_photos\inception --summaries_dir=C:\Users\***\PycharmProjects\flower_photos\training_summaries\basic --output_graph=C:\Users\***\PycharmProjects\flower_photos\retrained_graph.pb --output_labels=C:\Users\***\PycharmProjects\flower_photos\retrained_labels.txt --image_dir=C:\Users\***\PycharmProjects\flower_photos
複製代碼

使用訓練腳本完成圖片識別

const Promise = require('bluebird');
const childProcess = require('child_process');

(async () => new Promise(((resolve, reject) => {
	/**
	 * child.stdin 獲取標準輸入
	 * child.stdout 獲取標準輸出
	 * child.stderr 獲取標準錯誤輸出
	 */
	childProcess.exec('python3 /Users/***/Downloads/python/label_image.py --image /Users/***/Downloads/python/232831_44935.jpg --graph /Users/***/Downloads/python/retrained_graph.pb --labels /Users/***/Downloads/python/retrained_labels.txt', (error, stdout, stderr) => {
		// console.log('error', JSON.stringify(error));
		// console.log('stdout', stdout);
		// console.log('stderr', JSON.stringify(stderr));

		if (stdout.length > 0) {
			console.log(stdout);
			resolve(stdout);
		}
		if (error) {
			console.info(stderr);
			reject(error);
		}
	});
})))();
複製代碼

九、點選、空間推薦驗證破解思路

9.1語序點選

語序點選

9.2空間推理驗證

空間推理驗證

AI驗證碼破解

一、經過Puppetter對目標網站進行數據樣本爬取,爬取問題和答案,創建語序點選,圖標點選,空間推理的樣本庫。基於圖片學習和深度學習,完成樣本庫的模型訓練以後獲得對應的模型數據供後續破解使用。

二、Puppetter訪問對應的網站,喚醒拉起驗證碼,經過Puppetter截圖獲取問題圖片。經過Node服務執行Python腳本完成識圖功能,取得對應的答案。基於獲得的答案經過Puppetter完成驗證,實現目標網站的驗證破解。

至此,智能驗證碼進入AI對抗時代。

十、對抗升級

10.1 3D驗證碼

傳統驗證碼大部分基於二位空間,答案就在當前面,這使得Puppetter模擬線性的路徑相對容易。重新穎性和趣味性安全性三個方面出發,咱們研究了在二維空間模擬三維空間,實現答案的隱藏和解空間難度升級,大大提高了驗證碼的趣味性和安全性。

3D文字

3D圖片

3D旋轉驗證產品特色:

  • 問題面由1面提高到6面
  • 支持文字,圖片等多種形式
  • 答案面默認不在當前用戶可見面
  • 驗證碼默認有一個旋轉速率,增長打碼和機器人截取的難度
  • 答案在面上隨機分佈
  • 答案面轉動的時候,任意角度皆能夠經過,只要答案正常

3D旋轉

3D驗證碼主要技術點:

  • Java服務將face面編碼和face面信息隨機傳遞到網頁端
  • 網頁端基於CSS 3D進行3D立方體繪製,結合編面信息將立方體的6個面繪製完成
  • 獲取空間的相對點位信息用戶答案的驗證,用戶面的轉動角度不影響答案的計算

10.2空間推理驗證

空間推理驗證的安全性高於傳統的滑動和字符型驗證碼,爲了豐富產品線。咱們基於ThreeJS和Java 3D協同完成先後端的驗證識別。

空間推理驗證

空間推理驗證產品特色:

  • Java 3D提供問題和答案建模的數據模型
  • 基於ThreeJS 完成問題和答案的生成,生成服務採用離線策略,確保產品的兼容性和速度
  • 客戶端的驗證碼基於三維轉平面的一張圖片,基於視覺視差實現僞3D
  • 建模數據裏面使用了一些方便人理解,可是機器難以理解的描述語言,增長解空間難度
  • 全部校驗算法都在後端,前端只負責最基礎的展示,安全有保障

空間推理驗證

空間推理驗證技術點:

  • Java 3D負責ThreeJS 3D建模數據的產生,驗證碼的問題和答案數據由後端算法動態生成
  • 基於ThreeJS 完成3D建模,經過燈光,相機,場景的組合獲得三維立體空間展現
  • 基於離線生成3D驗證碼的問題三維空間圖片和答案圖片,問題圖片用戶客戶端展現,答案圖片用於服務端答案驗證
  • 問題結合了語序,語義,空間推理,物理平衡多種維度算法,解空間難度大大提高,加強的AI破解的難度

隨着互聯網技術的進步,黑灰產也逐漸造成了團體化、工具化,對企業形成的危害也愈加嚴重。在與黑產的對抗中,同盾科技反欺詐服務,依託大數據分析技術,提供內容安全,業務安全,雲安全,人機驗證,行爲驗證碼,營銷反做弊,註冊保護,登陸保護,圖像鑑黃,文本過濾,敏感詞過濾,黑產情報等產品用於黑產對抗,爲企業提供安全解決方案。

同盾智能驗證碼已由單點對抗演進到體系對抗,多維度的混編一體對抗,採用新型的驗證形式,提高用戶體驗的同時加強安全防護能力。安全是互聯網公司的生命,同盾驗證碼將協助用戶共同築起這道安全籬笆。

參考資料

驗證碼的前世此生(此生篇)

淺談Web安全驗證碼

Puppeteer-無頭瀏覽器簡介

node識別驗證碼

固定閾值(threshold)

利用Tesseract圖片文字識別初探

tesseract如何限定識別的文字

【模型解讀】Inception結構,你看懂了嗎

經過遷移訓練來定製 TensorFlow 模型

復旦大學肖仰華:12306的驗證碼已再也不安全,將來屬於智能驗證碼

相關文章
相關標籤/搜索