首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP GD 實現多彩驗證碼:指定顏色字符輸入提升安全性

     編輯:PHP 相關知識

傳統驗證碼全字符同色易被 OCR 識別。本文實現「多彩驗證碼」:隨機選取 2 個字符著色,用戶僅需輸入指定顏色字符,大幅提升機器識別難度。

核心邏輯

  1. 預設字符池(中文/字母/數字);
  2. 隨機抽取 N 個字符生成基礎文本;
  3. 隨機選取 1~2 個位置作為「目標字符」,分配特殊顏色;
  4. 其餘字符用干擾色(灰/黑)繪製;
  5. 前端提示:「請輸入 紅色 字符」。

完整實現代碼

<?php
header('Content-Type: image/png; charset=utf-8');

// 畫布尺寸
$width = 400;
$height = 60;
$im = imagecreatetruecolor($width, $height);

// 顏色分配
$white = imagecolorallocate($im, 255, 255, 255);
$black = imagecolorallocate($im, 40, 40, 40);
$gray  = imagecolorallocate($im, 150, 150, 150);
$red   = imagecolorallocate($im, 220, 50, 50);
$blue  = imagecolorallocate($im, 50, 100, 220);
$green = imagecolorallocate($im, 50, 180, 50);

$special_colors = [$red, $blue, $green];
$base_colors    = [$black, $gray];

// 字符池與文本生成
$charset = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
$len = 6;
$text = '';
for ($i = 0; $i < $len; $i++) {
    $text .= $charset[random_int(0, strlen($charset) - 1)];
}

// 隨機選取 1~2 個特殊位置
$special_count = random_int(1, 2);
$special_pos = [];
while (count($special_pos) < $special_count) {
    $pos = random_int(0, $len - 1);
    if (!in_array($pos, $special_pos, true)) {
        $special_pos[] = $pos;
    }
}
$special_color = $special_colors[array_rand($special_colors)];

// 字體設置(需確保字體文件存在)
$font = __DIR__ . '/fonts/NotoSansSC-Regular.otf'; // 建議使用開源中文字體
$font_size = 24;

// 繪製背景
imagefilledrectangle($im, 0, 0, $width - 1, $height - 1, $white);

// 可選:添加干擾線/點
for ($i = 0; $i < 8; $i++) {
    $line_color = imagecolorallocatealpha($im, 200, 200, 200, 80);
    imageline($im, random_int(0, $width), random_int(0, $height), random_int(0, $width), random_int(0, $height), $line_color);
}
for ($i = 0; $i < 100; $i++) {
    $dot_color = imagecolorallocatealpha($im, 100, 100, 100, 60);
    imagesetpixel($im, random_int(0, $width), random_int(0, $height), $dot_color);
}

// 逐字符繪製
$char_width = $width / $len;
for ($i = 0; $i < $len; $i++) {
    $x = (int)($i * $char_width + $char_width * 0.15);
    $y = (int)($height * 0.65);
    $angle = random_int(-12, 12);
    $color = in_array($i, $special_pos, true) ? $special_color : $base_colors[array_rand($base_colors)];
    imagettftext($im, $font_size, $angle, $x, $y, $color, $font, $text[$i]);
}

// 輸出並銷毀
imagepng($im);
imagedestroy($im);

// 將驗證信息存入 Session 供驗證
session_start();
$_SESSION['captcha'] = [
    'text' => $text,
    'special_pos' => $special_pos,
    'special_color' => '#' . sprintf('%02x%02x%02x',
        ($special_color >> 16) & 0xFF,
        ($special_color >> 8) & 0xFF,
        $special_color & 0xFF
    ),
    'expire' => time() + 300 // 5 分鐘有效
];
?>

前端驗證邏輯

<!-- HTML -->
<img id="captcha" src="captcha.php" alt="驗證碼" style="cursor:pointer" onclick="this.src='captcha.php?'+Date.now()">
<p>請輸入 <span id="color_hint" style="font-weight:bold"></span> 字符</p>
<input type="text" name="captcha_input" id="captcha_input" maxlength="2">

<script>
// 獲取顏色提示(需從後端 API 獲取或內聯輸出)
fetch('captcha_info.php')
  .then(r => r.json())
  .then(d => {
    document.getElementById('color_hint').textContent = d.color_name;
    document.getElementById('color_hint').style.color = d.color_hex;
  });

// 提交時驗證
document.querySelector('form').addEventListener('submit', async (e) => {
  const input = document.getElementById('captcha_input').value.toUpperCase();
  const res = await fetch('verify_captcha.php', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({input})
  });
  const data = await res.json();
  if (!data.ok) { alert(data.msg); e.preventDefault(); }
});
</script>

後端驗證邏輯

<?php // verify_captcha.php
session_start();
header('Content-Type: application/json');

$input = strtoupper(trim($_POST['input'] ?? ''));
$captcha = $_SESSION['captcha'] ?? null;

if (!$captcha || time() > $captcha['expire']) {
    echo json_encode(['ok' => false, 'msg' => '驗證碼已過期']);
    exit;
}

$text = $captcha['text'];
$special_pos = $captcha['special_pos'];
$expected = '';
foreach ($special_pos as $pos) {
    $expected .= $text[$pos];
}

if ($input === $expected) {
    unset($_SESSION['captcha']); // 一次性使用
    echo json_encode(['ok' => true]);
} else {
    echo json_encode(['ok' => false, 'msg' => '驗證碼錯誤']);
}

安全性增強建議

  • 字符池排除易混淆字符(O/0, I/1, l/1);
  • 字體隨機傾斜、字符間距微調;
  • 加入貝塞爾曲線干擾線替代直線;
  • 限制同 IP 請求頻率,防暴力刷新;
  • 生產環境建議使用成熟庫 Gregwar/Captcha 或 mews/captcha (Laravel)。

多彩驗證碼通過「人類易辨、機器難分」的顏色維度,在不犧牲用戶體驗前提下顯著提升防機器能力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved