You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS Cognito自定义邮件触发器解密密码出现HTML实体转义异常

问题描述

为AWS Cognito配置自定义邮件发送触发器(custom email sender trigger)时,业务子系统通过Cognito的admin-create-user命令创建用户,操作触发系统向用户发送包含初始一次性密码的邮件,90%场景下功能运行正常。
但部分场景下,解密得到的密码中特殊符号被表示为HTML实体,Cognito预期用户输入原始符号,二者不匹配导致用户无法登录:

  • Lambda邮件发送器内解密得到(待发送给用户)的密码值:iPi1Hz>H(包含>片段)
  • Cognito侧实际校验的正确密码值:iPi1Hz>H
    使用的Lambda解密逻辑代码如下:
const getPlainTextCode = async (event: CustomEmailSenderTriggerEvent) => {
  if (!event.request.code) {
    throw Error("Could not find code");
  }

  if (!process.env.KEY_ID) {
    throw Error("Cannot decrypt code");
  }

  const client = buildClient(CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT);
  const generatorKeyId = process.env.KEY_ALIAS;
  const keyIds = [process.env.KEY_ID];
  const keyring = new KmsKeyringNode({ generatorKeyId, keyIds });

  let plainTextCode: string | undefined = undefined;
  const decryptOutput = await client.decrypt(keyring, Buffer.from(event.request.code, "base64"));
  if (event.userPoolId !== decryptOutput.messageHeader.encryptionContext["userpool-id"]) {
    throw new Error("Encryption context does not match expected values!");
  }
  plainTextCode = decryptOutput.plaintext.toString(); // 输出为iPi1Hz>H

  return plainTextCode;
};
根本原因

这个问题和KMS解密逻辑无关,是Cognito自定义邮件触发器的内置转义规则导致的:
当Cognito生成的临时密码包含&、<、>、单引号、双引号这类HTML特殊字符时,会先对密码做HTML实体转义,再用配置的KMS密钥加密后传递给Lambda触发器。

  • 原始密码为iPi1Hz>H时,转义后的值为iPi1Hz&gt;H,加密后传入Lambda
  • 解密后拿到的实际字符串就是转义后的iPi1Hz&gt;H,日志中显示为iPi1Hz&amp;gt;H是日志平台对&字符做了二次转义的展示效果,并非解密结果本身包含两层转义
  • 因为转义规则仅在密码命中特定特殊字符时触发,所以90%不含特殊字符的密码场景下功能完全正常,只有密码命中特殊字符时才会出现密码不匹配问题。
修复方法

在KMS解密完成后,对得到的明文字符串做一次HTML实体解码,再将解码后的密码放入邮件发送给用户即可,不需要修改KMS解密、加密上下文校验的原有逻辑。
Node.js环境下可以直接用以下无依赖方法完成解码,覆盖Cognito会转义的所有特殊字符:

const decodeHtmlEntities = (str) => {
  const entityMap = {
    '&amp;': '&',
    '&lt;': '<',
    '&gt;': '>',
    '&quot;': '"',
    '&#39;': "'"
  };
  return str.replace(/&(amp|lt|gt|quot|#39);/g, (match) => entityMap[match]);
};

修改原有解密逻辑的返回部分:

// 原有解密逻辑
plainTextCode = decryptOutput.plaintext.toString();
// 新增解码步骤
plainTextCode = decodeHtmlEntities(plainTextCode);

return plainTextCode;

如果项目中已经引入了HTML实体处理库(比如he),也可以直接调用库的解码方法,效果完全一致。
修复后可以专门构造包含&、<、>字符的临时密码测试,解密解码后的密码会和Cognito侧存储的原始密码完全匹配,用户收到邮件输入密码即可正常登录。

内容的提问来源于stack exchange,提问作者florian norbert bepunkt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 20:42:17