CodeQL 文档

电子邮件生成中的 Host 头部污染

ID: js/host-header-forgery-in-email-generation
Kind: path-problem
Security severity: 9.8
Severity: error
Precision: high
Tags:
   - security
   - external/cwe/cwe-640
Query suites:
   - javascript-code-scanning.qls
   - javascript-security-extended.qls
   - javascript-security-and-quality.qls

点击查看 CodeQL 仓库中的查询

使用 HTTP Host 头部在电子邮件中构建链接可能会促进网络钓鱼攻击和泄露密码重置令牌。恶意用户可以向目标网站发送 HTTP 请求,但使用指向其自身网站的 Host 头部。这意味着电子邮件将发送给潜在受害者,这些电子邮件源自他们信任的服务器,但链接指向恶意网站。

如果电子邮件包含密码重置链接,而受害者点击了该链接,那么重置令牌将泄露给攻击者。使用泄露的令牌,攻击者可以构建真正的重置链接,并使用它来更改受害者的密码。

建议

从配置文件中获取服务器的主机名,避免依赖 Host 头部。

示例

以下示例使用 `req.host` 生成密码重置链接。此值来自 Host 头部,因此攻击者可以将其设置为任何内容

let nodemailer = require('nodemailer');
let express = require('express');
let backend = require('./backend');

let app = express();

let config = JSON.parse(fs.readFileSync('config.json', 'utf8'));

app.post('/resetpass', (req, res) => {
  let email = req.query.email;
  let transport = nodemailer.createTransport(config.smtp);
  let token = backend.getUserSecretResetToken(email);
  transport.sendMail({
    from: 'webmaster@example.com',
    to: email,
    subject: 'Forgot password',
    text: `Click to reset password: https://${req.host}/resettoken/${token}`,
  });
});

为确保链接指向正确的网站,请从配置文件中获取主机名

let nodemailer = require('nodemailer');
let express = require('express');
let backend = require('./backend');

let app = express();

let config = JSON.parse(fs.readFileSync('config.json', 'utf8'));

app.post('/resetpass', (req, res) => {
  let email = req.query.email;
  let transport = nodemailer.createTransport(config.smtp);
  let token = backend.getUserSecretResetToken(email);
  transport.sendMail({
    from: 'webmaster@example.com',
    to: email,
    subject: 'Forgot password',
    text: `Click to reset password: https://${config.hostname}/resettoken/${token}`,
  });
});

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私