用戶註冊、綁定郵箱時,單靠發送驗證郵件無法阻擋惡意註冊或格式錯誤導致的髒數據。本文構建一個分層驗證體系:安全過濾 → 格式校驗 → 後綴白名單 → 可選的 MX 記錄檢查。
在進入業務邏輯前,攔截腳本注入、iframe 等攻擊向量:
function sanitize_input(string $input): bool {
$dangerous = ['script', 'iframe', 'onload', 'onerror', 'javascript:'];
$lower = strtolower($input);
foreach ($dangerous as $keyword) {
if (strpos($lower, $keyword) !== false) {
return false;
}
}
return true;
}
function validate_email_structure(string $email): bool {
if (!sanitize_input($email)) return false;
// 基礎結構:單一 @,非首尾
if (substr_count($email, '@') !== 1) return false;
if ($email[0] === '@' || substr($email, -1) === '@') return false;
[$local, $domain] = explode('@', $email);
// 本地部分長度限制(RFC 5321)
if (strlen($local) > 64) return false;
// 域名部分長度限制
if (strlen($domain) > 255) return false;
// 域名格式簡易檢查
if (!preg_match('/^[a-z0-9.-]+\.[a-z]{2,}$/i', $domain)) return false;
return true;
}
防止一次性郵箱、拼寫錯誤域名:
const ALLOWED_SUFFIXES = [
'gmail.com', 'outlook.com', 'hotmail.com', 'yahoo.com',
'qq.com', '163.com', '126.com', 'sina.com', 'sohu.com',
'foxmail.com', 'icloud.com', 'protonmail.com'
// 根據業務擴展
];
function check_suffix_whitelist(string $email): bool {
$domain = substr(strrchr($email, '@'), 1);
return in_array(strtolower($domain), ALLOWED_SUFFIXES, true);
}
function check_mx_record(string $domain): bool {
if (function_exists('checkdnsrr')) {
return checkdnsrr($domain, 'MX');
}
// Windows 相容備選
$output = [];
exec("nslookup -type=mx $domain", $output);
return !empty($output);
}
function validate_email_complete(string $email): array {
$errors = [];
if (!sanitize_input($email)) {
$errors[] = '輸入包含非法字符';
}
if (!validate_email_structure($email)) {
$errors[] = '郵箱格式不正確';
}
if (!check_suffix_whitelist($email)) {
$errors[] = '不支援的郵箱服務商';
}
// 可選:MX 檢查
// $domain = substr(strrchr($email, '@'), 1);
// if (!check_mx_record($domain)) $errors[] = '域名無法接收郵件';
return [
'valid' => empty($errors),
'errors' => $errors
];
}
分層驗證策略能有效平衡安全性、用戶體驗與維護成本。