| 類型 | 安全性 | 使用者體驗 | 適用場景 |
|---|---|---|---|
| 傳統圖形驗證碼 | 低(易被 OCR/機器學習破解) | 差(需人工輸入) | 低風險表單、內部系統 |
| 滑塊/點選/旋轉驗證 | 中 | 中 | 登入/註冊頁面 |
| reCAPTCHA v3 / hCaptcha | 高(行為分析、設備指紋) | 最佳(無感/極少互動) | 高風險操作、公開 API、大流量站點 |
| 設備指紋 + 風控引擎 | 最高 | 無感 | 金融支付、核心業務 |
注意:僅供學習原理,生產環境強烈建議使用成熟第三方服務。
<?php
// captcha.php
session_start();
header('Content-Type: image/png');
$width = 120;
$height = 40;
$codeLength = 4;
$charset = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'; // 排除易混淆字元
$image = imagecreatetruecolor($width, $height);
$bgColor = imagecolorallocate($image, 240, 240, 240);
$textColor = imagecolorallocate($image, 50, 50, 50);
$noiseColor = imagecolorallocate($image, 180, 180, 180);
imagefilledrectangle($image, 0, 0, $width, $height, $bgColor);
// 干擾線
for ($i = 0; $i < 5; $i++) {
imageline($image, mt_rand(0, $width), mt_rand(0, $height), mt_rand(0, $width), mt_rand(0, $height), $noiseColor);
}
// 干擾點
for ($i = 0; $i < 50; $i++) {
imagesetpixel($image, mt_rand(0, $width), mt_rand(0, $height), $noiseColor);
}
// 生成驗證碼
$code = '';
for ($i = 0; $i < $codeLength; $i++) {
$code .= $charset[mt_rand(0, strlen($charset) - 1)];
$x = 20 + $i * 22 + mt_rand(-2, 2);
$y = 8 + mt_rand(-2, 2);
imagestring($image, 5, $x, $y, $code[$i], $textColor);
}
$_SESSION['captcha_code'] = strtoupper($code);
imagepng($image);
imagedestroy($image);
<!-- HTML -->
<img id="captchaImg" src="captcha.php" alt="驗證碼" style="cursor:pointer;vertical-align:middle" title="點擊更換">
<input type="text" name="captcha" id="captchaInput" placeholder="輸入驗證碼">
<script>
document.getElementById('captchaImg').addEventListener('click', function() {
this.src = 'captcha.php?' + Date.now(); // 防快取
});
</script>
<?php
// verify.php
session_start();
$input = isset($_POST['captcha']) ? strtoupper(trim($_POST['captcha'])) : '';
$stored = $_SESSION['captcha_code'] ?? '';
if ($input === $stored && $input !== '') {
echo '驗證通過';
unset($_SESSION['captcha_code']); // 一次性使用
} else {
echo '驗證碼錯誤或已過期';
}
grecaptcha.execute() 取得 token。<!-- 前端 -->
<script src="https://www.google.com/recaptcha/api.js?render=YOUR_SITE_KEY"></script>
<script>
function submitWithRecaptcha(action) {
grecaptcha.ready(function() {
grecaptcha.execute('YOUR_SITE_KEY', {action: action}).then(function(token) {
document.getElementById('recaptcha_token').value = token;
document.getElementById('recaptcha_action').value = action;
document.forms[0].submit();
});
});
}
</script>
<form method="POST">
<input type="hidden" name="recaptcha_token" id="recaptcha_token">
<input type="hidden" name="recaptcha_action" id="recaptcha_action">
<button type="button" onclick="submitWithRecaptcha('login')">登入</button>
</form>
<?php
// 後端驗證
$secret = 'YOUR_SECRET_KEY';
$token = $_POST['recaptcha_token'] ?? '';
$action = $_POST['recaptcha_action'] ?? '';
$remoteIp = $_SERVER['REMOTE_ADDR'];
$response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=$secret&response=$token&remoteip=$remoteIp");
$result = json_decode($response, true);
if ($result['success'] && $result['action'] === $action && $result['score'] >= 0.5) {
// 驗證通過,執行業務邏輯
} else {
// 驗證失敗,記錄日誌、要求二次驗證或封鎖
error_log('reCAPTCHA failed: ' . json_encode($result));
}