邮件发送功能本身不执行SQL,但其关联的模板查询、收件人拉取、日志写入等环节若拼接未过滤的用户输入(如$_POST),可能引发SQL注入;修复须禁用字符串拼接SQL,改用预处理语句,并对邮箱等字段严格校验与绑定。

邮件发送功能本身不直接执行 SQL,但若它在发送前查询用户偏好、模板、收件人列表或历史记录时拼接了未过滤的邮件内容(比如主题、收件人邮箱、自定义变量),就可能触发 SQL 注入。修复的关键不是“给邮件加防注入”,而是切断 $_POST、$_GET 或其他输入源到 SQL 查询语句的直连路径。
确认邮件功能是否真在查数据库
很多所谓“邮件处 SQL 注入”其实是个误判:邮件服务调用的是 SMTP 接口,不碰数据库;但配套的「模板渲染」「收件人拉取」「发送日志写入」环节却用了拼接 SQL。先 grep 代码里是否出现类似 SELECT * FROM mail_template WHERE name = '$_POST[subject]' 这种写法。如果没找到,问题大概率不在邮件模块本身,而在于它调用的 get_user_by_email()、load_template_by_id() 等辅助函数。
禁用所有手动拼接 SQL 的写法
只要看到 mysql_query()、mysqli_query() 或 PDO::query() 中包含字符串拼接(尤其是含 $_REQUEST、$_POST 的部分),必须替换。不要依赖 addslashes() 或 htmlspecialchars()——它们防 XSS 或 HTML 乱码,不防 SQL 注入。
- 改用预处理语句:PDO 的
prepare()+execute(),或 mysqli 的prepare()+bind_param() - 如果必须动态表名或字段名(极少见),只能白名单校验:
in_array($table, ['mail_log', 'mail_template']),不能靠正则过滤 - 避免把邮件主题、正文、发件人邮箱直接塞进 WHERE 条件,优先用 ID 关联。例如查模板别写
WHERE title = '{$_POST['title']}',改用WHERE id = ?并前端传固定 ID
特别注意邮箱字段的隐式类型绕过
邮箱看似是字符串,但攻击者常利用数据库对引号的自动补全或类型转换绕过基础过滤。比如 MySQL 在某些模式下会把 'admin@domain.com' OR 1=1# 当作合法邮箱字符串处理,然后拼进 SQL 后仍能执行逻辑分支。
- 邮箱字段入库/查询一律走
filter_var($email, FILTER_VALIDATE_EMAIL)校验格式,再用预处理绑定 - 禁止在 SQL 中对邮箱字段使用
LIKE '%{$email}%'这类模糊匹配——它既慢又易被注入,改用精确匹配或独立全文索引表 - 如果业务真要支持邮箱模糊搜索(如后台管理),把搜索词先转成标准格式(小写、去空格、截断长度),再进预处理参数,不拼 SQL
最常被忽略的一点:邮件发送成功后写日志的那条 INSERT INTO mail_log (to_email, subject, status) 语句,往往和主业务逻辑分离,开发者容易忘记给它加预处理——而这恰恰是 sqlmap 最爱打的点。

















