可參考項(xiàng)目地址:https://github.com/youthcity/graph-captcha
前言
圖形驗(yàn)證碼的主要目是為了解決驗(yàn)證安全問題岔绸。常見的使用場景有渺氧,登錄與注冊(cè)奋刽、短信驗(yàn)證碼下發(fā)、投票专筷、論壇評(píng)論忿墅、搜索等場景。
通過在原有業(yè)務(wù)邏輯上咬像,增加圖形驗(yàn)證碼驗(yàn)證環(huán)節(jié)算撮,有效地扼制了非法攻擊。例如县昂,我們公司曾發(fā)生過肮柜,黑產(chǎn)惡意刷短信接口,導(dǎo)致短信費(fèi)用劇增倒彰,耗盡短信賬號(hào)的資金审洞,影響了正常用戶的使用。因此待讳,為了保障業(yè)務(wù)的正常進(jìn)行芒澜,我們需要對(duì)一些存在安全問題的業(yè)務(wù),增加驗(yàn)證環(huán)節(jié)创淡。
背景
最近痴晦,由于極驗(yàn)提供的圖形驗(yàn)證碼(行為驗(yàn)證)服務(wù)不穩(wěn)定,經(jīng)常出現(xiàn)無法驗(yàn)證的情況辩昆,影響了正常業(yè)務(wù)的進(jìn)行。為了保證業(yè)務(wù)的正常運(yùn)行旨袒,需要對(duì)服務(wù)進(jìn)行容災(zāi)處理汁针,所以調(diào)研了市場上驗(yàn)證碼服務(wù)术辐,作為備選方案。
主要調(diào)研服務(wù)廠商有:
極驗(yàn)接入
業(yè)務(wù)流程時(shí)序圖
簡化一下施无,實(shí)際只有兩步:
- 獲取驗(yàn)證流水辉词;
- 獲取二次驗(yàn)證結(jié)果。
更為詳細(xì)的解釋猾骡,可以參考極驗(yàn)官方文檔瑞躺。
服務(wù)端接入
服務(wù)端我們使用 NodeJS 語言進(jìn)行開發(fā),主要針對(duì)獲取驗(yàn)證流水(API 1)和二次驗(yàn)證(API 2)這兩個(gè)接口進(jìn)行編碼兴想。
服務(wù)端代碼示例:https://github.com/youthcity/graph-captcha/blob/master/src/geetest/geetest_client.ts
Step 1 安裝極驗(yàn) Node SDK
# 安裝官方的依賴包
npm install gt3-sdk
Step 2 從極驗(yàn)后臺(tái)獲取配置并初始化實(shí)例
geetest_id
和 geetest_key
可以從管理后臺(tái)獲取幢哨。
this.client = new Geetest({
geetest_id: config.geetest_id,
geetest_key: config.geetest_key,
});
Step 3 封裝 register
和 validate
方法
為了方便使用,我們對(duì)極驗(yàn)實(shí)例的原函數(shù)進(jìn)行Promise化嫂便。
public async register(params?:RegisterParams) : Promise<RegisterData> {
return new Promise<RegisterData>((reslove, reject) => {
this.client.register(params, (err:any, data:RegisterData) => {
if (err) {
return reject(err);
}
return reslove(data);
});
});
}
public async validate(fallback:boolean, params:ValidateParams) : Promise<boolean> {
return new Promise<boolean>((reslove, reject) => {
return this.client.validate(fallback, {
geetest_challenge: params.geetest_challenge,
geetest_validate: params.geetest_validate,
geetest_seccode: params.geetest_seccode,
}, (err:any, success:boolean) => {
if (err) {
return reslove(false);
}
return reslove(success);
});
});
}
Step 4 API 1 獲取流水并設(shè)置狀態(tài)碼
通過調(diào)用 register
方法捞镰,即可獲取流水參數(shù),需要注意返回結(jié)果中 success
值毙替。因?yàn)榘妒郏诙€(gè)驗(yàn)證方法,需要根據(jù)這個(gè)狀態(tài)值厂画,設(shè)置 is_fallback
(極驗(yàn)官方文檔中凸丸,此變量命名為 fallback
)的值。
const result = await Client.register();
if (result.success === 0) {
ctx.session.is_fallback = true;
}
// result
{
challenge: "fbd7939d674997cdb4692d34de8633c465"
gt: "'eb8880df3cd839d11feee555545699c8'"
new_captcha: true
success: 0
}
當(dāng) success = 1
時(shí)袱院,is_fallback
值設(shè)為 false
屎慢。success = 1
表示極驗(yàn)服務(wù)正常,未進(jìn)行降級(jí)坑填。
若 success = 0
時(shí)抛人,is_fallback = true
。
is_fallback
狀態(tài)值需要保存起來脐瑰,以便用戶進(jìn)行二次驗(yàn)證使用妖枚。此處,我使用session存儲(chǔ)用戶的狀態(tài)值苍在。
Step 5 API 2 二次驗(yàn)證
當(dāng)用戶完整驗(yàn)證后绝页,極驗(yàn)會(huì)返回前端驗(yàn)證參數(shù)。前端需要將驗(yàn)證參數(shù)回傳給后端寂恬,進(jìn)行二次驗(yàn)證续誉。
const { geetest_challenge, geetest_validate, geetest_seccode } = ctx.query;
const is_fallback = ctx.session.is_fallback ? true : false;
const is_pass = await Client.validate(is_fallback, {
geetest_challenge,
geetest_validate,
geetest_seccode,
});
ctx.body = { is_pass };
客戶端接入
以 Web 端為例,可參考項(xiàng)目地址如下:
https://github.com/youthcity/graph-captcha/blob/master/src/static/geetest.html
1)加載客戶端 JS 庫
<script src="http://static.geetest.com/static/tools/gt.js"></script>
2)調(diào)用API 1從后端獲取驗(yàn)證流水
3)初始化極驗(yàn)并綁定到DOM中
4)注冊(cè)驗(yàn)證成功后的回調(diào)
總結(jié)
整體上初肉,極驗(yàn)是調(diào)研的四家中酷鸦,圖形驗(yàn)證碼服務(wù)最好的一家。主要從開發(fā)文檔、接入難度臼隔、管理工具嘹裂、客服響應(yīng)速度這幾個(gè)維度進(jìn)行考慮。極驗(yàn)的接入難度較為簡單摔握,唯一缺點(diǎn)是Web端 JS SDK不支持懶加載寄狼,不能動(dòng)態(tài)進(jìn)行包的加載。
此外氨淌,服務(wù)端開發(fā)者需要妥善的處理好泊愧,獲取極驗(yàn)流水時(shí) success
值的記錄。因?yàn)榉?wù)端二次驗(yàn)證時(shí)盛正,需要根據(jù)此值設(shè)置 is_fallback
值删咱。若設(shè)置不符,將會(huì)導(dǎo)致二次驗(yàn)證失敗蛮艰。且極驗(yàn)的驗(yàn)證參數(shù)具有一次性腋腮,驗(yàn)證一次后,驗(yàn)證參數(shù)將失效壤蚜。例如即寡,相同驗(yàn)證參數(shù),第一次驗(yàn)證通過袜刷,再次驗(yàn)證將會(huì)失敗聪富。
相關(guān)系列文章
- 圖形驗(yàn)證碼服務(wù)接入(一)極驗(yàn)接入
- 圖形驗(yàn)證碼服務(wù)接入(二)防水墻接入
- 圖形驗(yàn)證碼服務(wù)接入(三)騰訊天御接入
- 圖形驗(yàn)證碼服務(wù)接入(四)阿里云盾接入