JSとPuppeteerで「slider CAPTCHA」をバイパスする方法
次のトピックは「slider CAPTCHA」をJSで解決する方法です
スパムはウェブサイトの所有者にとって大きな問題です。その一方でCAPTCHAは私をひどくイライラさせるもので、ユーザーエクスペリエンスに悪影響を及ぼします。
CAPTCHAは最悪です。素直に認めましょう。人間かどうか検証する方法はたくさんありますが、どの方法も最悪です。
近年、BOTは日々賢くなっており、BOTからウェブサイトを守ることは困難です。ですが多くの空き時間と十分なリソースがあれば、ほぼどんなCAPTCHAでもバイパスできます。
PuppeteerがreCAPTCHAを突破するためのプラグインがあります。 CAPTCHA突破サービスを提供している会社が存在します。たとえば2Captchaがあります。 Puppeteerと2Captchaの使い方はこちらです。
代替手段として「スライドして確認する」CAPTCHA を実装した ウェブサイトがあります。しかし、なぜ単純なスライダーCAPTCHAを使う人がいるのでしょうか?
理由は次のとおりです。
- ほとんどのBOTはJSを実行しないため、BOTを止めることができる
- スライダーはユーザーフレンドリー
- スライダーにはモバイルユーザー向けの自然なスワイプアクションがある
したがって、スライダーは人間には使いやすくシンプルなものです。しかし、もっとスマートなBOTで簡単に解決することもできます。
いくつかのスライダーCAPTCHAをバイパスしてみましょう。
スライドして送信
「スライドして送信」フォーム用のjQueryプラグインです。これはフォーム上でスパムを防止するためのCAPTCHAの代替手段です。
まず、入力欄にデータを入力します。このスライダーを動かすには次のことを行う必要があります。
- ハンドルの中心にマウスを置く
- マウスをクリックする
- マウスを動かす
- マウスを離す
完了。こんなに簡単なのです。
const puppeteer = require('puppeteer' )
async function run () {
const browser = await puppeteer. launch({
headless: false,
defaultViewport: { width: 1366, height: 768 }
})
const page = await browser.newPage()
await page.goto('http://kthornbloom. com/slidetosubmit/')
await page.type('input[name="name"]', ‘Puppeteer Bot')
await page.type('input[name="email"]', 'js@automation.com')
let sliderElement = await page.$('.slide-submit' )
let slider = await sliderElement.boundingBox()
let sliderHandle = await page.$('.slide—submit—thumb' )
let handle = await sliderHandle.boundingBox()
await page.mouse.move(handle.x + handle.width / 2, handle.y + handle.height / 2)
await page.mouse.down()
await page.mouse.move(handle.x + slider.width, handle.y + handle.height / 2, { steps: 10 })
await page.mouse.up()
// success!
await browser.close()
}
run()
完了。こんなに簡単なのです。
Dipbit登録スライダー
Dipbitはデジタル通貨取引サイトです。ログインページと登録ページの両方に「スライドして確認」要素があります。
Dipbitは少し賢くできているので、Puppeteerの実行を隠すコードを追加する必要があります。
const puppeteer = require('puppeteer')
async function run() {
const browser = await puppeteer. launch({
headless: false
defaultViewport: { width: 1366, height: 768 }
})
const page = await browser.newPage()
await page.evaluateOnNewDocument ( () => {
Object.definaProperty(navigator, 'webdriver', {
get: () => false
}}
})
await page.goto('https://www.dipbit.com/auth/login')
await page.type('#email', 'js@automation.com')
await page.type('#password’, 'password123')
let sliderElement = await page.$('.slidetounlock')
let slider = await sliderElement.boundingBox()
let sliderHandle = await page.$('.slidetounlock')
let handle = await sliderHandle. boundingBox()
await page.mouse.move(handle.x + handle.width / 2, handle.y + handle.height / 2)
await page.mouse.down()
await page.mouse.move(handle.x + slider.width, handle.y + handle.height / 2, { steps: 50 })
await page.mouse.up()
// success!
await browser.close()
}
run()
Taobao
タオバオはAlibabaが運営する中国のオンラインショッピングサイトです。Dipbitと同様に登録時にスライダーが表示されます。唯一の違いは登録フォームがiframe内にあることです。しかしPuppeteerにとってそれは問題ではありません。
const puppeteer = require('puppeteer' )
async function run() {
const browser = await puppeteer. Launch({
headless: false,
defaultViewport: { width: 1366, height: 768 }
})
const page = await browser.newPage()
await page.evaluateOnNewDocument(() => {
Object.defineProperty(navigator, 'webdriver', {
get: () => false
})
])
await page.goto('https://world.taobao.com/markets/all/sea/register' )
let frame = page.frames()[1]
await frame.waitForSelector('.nc_iconfont.btn_slide')
const sliderElement = await frame.$('.slidetounlock')
const slider = await sliderElement.boundingBox()
const sliderHandle = await frame.$('.nc_iconfont.btn_slide')
const handle = await sliderHandle. boundingBox()
await page.mouse.move(handle.x + handle.width / 2, handle.y + handle.height / 2)
await page.mouse.down()
await page.mouse.move(handle.x + slider.width, handle.y + handle.height / 2, { steps: 50 })
await page.mouse.up()
// success!
await browser.close()
}
run()
パズル付きスライダーCAPTCHA
「スライドして確認する」Vue コンポーネントに遭遇しました。
人間にとっては簡単で、BOTにとっては難しいはずのものです。
この検証メソッドは画像を取得し、2つのキャンバスと1つのスライダーを作成します。パズルのピースで初期画像をレンダリングします。ユーザーがスライダーを動かすと、パズルのピースが一致します。 2つのピースが一致したらユーザーはスライダーを放す必要があります。これで検証は終了します。
このCAPTCHA はパズルの位置をランダム化してBOTを混乱させます。
ここではMLやOCRのような派手なことはしたくなかったので、そのスライダーを少しずつ動かして、結果の画像と最初の画像を比較します。
rembrandt.js libraryライブラリを使用して画像を比較します。差が最も小さい画像を見つけたら、スライダーを最適な位置に移動し、マウスを離します。
const puppeteer = require ('puppeteer')
const Rembrandt = ('rembrandt')
async function run () {
const browser = await puppeteer. Launch({
headless: false,
defaultViewport: { width: 1366, height: 768 }
})
const page = await browser.newPage()
let originalImage = ' '
await page.setRequestInterception(true)
page.on('request', request => request.continue())
page.on('response', async response => {
if (response. request().resourceType() === 'image')
originalImage = await response.buffer().catch(() => {})
})
await page.goto('https://monoplasty.github. io/vue—monop lasty-slide-verify/')
const sliderElement = await page.$('.slide-verify-slider'
const slider = await sliderElement.boundingBox()
const sliderHandle = await page.$('.slide-verify-slider—mask-item' )
const handle = await sliderHandle. boundingBox()
let currentPosition = @
let bestSlider = {
position: 0,
difference: 100
}
await page.mouse.move(handle.x + handle.width / 2, handle.y + handle.height / 2)
await page.mouse.down()
while (currentPosition < slider.width - handle.width / 2) {
await page.mouse.move(
handle.x + currentPosition,
handle.y + handle.height / 2 + Math.random() * 10 - 5
)
let sliderContainer = await page.$('.slide-verify')
let sliderImage = await sliderContainer.screenshot()
const rembrandt = new Rembrandt ({
imageA: originalImage,
imageB: sliderImage,
thresholdType: Rembrandt. THRESHOLD_PERCENT
})
let result = await rembrandt.compare()
let difference = result.percentageDifference * 100
if (difference < bestSlider.difference) {
bestSlider.difference = difference
bestSlider.position = currentPosition
}
currentPosition += 5
}
await page.mouse.move(handle.x + bestSlider.position, handle.y + handle.height / 2, { steps: 10 })
await page.mouse.up()
// success
await browser.close()
}
run()
クールな部分を1つ逃した場合。実際のユーザーのマウスの動きをエミュレートするために、Y軸のスライダーの動きをランダム化します😎
await page.mouse.move(
handle.x + currentPosition,
handle.y + handle.height / 2 + Math.random() * 10 - 5
)
すべてのコード例はgithub repoにあるので、必要な要素を自由にコピーしてください。
結論
ユーザーエクスペリエンスを向上させるためにCAPTCHAを簡単にバイパスできるようにするか、あるいはBOTから積極的に保護してユーザーエクスペリエンスを低下させるかは、ウェブサイトオーナーがよく悩まされるジレンマです。
ウェブサイトとBOTの間の戦争に終わりはありません。ウェブサイトがどんな検証方法を採用しようとも、誰かがそれを回避する方法を見つけ出すのは時間の問題です。
それにもかかわらず、これは教育目的のためだけのものであり、責任を持ってPuppeteerを使用してください。
同じトピックに関する次のストーリー - JSを使ってGeeTestの「スライダーCAPTCHA」をどのように突破するか
読んでくれてありがとう!記事が気に入っていただけた場合1回、2回、または50回拍手してください。
何か質問がある場合は、下にコメントを残すか、Twitterで話しかけてください。
Discussion