In dit artikel hebben we geprobeerd antwoord te geven op alle belangrijke vragen. De eerste stap bij het oplossen van het vraagstuk is vaststellen welk beveiligingssysteem wordt gebruikt. Daarvoor kun je de lijst met populaire captcha’s en anti-botbeveiligingssystemen raadplegen, met visuele voorbeelden en kernkenmerken die je helpen snel te bepalen waarmee je te maken hebt.
Als je ontdekt dat je website ComplexImage gebruikt, is de volgende stap om de eigenschappen en werking ervan uitgebreider te bestuderen. In dit artikel vind je ook een handleiding voor het integreren van ComplexImage, zodat je volledig begrijpt hoe het systeem op je website werkt. Zo kun je niet alleen de huidige bescherming beter doorgronden, maar ook het onderhoud ervan goed plannen.
Werken met CapMonster Cloud via de API bestaat doorgaans uit de volgende stappen:
type - ComplexImageTask
class - recognition
imagesBase64 - een array van afbeeldingen in base64-indeling. Voorbeeld: [“/9j/4AAQSkZJRgABAQEAAAAAAAD…”];
Task (binnen metadata) - naam van de taak (bijvoorbeeld dli).
https://api.capmonster.cloud/createTask{
"clientKey": "API_KEY",
"task": {
"type": "ComplexImageTask",
"class": "recognition",
"imagesBase64": [
"base64"
],
"metadata": {
"Task": "dli" // vervang door de gewenste taak, een lijst van beschikbare modules is te vinden op https://docs.capmonster.cloud/docs/captchas/ComplexImageTask-Recognition/
}
}
}
{
"errorId":0,
"taskId":407533072
}https://api.capmonster.cloud/getTaskResult{
"clientKey":"API_KEY",
"taskId": 407533072
}
{
"solution":
{
"answer": "1",
"metadata": {
"AnswerType": "Text"
}
},
"cost": 0.0003,
"status": "ready",
"errorId": 0,
"errorCode": null,
"errorDescription": null
}
// npm install playwright @zennolab_com/capmonstercloud-client
// npx playwright install chromium
import { chromium } from 'playwright';
import { CapMonsterCloudClientFactory, ClientOptions, ComplexImageTaskRecognitionRequest } from '@zennolab_com/capmonstercloud-client';
const API_KEY = "YOUR_API_KEY";
const TARGET_URL = "https://example.com/captcha-page";
async function solveComplexImageTaskPlaywright() {
const browser = await chromium.launch({ headless: false });
const context = await browser.newContext();
const page = await context.newPage();
await page.goto(TARGET_URL);
// Zoek de CAPTCHA-afbeelding
const captchaHandle = await page.$('#captcha'); // vervang door de werkelijke selector
const captchaBase64 = await captchaHandle.evaluate(img => {
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
return canvas.toDataURL('image/png').split(',')[1];
});
console.log("Captcha base64:", captchaBase64.substring(0, 50) + "...");
const cmcClient = CapMonsterCloudClientFactory.Create(
new ClientOptions({ clientKey: API_KEY })
);
// Stuur de CAPTCHA naar herkenning
const citRecognitionRequest = new ComplexImageTaskRecognitionRequest({
imagesBase64: [captchaBase64],
metaData: { Task: 'oocl_rotate' } // vervang door uw CAPTCHA-type
});
const result = await cmcClient.Solve(citRecognitionRequest);
console.log("Solution received:", result);
// Verwerking van de oplossing
const solution = result.solution;
if (!solution) {
console.error("No solution received");
return;
}
if (solution.metadata?.AnswerType === "Coordinate") {
// CAPTCHA met coördinaten
const box = await captchaHandle.boundingBox();
for (const point of solution.answer) {
const clickX = box.x + point.X;
const clickY = box.y + point.Y;
console.log(`Clicking at: (${clickX}, ${clickY})`);
await page.mouse.click(clickX, clickY);
}
} else if (solution.metadata?.AnswerType === "Grid") {
// Grid-CAPTCHA (array true/false)
const box = await captchaHandle.boundingBox();
const gridItems = await page.$$('#captcha_grid div'); // vervang door selectors van grid-elementen
const answers = solution.answer;
for (let i = 0; i < answers.length; i++) {
if (answers[i] && gridItems[i]) {
const itemBox = await gridItems[i].boundingBox();
const clickX = itemBox.x + itemBox.width / 2;
const clickY = itemBox.y + itemBox.height / 2;
console.log(`Clicking grid item ${i} at: (${clickX}, ${clickY})`);
await page.mouse.click(clickX, clickY);
}
}
} else {
console.warn("Unknown captcha solution type:", solution.metadata?.AnswerType);
}
// Klik op de bevestigingsknop (indien aanwezig)
await page.click('#submit_button'); // vervang door de werkelijke knopselector
console.log("Captcha solved.");
}
solveComplexImageTaskPlaywright().catch(console.error);
1. CAPTCHA genereren op de server.
2. CAPTCHA naar de client verzenden
<!--CAPTCHA met afbeeldingsgrid-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Grid CAPTCHA Demo</title>
<style>
#captchaGrid {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-gap: 10px;
margin-bottom: 10px;
}
.grid-item {
width: 100px;
height: 100px;
background-color: #eee;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
border: 2px solid transparent;
}
.grid-item.selected {
border-color: blue;
}
</style>
</head>
<body>
<h1>Grid CAPTCHA Demo</h1>
<div id="captchaGrid"></div>
<button id="submitBtn">Submit</button>
<button id="refreshBtn">Refresh CAPTCHA</button>
<p id="result"></p>
<script>
let captchaId;
let answers = []; // array true/false voor clicks
async function loadCaptcha() {
const res = await fetch('/captcha'); // server moet JSON teruggeven met captchaId en array van base64-afbeeldingen
const data = await res.json();
captchaId = data.captchaId;
answers = new Array(data.images.length).fill(false);
const grid = document.getElementById('captchaGrid');
grid.innerHTML = '';
data.images.forEach((imgBase64, i) => {
const div = document.createElement('div');
div.className = 'grid-item';
div.style.backgroundImage = `url('data:image/png;base64,${imgBase64}')`;
div.style.backgroundSize = 'cover';
div.addEventListener('click', () => {
answers[i] = !answers[i];
div.classList.toggle('selected', answers[i]);
});
grid.appendChild(div);
});
document.getElementById('result').textContent = '';
}
document.getElementById('refreshBtn').addEventListener('click', loadCaptcha);
document.getElementById('submitBtn').addEventListener('click', async () => {
const res = await fetch('/captcha/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ captchaId, answer: answers })
});
const data = await res.json();
document.getElementById('result').textContent = data.success ? 'Captcha passed!' : 'Captcha failed, try again.';
if (!data.success) loadCaptcha();
});
// CAPTCHA laden bij start
loadCaptcha();
</script>
</body>
</html>
3. Antwoordinvoer door gebruiker
4. Antwoord naar server verzenden:
5. Controle op server
<?php
session_start();
// TTL CAPTCHA in seconden
define('CAPTCHA_TTL', 300); // 5 minuten
// Willekeurige afbeelding genereren
function generateCaptchaImage($text = null) {
$width = 100;
$height = 100;
if (!$text) {
$text = substr(str_shuffle('ABCDEFGHJKLMNPQRSTUVWXYZ23456789'), 0, 2);
}
$image = imagecreatetruecolor($width, $height);
// achtergrond
$bgColor = imagecolorallocate($image, rand(180, 255), rand(180, 255), rand(180, 255));
imagefilledrectangle($image, 0, 0, $width, $height, $bgColor);
// tekst
$textColor = imagecolorallocate($image, 0, 0, 0);
$fontSize = 15;
$fontFile = __DIR__ . '/Arial.ttf'; // pad naar TTF-lettertype
if (file_exists($fontFile)) {
imagettftext($image, $fontSize, rand(-20,20), 10, 50, $textColor, $fontFile, $text);
} else {
imagestring($image, 5, 10, 40, $text, $textColor);
}
ob_start();
imagepng($image);
$imgData = ob_get_clean();
imagedestroy($image);
return base64_encode($imgData);
}
// Grid CAPTCHA maken
function generateGridCaptcha() {
$numImages = 9; // 3x3
$images = [];
$solution = [];
for ($i = 0; $i < $numImages; $i++) {
// willekeurige oplossing, juiste afbeelding of niet (voorbeeld)
$isCorrect = rand(0,1) === 1;
$solution[] = $isCorrect;
// Afbeelding genereren (voor echte CAPTCHA kunnen objecten worden toegevoegd)
$text = $isCorrect ? 'OK' : 'NO';
$images[] = generateCaptchaImage($text);
}
return ['images' => $images, 'solution' => $solution];
}
// Endpoint CAPTCHA genereren
if ($_SERVER['REQUEST_METHOD'] === 'GET' && $_SERVER['REQUEST_URI'] === '/captcha') {
$captchaId = uniqid('captcha_', true);
$gridCaptcha = generateGridCaptcha();
$_SESSION['captchas'][$captchaId] = [
'solution' => $gridCaptcha['solution'],
'timestamp' => time()
];
header('Content-Type: application/json');
echo json_encode([
'captchaId' => $captchaId,
'images' => $gridCaptcha['images']
]);
exit;
}
// Endpoint CAPTCHA verifiëren
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER['REQUEST_URI'] === '/captcha/verify') {
$data = json_decode(file_get_contents('php://input'), true);
$captchaId = $data['captchaId'] ?? '';
$answer = $data['answer'] ?? [];
if (!isset($_SESSION['captchas'][$captchaId])) {
echo json_encode(['success' => false, 'message' => 'Captcha expired or not found']);
exit;
}
$captcha = $_SESSION['captchas'][$captchaId];
// TTL controleren
if (time() - $captcha['timestamp'] > CAPTCHA_TTL) {
unset($_SESSION['captchas'][$captchaId]);
echo json_encode(['success' => false, 'message' => 'Captcha expired']);
exit;
}
// array true/false controleren
$success = $captcha['solution'] === $answer;
// CAPTCHA verwijderen na verificatie
unset($_SESSION['captchas'][$captchaId]);
echo json_encode(['success' => $success]);
exit;
}
// 404
http_response_code(404);
echo 'Not found';
6. Verdere stappen
Aanvullende aanbevelingen
Voer een load-test uit (bijv. met k6 of JMeter) — bij veel verzoeken:
Als u op een website bent met al geïnstalleerde CAPTCHA of een ander beschermingssysteem en geen toegang heeft tot de code, is dat geen probleem! Het is vrij eenvoudig om de technologie te identificeren. Voor het controleren van correcte werking kunt u CapMonster Cloud gebruiken in een geïsoleerde testomgeving om te verifiëren dat tokenverwerking en logica correct functioneren.
Voor CAPTCHA met afbeeldingen volstaat het om het systeem te herkennen, het gedrag te bestuderen en te controleren of de bescherming werkt. In dit artikel hebben we getoond hoe u een ComplexImage CAPTCHA kunt identificeren en hoe u deze kunt integreren of opnieuw instellen om de bescherming te handhaven en de werking te controleren.