整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          實(shí)戰(zhàn)筆記—滑動(dòng)驗(yàn)證碼攻防對(duì)抗

          實(shí)戰(zhàn)筆記—滑動(dòng)驗(yàn)證碼攻防對(duì)抗

          索公眾號(hào):暗網(wǎng)黑客

          可領(lǐng)全套網(wǎng)絡(luò)安全課程、配套攻防靶場(chǎng)

          大家好!我是每天為大家分享好文的檸檬!與你一起成長(zhǎng)~

          有需要體系化黑客滲透視頻教程可搜索公眾號(hào):暗網(wǎng)黑客


          一、背景介紹


          在業(yè)務(wù)安全領(lǐng)域,滑動(dòng)驗(yàn)證碼已經(jīng)是國(guó)內(nèi)繼傳統(tǒng)字符型驗(yàn)證碼之后的標(biāo)配。

          眾所周知,打碼平臺(tái)和機(jī)器學(xué)習(xí)這兩種繞過驗(yàn)證碼的方式,已經(jīng)是攻擊者很主流的思路,不再闡述。

          本文介紹的是一個(gè)冷門的繞過思路和防御方案。

          這些積累,均來(lái)自于實(shí)戰(zhàn)之中,希望有用。


          二、思路介紹


          知己知彼,百戰(zhàn)不殆。

          如果不清楚攻擊者的手段,又如何能制定防御方案?


          滑動(dòng)驗(yàn)證碼繞過思路


          漏洞名字:session參數(shù)重復(fù)校驗(yàn)漏洞

          思路介紹:

          此思路來(lái)源于一次對(duì)黑產(chǎn)路徑的溯源復(fù)現(xiàn),由于每次拖動(dòng)滑塊后

          會(huì)發(fā)送一個(gè)Request請(qǐng)求數(shù)據(jù)包到服務(wù)器,服務(wù)器會(huì)驗(yàn)證這個(gè)Request請(qǐng)求數(shù)據(jù)包里攜帶的位移參數(shù)

          來(lái)判斷是否是拖動(dòng)滑塊到了正確的缺口位置。

          而服務(wù)器接收的數(shù)據(jù)包有很多,除了你發(fā)送的,也還會(huì)有其他人發(fā)送的請(qǐng)求

          所以需要一個(gè)session參數(shù)來(lái)作為標(biāo)識(shí)。

          本文中的”rid”值就是一個(gè)session標(biāo)識(shí)。

          其中”rid”值是加引號(hào)的,因?yàn)樗皇且粋€(gè)參數(shù)。

          針對(duì)不同的滑動(dòng)驗(yàn)證碼廠商,可能參數(shù)命名不一樣。


          漏洞詳情:

          在用戶客戶端完成一次正確的驗(yàn)證碼滑動(dòng)后,發(fā)送到服務(wù)器的session參數(shù),會(huì)在服務(wù)器后端,默認(rèn)隱含生成一個(gè)有效時(shí)間和一個(gè)有效次數(shù)的值。

          前提條件是正確的滑動(dòng)。想想這里會(huì)不會(huì)存在問題?

          曾在黑盒測(cè)試中發(fā)現(xiàn),有的滑動(dòng)驗(yàn)證碼廠商的后端邏輯設(shè)計(jì)存在缺陷

          一個(gè)session參數(shù)的有效時(shí)間是10分鐘,有效使用次數(shù)是5次。

          那么如何利用呢?

          這是我在風(fēng)控后臺(tái)的真實(shí)業(yè)務(wù)環(huán)境下,挖掘到的一條黑產(chǎn)繞過滑動(dòng)驗(yàn)證碼的手法。

          思路剖析:

          首先,觸發(fā)滑動(dòng)驗(yàn)證機(jī)制,如下圖類似。

          接著,滑動(dòng)滑塊到正確缺口位置,然后抓包。

          分析數(shù)據(jù)包,尋找session參數(shù)。通過測(cè)試找到”rid”值為session參數(shù)。

          這里再?gòu)?qiáng)調(diào)一下,不同的廠商開發(fā)的代碼,可能對(duì)session參數(shù)命名不一樣。

          比如下圖,”sessionId”值是另一家廠商的session參數(shù),需要我們?nèi)シ治雠袛唷?/p>

          每次滑動(dòng)正確位移后,使用Brupsuite或者其它中間人代理工具

          抓包提取數(shù)據(jù)包里的session參數(shù)(”rid”值),保存到本地。

          因?yàn)榉?wù)器后端默認(rèn)隱含對(duì)我們本地保存的session參數(shù)有一個(gè)有效時(shí)間和有效次數(shù)

          所以我們不需要再去滑動(dòng)驗(yàn)證碼

          直接在session的有效期內(nèi)發(fā)送Request請(qǐng)求數(shù)據(jù)包到服務(wù)器即可驗(yàn)證成功!

          上述操作,我用python編寫了一個(gè)小工具使其流程化。

          全自動(dòng)化過程:調(diào)用打碼平臺(tái)滑動(dòng)驗(yàn)證碼滑塊到正確位置

          使用python的mitmproxy庫(kù)配合正則提取rid,并寫入保存到本地rid.txt。

          最后黑產(chǎn)在實(shí)際批量注冊(cè),薅羊毛或刷贊過程中,遇到觸發(fā)的滑動(dòng)驗(yàn)證碼機(jī)制

          只要session在有效期內(nèi),只需使用python讀取本地的rid.txt內(nèi)容

          調(diào)用requests庫(kù)發(fā)送請(qǐng)求數(shù)據(jù)包,即可繞過滑動(dòng)驗(yàn)證碼。

          至此,滑動(dòng)驗(yàn)證碼繞過思路剖析完成。


          滑動(dòng)驗(yàn)證碼js接口XSS攻擊:

          眾所周知的跨站腳本攻擊—XSS,攻擊手法可能很平常

          但把常用的攻擊手法用在一個(gè)不被人注意的地方,有時(shí)候會(huì)給你意想不到的效果。

          在某次實(shí)戰(zhàn)中,對(duì)一個(gè)安全公司的真實(shí)后臺(tái)登錄頁(yè)面做黑盒測(cè)試。

          首先,給到的只有一個(gè)這種后臺(tái)登錄頁(yè)面。

          對(duì)常規(guī)的地方進(jìn)行一番測(cè)試后,并沒有發(fā)現(xiàn)什么脆弱缺陷。

          既是一家安全公司,安全防護(hù)做的比較高,也是意料之中的事。

          在屏幕前發(fā)了很久的呆,沒有思路的時(shí)候,喜歡倒退,會(huì)回到滲透測(cè)試最本質(zhì)的起點(diǎn),信息收集。

          因?yàn)檫@家公司做的是業(yè)務(wù)安全,了解到這個(gè)后臺(tái)是一個(gè)風(fēng)控?cái)?shù)據(jù)監(jiān)測(cè)的登錄后臺(tái)。

          風(fēng)控面對(duì)的業(yè)務(wù)場(chǎng)景有:注冊(cè)、登錄、瀏覽,支付,活動(dòng)等。

          面對(duì)的威脅有:惡意爬蟲、批量注冊(cè)、薅羊毛、盜號(hào)撞庫(kù)等。

          風(fēng)控策略有:限制注冊(cè)登錄頻率、惡意IP識(shí)別、驗(yàn)證碼等。

          【惡意/正常行為】——【風(fēng)控策略】——【業(yè)務(wù)場(chǎng)景】

          風(fēng)控在其中扮演者中間人的角色,無(wú)論是一個(gè)正常用戶的行為還是群控設(shè)備的惡意行為

          風(fēng)控一方面會(huì)使用策略進(jìn)行過濾行為

          另一方面會(huì)將惡意/正常行為會(huì)被記錄到日志中,進(jìn)而在后臺(tái)展示。

          至此,信息收集完畢,我們整理一下思路。

          我們先看一下手里拿到的測(cè)試頁(yè)面,再對(duì)比分析一下上面那段信息。

          我們發(fā)現(xiàn)這個(gè)登錄頁(yè),是有滑動(dòng)驗(yàn)證碼的。

          而對(duì)比上面的信息,我將紅色框圈出來(lái)的文字,構(gòu)建了一個(gè)我的漏洞測(cè)試想法。

          如果我能控制滑動(dòng)驗(yàn)證碼的輸入,那在后臺(tái)的輸出也可能將是可控的。

          紅色框圈出的最后四個(gè)字,“后臺(tái)展示”,第一反應(yīng)就是用XSS攻擊手法再合適不過了。


          開始行動(dòng)

          首先,找到獲取滑動(dòng)驗(yàn)證碼的js接口

          分析接口參數(shù)

          找到以下參數(shù):

          channel,appId,orgaization,lang,data,sdkver,callback,model,reversion

          黑盒XSS——FUZZ

          刷新驗(yàn)證碼,截?cái)啵グ?/p>

          蠻力碰撞,直接把所有的參數(shù)的值替換成XSS payload,但這樣往往容易失敗,因?yàn)橛行﹨?shù)是硬編碼,一旦更改,服務(wù)器返回的respnse就會(huì)直接顯示reject拒絕。

          舍近求遠(yuǎn),9個(gè)參數(shù),抓9次包,分別替換參數(shù)值成XSS payload,最后,幾分鐘后,成功打到了cookie。

          (因?yàn)閄SS平臺(tái)更新,當(dāng)時(shí)的記錄未保存)

          因?yàn)槭呛诤袦y(cè)試,在漏洞修復(fù)后,內(nèi)部人員把后臺(tái)觸發(fā)漏洞的位置告訴了我。

          下面這張圖是,風(fēng)控后臺(tái)的滑動(dòng)驗(yàn)證碼記錄的行為信息展示欄,未修復(fù)之前這里有一列l(wèi)anguage的值,就是參數(shù)里的”lang”,而插入的XSS payload也就會(huì)出現(xiàn)在這個(gè)位置。

          由于開發(fā)人員未考慮到這個(gè)隱秘的js接口,所以未做過濾防護(hù),且未申明http only,導(dǎo)致XSS payload可以順利執(zhí)行。

          最后,在黑盒測(cè)試盲打XSS中,很大一部分靠運(yùn)氣。

          但使用極限語(yǔ)句再配合一個(gè)超短域名的XSS平臺(tái),會(huì)增加成功率。

          風(fēng)控防御方

          滑動(dòng)驗(yàn)證碼可能會(huì)部署在:注冊(cè)、登錄、反爬、支付等場(chǎng)景當(dāng)中,而黑產(chǎn)繞過滑動(dòng)驗(yàn)證碼的技術(shù)會(huì)有很多種,但凡只要有一種是當(dāng)前風(fēng)控策略未考慮的情況,就可能會(huì)造成比較嚴(yán)重的損失。


          攻擊手法總結(jié)

          從黑產(chǎn)/攻擊者的角度,針對(duì)滑動(dòng)驗(yàn)證碼,我們介紹了一種繞過的思路:session參數(shù)重復(fù)校驗(yàn)漏洞,一種攻擊的手法:JS接口的XSS攻擊。

          那么,從風(fēng)控/防御方的角度,我們?nèi)绾沃贫ǚ朗胤桨改兀?/p>

          才疏學(xué)淺,不敢無(wú)稽之談,只能把平時(shí)實(shí)戰(zhàn)之中碰到的問題,記錄下來(lái),希望有用。


          被動(dòng)防守——針對(duì)攻擊者

          這里沒什么特色,既然是被動(dòng)防守,自然是要避免亡羊補(bǔ)牢。

          針對(duì)諸如XSS等OWASP TOP漏洞,不能依賴開發(fā)的細(xì)心。

          除了在業(yè)務(wù)上線之前,內(nèi)部測(cè)試和攻防測(cè)試;

          還可以在在業(yè)務(wù)上線之后,托管類似國(guó)外Hackone平臺(tái)的國(guó)內(nèi)賞金平臺(tái),或自運(yùn)營(yíng)SRC。

          當(dāng)然,結(jié)合考慮預(yù)算成本。


          主動(dòng)出擊——針對(duì)灰黑產(chǎn)

          主動(dòng)出擊,針對(duì)的是利用滑動(dòng)驗(yàn)證碼,來(lái)精準(zhǔn)識(shí)別灰黑產(chǎn)。

          在一次滑動(dòng)驗(yàn)證碼更新升級(jí)過程中,發(fā)現(xiàn)了一個(gè)新思路。

          原始過程:在用戶完成一次驗(yàn)證碼滑動(dòng)后,將request請(qǐng)求數(shù)據(jù)包發(fā)送給服務(wù)器。

          升級(jí)方案:在服務(wù)器后端升級(jí)滑動(dòng)驗(yàn)證碼的js代碼,使每一個(gè)滑動(dòng)驗(yàn)證碼都在用戶客戶端生成一個(gè)或多個(gè)隨機(jī)參數(shù),這些隨機(jī)參數(shù)需要跟隨request請(qǐng)求發(fā)送到服務(wù)器進(jìn)行一個(gè)簡(jiǎn)單邏輯驗(yàn)證。

          重點(diǎn)在于:正常用戶只有通過滑動(dòng)滑塊發(fā)送的request數(shù)據(jù)包才一定是攜帶隨機(jī)參數(shù)的

          但并不強(qiáng)制要求發(fā)送的request請(qǐng)求攜帶這些隨機(jī)參數(shù)。

          精準(zhǔn)識(shí)別:因?yàn)楹诵娜Φ暮诋a(chǎn)下放的工具,都是通過直接通過發(fā)送request請(qǐng)求數(shù)據(jù)包來(lái)進(jìn)行批量注冊(cè)、刷量刷贊和惡意爬蟲等行為。

          稱之為:“協(xié)議刷”或“打接口”,這種方式效率極高。加上利益化的原因,黑產(chǎn)不會(huì)去在乎過程,只在乎是否結(jié)果能成功。

          升級(jí)的方案:只有通過正常滑動(dòng)滑塊,才能發(fā)送攜帶隨機(jī)參數(shù)的request數(shù)據(jù)包發(fā)到服務(wù)器。

          舊方案:通過以前的舊接口直接發(fā)送不攜帶隨機(jī)參數(shù)的request數(shù)據(jù)包到服務(wù)器也可以通過驗(yàn)證。

          在無(wú)聲無(wú)息升級(jí)后,兩種方案并行運(yùn)行,那么拐點(diǎn)就到來(lái)了。

          是不是就意味著舊方案的驗(yàn)證碼接口過來(lái)的ip,sdk,captcha_flag等數(shù)據(jù)一定都是源于黑產(chǎn)池;

          而升級(jí)方案的驗(yàn)證碼接口過來(lái)的ip,sdk,captcha_flag等數(shù)據(jù)不說(shuō)百分百

          也絕大部分都是來(lái)自正常用戶群體。這就悄然無(wú)聲的就達(dá)到了精準(zhǔn)識(shí)別灰黑產(chǎn)的目的。

          持續(xù)化:在被黑產(chǎn)發(fā)現(xiàn)后,就需要做持續(xù)化更新的對(duì)抗了。

          還是那句,攻防本身就是一場(chǎng)不公平的戰(zhàn)斗,或許只要能大大增加黑產(chǎn)攻擊者的成本,就是有效果的防守。

          三、總結(jié)


          以上理論,皆為實(shí)戰(zhàn)總結(jié)。希望有用。

          如果沒有,我想下篇或許會(huì)有。



          黑客滲透體系化視頻教程免費(fèi)分享

          視頻+進(jìn)群+領(lǐng)工具+靶場(chǎng)-----掃碼直接免費(fèi)領(lǐng)取


          作者:N10th九號(hào)

          轉(zhuǎn)載自:https://www.freebuf.com/articles/web/238038.html

          名稱

          尺寸

          bg.jpg

          552 * 344

          hole.png

          110 * 110

          slider.png

          110 * 110

          hole.png和slider.png為png是因?yàn)閳D片帶有透明度。



          合成目標(biāo)

          最終為前端生成兩張圖片:

          圖片

          名稱

          尺寸

          out_bg.jpg

          552 * 344

          out_slider.png

          110 * 344

          out_slider.png高度為344與背景圖等高。

          也可以打開滑動(dòng)驗(yàn)證Demo頁(yè)面,F(xiàn)12來(lái)觀察圖片。




          實(shí)現(xiàn)

          本機(jī)環(huán)境為.net 6.0.300-preview.22204.3, 裝有Vscode。

          1.創(chuàng)建項(xiàng)目

          創(chuàng)建console項(xiàng)目

          mkdir SlideImageGenerator
          cd SlideImageGenerator
          dotnet new console
          

          2.添加ImageSharp

          dotnet add package SixLabors.ImageSharp
          dotnet add package SixLabors.ImageSharp.Drawing --prerelease
          

          3.vscode打開

          code .
          

          4.引入圖片

          創(chuàng)建Images目錄, 并放入bg.jpg,hole.png,slider.png

          mkdir Images
          

          5.生成out_bg.jpg

          out_bg.jpg生成比較簡(jiǎn)單,直接將hole.png"疊加"到bg.jpg。hole.png灰色區(qū)域是半透明的,因此能夠隱約看到背景。開始!
          清空Program.cs,引入命名空間

          using SixLabors.ImageSharp;
          using SixLabors.ImageSharp.Drawing;
          using SixLabors.ImageSharp.PixelFormats;
          using SixLabors.ImageSharp.Processing;
          using SixLabors.ImageSharp.Drawing.Processing;
          

          生成隨機(jī)坐標(biāo),代表繪制凹槽的起始位置:

          // 生成隨機(jī)坐標(biāo)
          int randomX=100, randomY=120;
          

          加載圖片

          using var backgroundImage=Image.Load<Rgba32>("images/bg.jpg");
          using var holeTemplateImage=Image.Load<Rgba32>("images/hole.png");
          using var sliderTemplateImage=Image.Load<Rgba32>("images/slider.png");
          

          "疊加"holeTemplateImage到backgroundImage。用ImageSharp來(lái)說(shuō)就是以backgroundImage為底,從位置randomX,randomY開始繪制holeTemplateImage。

          backgroundImage.Mutate(x=> x.DrawImage(holeTemplateImage, new Point(randomX, randomY), 1));
          backgroundImage.SaveAsJpegAsync("out_bg.jpg");
          

          運(yùn)行

          dotnet run
          

          運(yùn)行后可以在目錄看到out_bg.jpg

          全部代碼:

          using SixLabors.ImageSharp;
          using SixLabors.ImageSharp.Drawing;
          using SixLabors.ImageSharp.PixelFormats;
          using SixLabors.ImageSharp.Processing;
          using SixLabors.ImageSharp.Drawing.Processing;
          
          // 生成隨機(jī)坐標(biāo)
          int randomX=100, randomY=120;
          
          // 加載圖片
          using var backgroundImage=Image.Load<Rgba32>("images/bg.jpg");
          using var holeTemplateImage=Image.Load<Rgba32>("images/hole.png");
          using var sliderTemplateImage=Image.Load<Rgba32>("images/slider.png");
          
          // "疊加"holeTemplateImage到backgroundImage
          backgroundImage.Mutate(x=> x.DrawImage(holeTemplateImage, new Point(randomX, randomY), 1));
          backgroundImage.SaveAsJpegAsync("out_bg.jpg");
          
          

          6.生成out_slider.png

          out_slider.png生成需要三步:
          a. 從背景圖中扣出凹槽區(qū)域,形成holeMattingImage。
          b. 將slider.png"疊加"到摳圖holeMattingImage。
          c. 將b生成的圖形"疊加"到一個(gè)高為344,寬為110的透明區(qū)域,最終生成out_slider.
          以下具體講解:
          a步驟我直接上代碼,其實(shí)就一個(gè)裁剪操作:

          // backgroundImage已做修改,這里重新加載背景
          using var backgroundImage2=Image.Load<Rgba32>("images/bg.jpg");
          using var holeMattingImage=new Image<Rgba32>(sliderTemplateImage.Width, sliderTemplateImage.Height); // 110 * 110
          // 根據(jù)透明度計(jì)算凹槽圖輪廓形狀(形狀由不透明區(qū)域形成)
          var holeShape=CalcHoleShape(holeTemplateImage);
          // 生成凹槽摳圖
          holeMattingImage.Mutate(x=>
          {
              // 可以這樣理解:
              //   將holeShape想象成一幅110X110的圖片
              //   p=> p.DrawImage(backgroundImage2, new Point(-randomX, -randomY), 1)則表示
              //   從holeShape的-randomX, -randomY開始繪制backgroundImage2(相當(dāng)于backgroundImage2左移randomX,上移randomY)
              //   然后將holeShape繪制結(jié)果疊加到holeMattingImage上
              x.Clip(holeShape, p=> p.DrawImage(backgroundImage2, new Point(-randomX, -randomY), 1));
          });
          holeMattingImage.SaveAsJpegAsync("out_holeMatting.jpg");
          

          裁剪注意傳入的負(fù)坐標(biāo),注釋是我個(gè)人的理解。凹槽的形狀通過CalcHoleShape實(shí)現(xiàn)的,原理是一行行掃描圖像,每行連續(xù)不透明區(qū)域(包含半透明)形成一個(gè)或多個(gè)n*1的矩形。最后將所有小矩形組合形成一個(gè)組合形狀ComplexPolygon

          Func<Image<Rgba32>, ComplexPolygon> CalcHoleShape=(holeTemplateImage)=> { 
              int temp=0;
              var pathList=new List<IPath>();
              holeTemplateImage.ProcessPixelRows(accessor=>
              {
                  for (int y=0; y < holeTemplateImage.Height; y++)
                  {
                      var rowSpan=accessor.GetRowSpan(y);
                      for (int x=0; x < rowSpan.Length; x++)
                      {
                          ref Rgba32 pixel=ref rowSpan[x];
                          if (pixel.A !=0)
                          {
                              if (temp==0)
                              {
                                  temp=x;
                              }
                          }
                          else
                          {
                              if (temp !=0)
                              {
                                  pathList.Add(new RectangularPolygon(temp, y, x - temp, 1));
                                  temp=0;
                              }
                          }
                      }
                  }
              });
          
              return new ComplexPolygon(new PathCollection(pathList));
          };
          

          運(yùn)行,形成out_holeMatting.jpg

          dotnet run 
          

          b. 將slider.png"疊加"到摳圖holeMattingImage,代碼比較簡(jiǎn)單

          // 疊加拖塊模板
          holeMattingImage.Mutate(x=> x.DrawImage(sliderTemplateImage, new Point(0, 0), 1));
          holeMattingImage.SaveAsJpegAsync("out_holeMatting2.jpg");
          

          運(yùn)行,形成out_holeMatting2.jpg

          dotnet run 
          

          c. 將out_holeMatting2疊加到"疊加"到一個(gè)高為344,寬為110的透明區(qū)域

          using var sliderBarImage=new Image<Rgba32>(sliderTemplateImage.Width, backgroundImage2.Height);
          // 繪制拖塊條
          sliderBarImage.Mutate(x=> x.DrawImage(holeMattingImage, new Point(0, randomY), 1));
          sliderBarImage.SaveAsJpegAsync("out_slider.jpg");
          

          運(yùn)行,形成out_slider.jpg

          dotnet run 
          

          全部代碼

          using SixLabors.ImageSharp;
          using SixLabors.ImageSharp.Drawing;
          using SixLabors.ImageSharp.PixelFormats;
          using SixLabors.ImageSharp.Processing;
          using SixLabors.ImageSharp.Drawing.Processing;
          
          // 生成隨機(jī)坐標(biāo)
          int randomX=100, randomY=120;
          
          // 加載圖片
          using var backgroundImage=Image.Load<Rgba32>("images/bg.jpg");
          using var holeTemplateImage=Image.Load<Rgba32>("images/hole.png");
          using var sliderTemplateImage=Image.Load<Rgba32>("images/slider.png");
          
          // "疊加"holeTemplateImage到backgroundImage
          backgroundImage.Mutate(x=> x.DrawImage(holeTemplateImage, new Point(randomX, randomY), 1));
          backgroundImage.SaveAsJpegAsync("out_bg.jpg");
          
          Func<Image<Rgba32>, ComplexPolygon> CalcHoleShape=(holeTemplateImage)=> { 
              int temp=0;
              var pathList=new List<IPath>();
              holeTemplateImage.ProcessPixelRows(accessor=>
              {
                  for (int y=0; y < holeTemplateImage.Height; y++)
                  {
                      var rowSpan=accessor.GetRowSpan(y);
                      for (int x=0; x < rowSpan.Length; x++)
                      {
                          ref Rgba32 pixel=ref rowSpan[x];
                          if (pixel.A !=0)
                          {
                              if (temp==0)
                              {
                                  temp=x;
                              }
                          }
                          else
                          {
                              if (temp !=0)
                              {
                                  pathList.Add(new RectangularPolygon(temp, y, x - temp, 1));
                                  temp=0;
                              }
                          }
                      }
                  }
              });
          
              return new ComplexPolygon(new PathCollection(pathList));
          };
          
          // backgroundImage已做修改,這里重新加載背景
          using var backgroundImage2=Image.Load<Rgba32>("images/bg.jpg");
          using var holeMattingImage=new Image<Rgba32>(sliderTemplateImage.Width, sliderTemplateImage.Height); // 110 * 110
          // 根據(jù)透明度計(jì)算凹槽圖輪廓形狀(形狀由不透明區(qū)域形成)
          var holeShape=CalcHoleShape(holeTemplateImage);
          // 生成凹槽摳圖
          holeMattingImage.Mutate(x=>
          {
              // 可以這樣理解:
              //   將holeShape想象成一幅110X110的圖片
              //   p=> p.DrawImage(backgroundImage2, new Point(-randomX, -randomY), 1)則表示
              //   從holeShape的-randomX, -randomY開始繪制backgroundImage2(相當(dāng)于backgroundImage2左移randomX,上移randomY)
              //   然后將holeShape繪制結(jié)果疊加到holeMattingImage上
              x.Clip(holeShape, p=> p.DrawImage(backgroundImage2, new Point(-randomX, -randomY), 1));
          });
          holeMattingImage.SaveAsJpegAsync("out_holeMatting.jpg");
          
          // 疊加拖塊模板
          holeMattingImage.Mutate(x=> x.DrawImage(sliderTemplateImage, new Point(0, 0), 1));
          holeMattingImage.SaveAsJpegAsync("out_holeMatting2.jpg");
          
          using var sliderBarImage=new Image<Rgba32>(sliderTemplateImage.Width, backgroundImage2.Height);
          // 繪制拖塊條
          sliderBarImage.Mutate(x=> x.DrawImage(holeMattingImage, new Point(0, randomY), 1));
          sliderBarImage.SaveAsJpegAsync("out_slider.jpg");
          

          最后

          完整的滑動(dòng)驗(yàn)證,可以參考LazySlideCaptcha。寫的比較水,歡迎Star。

        1. 本文作者: 破劍冰
        2. 本文鏈接: https://www.cnblogs.com/readafterme/p/16110788.html
        3. 一款小而美的開源滑動(dòng)驗(yàn)證碼組件:打造安全與用戶體驗(yàn)的完美平衡

          ---

          **引言:滑動(dòng)驗(yàn)證碼的必要性與挑戰(zhàn)**

          在日益嚴(yán)重的網(wǎng)絡(luò)安全威脅面前,傳統(tǒng)的字符輸入驗(yàn)證碼已經(jīng)無(wú)法完全阻擋機(jī)器人的惡意攻擊。滑動(dòng)驗(yàn)證碼作為一種新型的驗(yàn)證方式,因其趣味性與較高的人機(jī)識(shí)別度,受到越來(lái)越多網(wǎng)站和應(yīng)用的青睞。本文將詳細(xì)介紹一款開源滑動(dòng)驗(yàn)證碼組件——`sliderCaptcha`,通過解析其實(shí)現(xiàn)原理與應(yīng)用案例,幫助開發(fā)者輕松集成這款小而美的安全組件,提高用戶體驗(yàn)的同時(shí),有效防范自動(dòng)化攻擊。

          ---

          **【第一部分】sliderCaptcha簡(jiǎn)介與安裝**

          **標(biāo)題:輕巧高效,安裝便捷**

          `sliderCaptcha`是一款基于純JavaScript實(shí)現(xiàn)的滑動(dòng)驗(yàn)證碼組件,大小輕便,依賴少,適用于各種Web前端項(xiàng)目。通過npm包管理器進(jìn)行安裝:

          ```bash

          npm install slider-captcha --save

          ```

          或者通過CDN引入:

          ```html

          <script src="https://cdn.jsdelivr.net/npm/slider-captcha/dist/sliderCaptcha.min.js"></script>

          ```

          ---

          **【第二部分】sliderCaptcha核心功能與API詳解**

          **標(biāo)題:功能強(qiáng)大,API友好**

          1. **初始化與配置**:

          ```javascript

          import SliderCaptcha from 'slider-captcha';

          const captcha=new SliderCaptcha({

          container: '#captcha-container', // 驗(yàn)證碼容器ID

          width: 300, // 驗(yàn)證碼寬度,默認(rèn)300px

          height: 100, // 驗(yàn)證碼高度,默認(rèn)100px

          // 其他配置項(xiàng)...

          });

          captcha.init();

          ```

          2. **驗(yàn)證與回調(diào)**:

          ```javascript

          captcha.on('success', (token)=> {

          // 用戶滑動(dòng)驗(yàn)證成功,獲得token,可在此處發(fā)送至服務(wù)器校驗(yàn)

          sendTokenToServer(token);

          });

          captcha.on('error', ()=> {

          // 用戶滑動(dòng)驗(yàn)證失敗,可在此處提示用戶重新驗(yàn)證

          alert('驗(yàn)證失敗,請(qǐng)重新滑動(dòng)驗(yàn)證');

          });

          ```

          3. **刷新驗(yàn)證碼**:

          ```javascript

          captcha.reset(); // 重新生成驗(yàn)證碼

          ```

          ---

          **【第三部分】sliderCaptcha工作原理揭秘**

          **標(biāo)題:人機(jī)識(shí)別與圖像處理**

          1. **隨機(jī)生成缺口與背景**:`sliderCaptcha`會(huì)隨機(jī)生成一張帶有缺口的圖片和一張背景圖片,缺口圖片會(huì)置于背景圖片之上,形成滑動(dòng)拼圖的效果。

          2. **滑塊拖拽與驗(yàn)證**:用戶拖動(dòng)滑塊填補(bǔ)缺口時(shí),組件通過計(jì)算滑塊與缺口的實(shí)際距離與理想距離的誤差,判斷用戶操作的有效性。

          3. **防機(jī)器人策略**:組件內(nèi)置了一定的人工智能識(shí)別策略,如檢測(cè)滑動(dòng)軌跡的速度、加速度、方向等因素,增強(qiáng)對(duì)機(jī)器人的識(shí)別能力。

          ---

          **【第四部分】實(shí)戰(zhàn)案例:在網(wǎng)頁(yè)表單中集成sliderCaptcha**

          **標(biāo)題:從零到一,快速集成**

          在HTML文件中放置滑動(dòng)驗(yàn)證碼容器:

          ```html

          <div id="captcha-container"></div>

          ```

          在JavaScript中初始化并配置滑動(dòng)驗(yàn)證碼組件,同時(shí)處理驗(yàn)證結(jié)果:

          ```javascript

          import SliderCaptcha from 'slider-captcha';

          const captcha=new SliderCaptcha({

          container: '#captcha-container',

          // 其他配置...

          });

          captcha.init();

          captcha.on('success', (token)=> {

          // 發(fā)送token至服務(wù)器驗(yàn)證,并在驗(yàn)證通過后提交表單

          validateTokenOnServer(token).then(valid=> {

          if (valid) {

          submitForm();

          } else {

          captcha.reset();

          }

          });

          });

          captcha.on('error', ()=> {

          // 驗(yàn)證失敗,提示用戶重新驗(yàn)證

          captcha.reset();

          });

          ```

          ---

          **結(jié)語(yǔ):**

          `sliderCaptcha`這款小而美的開源滑動(dòng)驗(yàn)證碼組件,憑借其簡(jiǎn)潔的API、強(qiáng)大的防機(jī)器人功能和出色的用戶體驗(yàn),已經(jīng)成為眾多開發(fā)者在Web前端安全防護(hù)方面的得力助手。借助這款組件,開發(fā)者能夠輕松提升網(wǎng)站或應(yīng)用的安全等級(jí),同時(shí)兼顧用戶體驗(yàn),實(shí)現(xiàn)安全與體驗(yàn)的完美平衡。不論是新手還是資深前端開發(fā)者,都能夠快速上手并融入到自己的項(xiàng)目中,為用戶提供更安全、更有趣的驗(yàn)證體驗(yàn)。


          主站蜘蛛池模板: 亚洲一区二区三区电影| 无码日韩人妻av一区免费| 无码av中文一区二区三区桃花岛| 天美传媒一区二区三区| 91在线看片一区国产| 中文字幕永久一区二区三区在线观看 | 久久se精品动漫一区二区三区| 国模无码视频一区二区三区| 中文字幕一区二区三区精彩视频 | 久久久91精品国产一区二区| 国产精品99无码一区二区| 国产免费av一区二区三区| 欧美成人aaa片一区国产精品 | 91午夜精品亚洲一区二区三区| 九九久久99综合一区二区| 国产婷婷一区二区三区| 日本丰满少妇一区二区三区| 国产精品电影一区二区三区| 相泽南亚洲一区二区在线播放 | 男人的天堂亚洲一区二区三区| 女人18毛片a级毛片一区二区| 国产成人一区二区三区| 久久久无码精品人妻一区| 亚洲av成人一区二区三区观看在线| 一区二区亚洲精品精华液| 色婷婷av一区二区三区仙踪林| 亚洲福利一区二区精品秒拍| 精品少妇ay一区二区三区| 国产99视频精品一区| 人妻互换精品一区二区| 国产亚洲综合精品一区二区三区| 成人欧美一区二区三区在线视频| 无码午夜人妻一区二区不卡视频| 亚洲AV成人精品日韩一区| 国产精品亚洲综合一区在线观看| 一区二区三区中文字幕| 国产亚洲一区二区精品| 欧洲无码一区二区三区在线观看| 国产成人精品日本亚洲专一区| 成人欧美一区二区三区在线视频| 老鸭窝毛片一区二区三区|