为什么我的 AWS Lambda 函数返回“无效 JSON"?错误? [英] Why does my AWS Lambda Function return "Invalid JSON" error?

查看:33
本文介绍了为什么我的 AWS Lambda 函数返回“无效 JSON"?错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个几天前写的 lambda 函数,经过测试,它表现得非常好.今天去测试后(不更改任何代码),我收到以下错误:"Invalid lambda function output : Invalid JSON".

I have a lambda function that I wrote a few days ago that was acting totally fine when tested. After going to test it today (without changing any of the code), I receive the following error: "Invalid lambda function output : Invalid JSON".

这是函数代码(Node.js 10.x):

Here is the function code (Node.js 10.x):

const AWS = require("aws-sdk");
const joi = require("@hapi/joi");

const Cognito = new AWS.CognitoIdentityServiceProvider();

exports.handler = async (event) => {
    // NOTE: Cognito expects Username to be the user's email

    // Vars
    const userPoolId = process.env.COGNITO_USER_POOL_ID;
    const {email : UNSAFE_EMAIL, language : UNSAFE_LANGUAGE = "en-US"} = event;

    // Normalize email and language
    const UNSAFE_TRIMMED_EMAIL = UNSAFE_EMAIL.trim();
    const UNSAFE_TRIMMED_LANGUAGE = UNSAFE_LANGUAGE.trim();

    // Validate UNSAFE_INPUTS
    const languageRegex = /^[a-z]{2}-[A-Z]{2}$/;

    const schema = joi.object().keys({
        email: joi.string().trim().email({minDomainSegments: 2}).required(),
        language: joi.string().trim().min(2).max(5).regex(languageRegex).required()
    });

    const validationResult = joi.validate({
        email: UNSAFE_TRIMMED_EMAIL,
        language: UNSAFE_TRIMMED_LANGUAGE
    }, schema);

    if(validationResult.error) {
        console.log(JSON.stringify(validationResult.error, null, 2));
        return {
            statusCode: 400,
            body: JSON.stringify({
                error: true,
                error_message: "Invalid"
            })
        }
    }

    // Validation successful, change variable names to reflect
    const VALIDATED_EMAIL = UNSAFE_TRIMMED_EMAIL;
    const VALIDATED_LANGUAGE = UNSAFE_TRIMMED_LANGUAGE;

    // Cognito params
    // Username is the user's email
    // email is also required in UserAttributes in order to send confirmation
    // DesiredDeliveryMediums is required to send confirmation
    const params = {
        UserPoolId: userPoolId,
        Username: VALIDATED_EMAIL,
        UserAttributes: [
            {
                Name: "email",
                Value: VALIDATED_EMAIL
            },
            {
                Name: "custom:language",
                Value: VALIDATED_LANGUAGE
            } 
        ],
        DesiredDeliveryMediums: ["EMAIL"]
    }

    // Attempt to create user in Cognito
    try {
        const authRes = await Cognito.adminCreateUser(params).promise();
        console.log("Success: ", JSON.stringify(authRes, null, 2));
        return {
            statusCode: 200,
            body: JSON.stringify({
                success: true
            })
        }
    } catch(err) {
        console.log("Error: ", JSON.stringify(err, null, 2));
        return {
            statusCode: 400,
            body: JSON.stringify({
                error: true,
                error_message: err.message
            })
        }
    }
};

运行测试时,我在传入格式错误的事件数据时收到预期的错误消息,并且在尝试使用相同的电子邮件创建用户两次时收到 Cognito 错误.再次,这是意料之中的.但是,当在用户池中没有用户的情况下传递有效电子邮件时,我会收到以下回复(格式为可读性):

Running the tests, I get the expected error message when passing in badly formatted event data, and I get a Cognito error when attempting to create a user with the same email twice. Again, this is expected. However, when passing in a valid email with no users in the user pool I get the following as my response (formatted for readability):

Response:
{
  "statusCode": 400,
  "body": {
    "error": true,
    "error_message": "Invalid lambda function output : Invalid JSON"
  }
}

检查此函数连接到的 Cognito 用户池,我看到已成功创建用户.然而,没有像几天前那样向该电子邮件地址发送电子邮件.

Checking in the Cognito User Pool that this function connects to, I see that a user has been successfully created. Yet, no email has been sent to the email address as was happening a few days ago.

记录的所有信息都是说我有一个无效的 JSON 错误,根本没有记录 authRes.当移除对 Cognito 的调用和相应的 console.log 调用时,try 块运行成功.所以问题在于对 Cognito 的调用.

All that is logged is information saying that I have an invalid JSON error, there is no authRes logged at all. When removing the call to Cognito and the corresponding console.log call, the try block runs successfully. So the issue is with the call to Cognito.

但是为什么这段代码在几天前运行良好时今天却失败了?这就是让我非常沮丧的部分.

But why is this code failing today when it was working perfectly a few days ago? That is the part that is making me very frustrated.

推荐答案

问题根本不在于这个 lambda 函数.这是 AWS 和我用作 Cognito 用户池的自定义消息触发器的 lambda 函数的问题.这是哪里出了问题:

The issue wasn't with this lambda function at all. It was an issue with AWS and the lambda function I was using as a Custom Message Trigger for Cognito User Pools. Here is what went wrong:

根据 AWS 文档,提供给自定义消息触发器 lambda 的事件数据对于 adminCreateUser 函数调用采用以下形式:

Per the AWS docs, the event data provided to the Custom Message Trigger lambda is of the following form for the adminCreateUser function call:

{
  "version": 1,
  "triggerSource": "CustomMessage_AdminCreateUser",
  "region": "<region>",
  "userPoolId": "<userPoolId>",
  "userName": "<userName>",
  "callerContext": {
      "awsSdk": "<calling aws sdk with version>",
      "clientId": "<apps client id>",
      ...
  },
  "request": {
      "userAttributes": {
          "phone_number_verified": false,
          "email_verified": true,
           ...
      },
      "codeParameter": "####",
      "usernameParameter": "username"
  },
  "response": {
      "smsMessage": "<custom message to be sent in the message with code parameter and username parameter>"
      "emailMessage": "<custom message to be sent in the message with code parameter and username parameter>"
      "emailSubject": "<custom email subject>"
  }
}

并且期望从自定义消息触发器 lambda 返回的数据与事件具有相同的形式 - 仅更改了 response 对象.

And it is expected that the data returned from the Custom Message Trigger lambda is of the same form as the event - only with the response object changed.

这就是我为 lambda 写的:

So this is what I wrote for the lambda:

const email_message = require("./email_message");

exports.handler = async (event) => {
    // Vars
    const {codeParameter, usernameParameter} = event.request;
    console.log("Cognito Event: ", event);

    // Check that codeParameter equals "####" and usernameParameter equals "username"
    // This is to ensure that no compromised values are entered into the html
    if(!(codeParameter === "####" && usernameParameter === "username")) {
        return null;
    }


    const newRes = {
        smsMessage: `Welcome: confirmation code is ${codeParameter} and username is ${usernameParameter}`,
        emailMessage: email_message({codeParameter, usernameParameter}),
        emailSubject: "Welcome To Our Site"
    }

    return {...event, response: newRes};
};

这在几天前测试时有效,因为事件对象是上面的形式.发生的事情是 AWS 偷偷地将 codeParameterusernameParameter 字段的内容更改为以下内容:

And this worked when tested a few days ago because the event object was of the form above. What had happened is that AWS sneakily changed the content of the codeParameter and usernameParameter fields to the following:

{
    ...
    "codeParameter": "{####}",
    "usernameParameter": "{username}",
    ...
}

所以 lambda 函数返回 null 因为这些字符串没有通过验证 - 而 null 不是有效的 JSON.

So the lambda function was returning null as these strings didn't pass validation - and null isn't valid JSON.

所以临时修复是验证这些新字符串.然而,这引起了一些担忧.为什么 AWS 会突然更改事件对象而不更新文档?其次,我应该如何验证这些字符串是否可以安全地注入到客户的电子邮件地址中?我知道我可以清理 usernameParameter 但是 codeParameter 怎么样,因为它很可能包含危险字符,例如 <>&' " 因为它是用随机符号生成的密码?如果我自己生成密码,我可以确定它不会包含来自恶意行为者的数据,因此无需清理.但如果它来自 AWS,谁能说这些值不会以某种方式受到损害?因此,为什么我首先添加了验证步骤,如果这些值发生更改,该步骤应该会失败.这正是发生的事情.

So the temporary fix is to validate these new strings instead. However, this raises some concerns. Why is AWS changing the event object without so much as an update to the docs all of a sudden? Second, how should I validate that these strings are safe to inject in a customer's email address? I know that I can sanitize the usernameParameter but how about the codeParameter since it could very likely contain dangerous characters such as < > & ' " since it is a password generated with random symbols? If generating the password myself I can be sure that it won't contain data from a malicious actor so there is no need to sanitize. But if it's coming from AWS, who's to say that somehow these values aren't compromised? Hence why I added the validation step in the first place that was supposed to fail in the case those values had been changed. Which is exactly what happened.

简而言之,我的所有代码都按预期运行.AWS 在没有通知的情况下突然更改了他们的事件对象.

So in short, all of my code behaved as expected. AWS changed their event object all of a sudden without notice.

这篇关于为什么我的 AWS Lambda 函数返回“无效 JSON"?错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆