我按照此说明在 Cognito 中实现自定义消息发送器https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-custom-sms-sender.html
所有功能都适用于类似的代码(我在 AWS Lambda 上使用 Typescript):
import {buildClient, CommitmentPolicy, KmsKeyringNode} from '@aws-crypto/client-node';
import b64 from 'base64-js';
const {decrypt} = buildClient(CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT);
const keyring = new KmsKeyringNode({keyIds: ["my-key-arn"]});
...
const {plaintext} = await decrypt(keyring, b64.toByteArray(event.request.code));
console.log(plainttext.toString()) // prints plain text exactly as I need
但是,这个库
@aws-crypto/client-node
让我的包变得非常巨大,几乎有20MB!可能是因为它依赖于一些较旧的 AWS 库...
我曾经使用像
@aws-sdk/xxx
这样的模块化库,它确实提供了更小的包。
我发现对于加密/解密我可以使用
@aws-sdk/client-kms
。但这不起作用!
我正在尝试以下代码:
import {KMSClient, DecryptCommand} from "@aws-sdk/client-kms";
import b64 from 'base64-js';
const client = new KMSClient;
await client.send(new DecryptCommand({CiphertextBlob: b64.toByteArray(event.request.code), KeyId: 'my-key-arn'}))
这给了我一个错误:
InvalidCiphertextException: UnknownError
at deserializeAws_json1_1InvalidCiphertextExceptionResponse (/projectdir/node_modules/@aws-sdk/client-kms/dist-cjs/protocols/Aws_json1_1.js:3157:23)
at deserializeAws_json1_1DecryptCommandError (/projectdir/node_modules/@aws-sdk/client-kms/dist-cjs/protocols/Aws_json1_1.js:850:25)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async /projectdir/node_modules/@aws-sdk/middleware-serde/dist-cjs/deserializerMiddleware.js:7:24
at async /projectdir/node_modules/@aws-sdk/middleware-signing/dist-cjs/middleware.js:14:20
at async StandardRetryStrategy.retry (/projectdir/node_modules/@aws-sdk/middleware-retry/dist-cjs/StandardRetryStrategy.js:51:46)
at async /projectdir/node_modules/@aws-sdk/middleware-logger/dist-cjs/loggerMiddleware.js:6:22
at async REPL7:1:33 {
'$fault': 'client',
'$metadata': {
httpStatusCode: 400,
requestId: '<uuid>',
extendedRequestId: undefined,
cfId: undefined,
attempts: 1,
totalRetryDelay: 0
},
__type: 'InvalidCiphertextException'
}
我做错了什么?这个KMSClient支持我需要的吗?
我还尝试了 AWS CLI
aws kms decrypt --ciphertext-blob ...
命令,给了我完全相同的响应。不过,如果我加密和解密任何随机消息(例如“hello world”),它就会像魅力一样发挥作用。
我做错了什么,Cognito 代码密文有什么特别之处,所以我必须以另一种方式解密它?
简短回答: Cognito 不使用 KMS 来加密文本,它使用加密 SDK。所以你不能使用KMS来解密Cognito密文。
更长的答案:过去一天我试图使用 boto3 和 KMS 客户端让 Python 电子邮件发送器触发函数与 Cognito 一起工作,直到我发现另一篇文章(在某个地方?)解释 Cognito 不使用 KMS 加密数据,而不是加密 SDK。当然这两种加密机制是不兼容的。
对于 JavaScript 和 Node.js 应用程序,您似乎可以选择包含整个加密客户端:https://www.npmjs.com/package/@aws-crypto/decrypt-node
如果你所做的只是解密,上面的包可以让你使用Encryption SDK进行解密,而且它只有159KB。
我已经成功地解决了我的任务。我发现它确实不是简单地使用KMS来加密文本,加密/解密过程要复杂得多。
有参考页面https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/message-format.html
它描述了消息的外观,包括所有标头和正文、IV、AAD、密钥等...我已经编写了自己的脚本来解析所有内容并正确解密,它起作用了!可能太长了,无法分享...我建议改用参考资料。希望将来他们能够发布合适的模块化版本的 SDK。
“@aws-crypto”中的那个对我不起作用,可能无法正确支持所有协议。在您阅读本文时,这可能不是事实。
因为显然这在互联网上的其他任何地方都不存在,并且 AWS 对于 python 也没有明确记录它,因此以下是实现此功能的代码:
# ...previous code...
import base64
import aws_encryption_sdk
from aws_encryption_sdk import CommitmentPolicy
# Get the code from the event
code: str = event["request"]["code"]
# Set up an encryption client with an explicit commitment policy. If you do not explicitly choose a
# commitment policy, REQUIRE_ENCRYPT_REQUIRE_DECRYPT is used by default.
client = aws_encryption_sdk.EncryptionSDKClient(commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_ALLOW_DECRYPT)
# Create an AWS KMS master key provider
kms_kwargs = dict(key_ids=[KMS_KEY_ARN])
kms_key_provider = aws_encryption_sdk.StrictAwsKmsMasterKeyProvider(**kms_kwargs)
# Decrypt the encrypted message using the AWS Encryption SDK. It returns the decrypted message and the header.
plaintext_bytes, decrypted_message_header = client.decrypt(source=base64.b64decode(code), key_provider=kms_key_provider)
template_kwargs = {"verificationCode": plaintext_bytes.decode("utf-8")}
文档明确指出“Amazon Cognito 使用 AWS 加密 SDK 来加密授权用户 API 请求的秘密、临时密码和代码。”
他们还提供了一个 JS 示例(并且 aws-encryption-sdk python 库有一些不错的示例),但没有人提到的是,您需要在
base64.b64decode
代码上使用 Cognito
才能实现此目的工作。
否则,您会收到
aws_encryption_sdk.exceptions.NotSupportedError: Unsupported version
错误。