PHP密码重置页面遭滥用致批量发件,求漏洞排查与加固方案
密码重置表单安全漏洞排查与加固方案
一、现有代码中的安全漏洞
- 输入校验缺失:未对
login_var参数做严格格式验证,攻击者可提交任意内容;跳转URL直接拼接未转义的$login参数,存在XSS风险。 - 无批量请求防护:未限制同一IP/邮箱的请求频率,自动化脚本可批量提交请求,引发邮件轰炸。
- 错误处理不严谨:
mail函数前加@屏蔽错误,无法排查邮件发送异常;header跳转后未执行exit()/die(),后续代码仍会运行,可能引发逻辑混乱;- 数据库操作(
DELETE/INSERT)未严格判断执行结果,失败后仍继续流程,可能导致无效操作。
- URL编码不规范:密码重置链接直接拼接
$token,未做URL编码,不符合安全编码规范。 - token无有效期:未给重置token设置过期时间,旧token长期有效,存在被滥用风险。
二、可能的攻击方式
- 邮件轰炸攻击:攻击者通过枚举网站注册用户邮箱(可通过表单错误提示
?err=$login枚举存在的用户),用自动化脚本高频提交密码重置请求,利用服务器向目标邮箱发送大量重置邮件,导致域名被邮件服务商标记为垃圾邮件发送者,同时骚扰用户。 - XSS攻击:攻击者构造恶意
login_var参数(如"><script>alert('xss')</script>),跳转后未转义的参数会在页面执行脚本,窃取用户会话或进行其他恶意操作。 - 潜在邮件头注入:若
test_input函数未严格过滤换行符等特殊字符,攻击者可构造包含额外邮件头的输入,若后续逻辑疏漏,可能篡改邮件发件人或添加抄送地址,导致邮件被滥用。
三、安全加固方案
1. 输入输出安全处理
- 严格校验输入格式:对
login_var分场景验证:if(filter_var($login, FILTER_VALIDATE_EMAIL)){ // 邮箱格式合法 } else { // 用户名格式验证:限制长度1-20字符,仅允许字母、数字、下划线 if(!preg_match('/^[a-zA-Z0-9_]{1,20}$/', $login)){ header("location:forgot_password_page.php?invalid_input=1"); exit(); } } - 输出转义:跳转URL中的参数必须转义,避免XSS:
header("location:forgot_password_page.php?err=".urlencode(htmlspecialchars($login))); exit();
2. 阻止批量请求
- 添加速率限制:记录每个IP/邮箱的请求时间,限制1小时内最多5次请求:
// 示例:用数据库记录请求日志 $ip = $_SERVER['REMOTE_ADDR']; $check_query = "SELECT COUNT(*) FROM reset_requests WHERE ip=? AND created_at >= DATE_SUB(NOW(), INTERVAL 1 HOUR)"; $stmt = $link->prepare($check_query); $stmt->bind_param("s", $ip); $stmt->execute(); $count = $stmt->get_result()->fetch_row()[0]; if($count >= 5){ header("location:forgot_password_page.php?too_many_requests=1"); exit(); } // 记录本次请求 $insert_query = "INSERT INTO reset_requests (ip, created_at) VALUES (?, NOW())"; $stmt = $link->prepare($insert_query); $stmt->bind_param("s", $ip); $stmt->execute(); - 添加人机验证:在表单中加入验证码(如reCAPTCHA),提交前验证用户身份,阻止自动化脚本。
3. 代码逻辑优化
- 完善错误处理:
- 移除
mail函数前的@,保留错误信息并添加日志记录:if (mail($email, $subject, $msg, $headers,'-f'.$FromEmail)) { header("location:forgot_password_page.php?sent=1"); exit(); } else { error_log("Password reset email failed for: ".$email); header("location:forgot_password_page.php?servererr=1"); exit(); } - 所有
header跳转后立即执行exit()/die(),终止后续代码执行; - 数据库操作严格判断执行结果:
$sql = "DELETE FROM pass_reset WHERE email=?"; if(!($stmt = mysqli_prepare($link, $sql))){ header("location:forgot_password_page.php?db_err=1"); exit(); } mysqli_stmt_bind_param($stmt,"s", $email); if(!mysqli_stmt_execute($stmt)){ header("location:forgot_password_page.php?db_err=1"); exit(); }
- 移除
- URL编码处理:对重置链接的
token进行URL编码:$mlink = "https://mywebsite.de/password_reset_page.php?token=".urlencode($token);
4. 邮件发送安全升级
- 使用PHPMailer/SwiftMailer替代原生
mail函数,这类库自带邮件头过滤、身份验证功能,能有效防止邮件头注入,提升发送可靠性; - 配置SPF、DKIM、DMARC域名解析记录,验证邮件真实性,防止发件人被伪造,降低域名被标记为垃圾邮件的风险。
5. 密码重置token安全强化
- 为token添加有效期,数据库新增
expires_at字段:$expires_at = date("Y-m-d H:i:s", strtotime("+15 minutes")); $sql = "INSERT INTO pass_reset (email,token,expires_at) VALUES (?,?,?)"; $stmt = mysqli_prepare($link, $sql); mysqli_stmt_bind_param($stmt,"sss", $email, $token, $expires_at); - 用户修改密码后,立即删除对应的
pass_reset记录,避免token重复使用。
内容的提问来源于stack exchange,提问作者phil3450
相关产品推荐
相关产品推荐

