无法在AWS Lambda自定义授权程序

时间:2017-11-18 01:47:53

标签: node.js lambda aws-lambda twilio

我已经使用NodeJS构建了一个自定义授权器lambda函数,我已将其配置为在AWS中授权另一个lambda函数。此其他功能是从HTTP端点触发的,并且我将我在Twilio Messaging Service中配置的URL作为带有 GET 方法的webhook URL。

我必须使用GET,因为AWS不会将POST请求的标头包含在授权器函数的输入参数中,并且我需要标头才能获得X-Twilio-Signature。

在authorizer函数中,我正在调用Twilio Node Helper validateRequest(token, signature, url, params)函数并提供我的身份验证令牌,来自请求头的Twilio签名,以及与webhook中配置的完全相同的URL(无查询参数) ,没有多余的装饰,只是一个带有api资源路径的https网址。)

然而,这些参数是我认为情况正在崩溃的地方以及验证失败的原因。

由于我正在为webhook使用GET方法,这是否意味着当Twilio在其末端创建签名哈希时,没有附加POST数据(根据https://www.twilio.com/docs/api/security上的文档),或者我应该提供他们在我的GET请求的查询中提供的所有表单数据??

无论我尝试过什么,我的验证都会失败,好像我使用的参数不同于Twilio创建签名所做的那些。

我已经创建了一个简单的测试,看看我是否可以使用我所做的实际HTTP请求的参数和签名来验证请求,但它似乎永远不会起作用。这是我的简单测试:

const token = '[my auth token]';
const url = 'https://my-api.company.io/sms/receive';
const signature = '[twilio header signature]';

const params = { 
  MessagingServiceSid: '[sid to my msg svc]',
  ApiVersion: '2010-04-01',
  SmsSid: 'SM6b3e14ea5e87ff967adb0c00c81406b8',
  SmsStatus: 'received',
  SmsMessageSid: 'SM6b3e14ea5e87ff967adb0c00c81406b8',
  NumSegments: '1',
  ToState: 'TX',
  From: '+19998675309',
  MessageSid: 'SM6b3e14ea5e87ff967adb0c00c81406b8',
  AccountSid: '[my account sid]',
  ToZip: '75229',
  ToCity: 'DALLAS',
  FromCountry: 'US',
  FromCity: 'IRVING',
  To: '[my twilio number]',
  FromZip: '75014',
  ToCountry: 'US',
  Body: 'Super duper',
  NumMedia: '0',
  FromState: 'TX' 
};
const result = twilio.validateRequest(token, signature, url, params);
console.log(result);

更新 为了回应Phil(Twilio Dev Evangelist)的回答,当我切换到使用 POST webhook URL时,我在授权器功能的日志中看到的内容(这不适用于评论,所以我正在编辑Q)。

请注意,此有效负载没有任何上述参数,这些参数由Twilio在POST请求正文中提供,我可能需要提供给twilio.validateRequest函数:

{
  type: 'REQUEST',
  methodArn: 'arn:aws:execute-api:us-east-1:********:********/dev/POST/receive',
  resource: '/receive',
  path: '/sms/receive',
  httpMethod: 'POST',
  headers: {
    Accept: '*/*',
    'CloudFront-Viewer-Country': 'US',
    'CloudFront-Forwarded-Proto': 'https',
    'CloudFront-Is-Tablet-Viewer': 'false',
    'CloudFront-Is-Mobile-Viewer': 'false',
    'User-Agent': 'TwilioProxy/1.1',
    'X-Forwarded-Proto': 'https',
    'CloudFront-Is-SmartTV-Viewer': 'false',
    Host: 'api.myredactedcompany.io',
    'X-Forwarded-Port': '443',
    'X-Amzn-Trace-Id': 'Root=**************',
    Via: '1.1 ***************.cloudfront.net (CloudFront)',
    'Cache-Control': 'max-age=259200',
    'X-Twilio-Signature': '***************************',
    'X-Amz-Cf-Id': '****************************',
    'X-Forwarded-For': '[redacted IP addresses]',
    'Content-Length': '492',
    'CloudFront-Is-Desktop-Viewer': 'true',
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  queryStringParameters: {},
  pathParameters: {},
  stageVariables: {},
  requestContext: {
    path: '/sms/receive',
    accountId: '************',
    resourceId: '*****',
    stage: 'dev',
    requestId: '5458adda-ce2c-11e7-ba08-b7e69bc7c01c',
    identity: {
      cognitoIdentityPoolId: null,
      accountId: null,
      cognitoIdentityId: null,
      caller: null,
      apiKey: '',
      sourceIp: '[redacted IP]',
      accessKey: null,
      cognitoAuthenticationType: null,
      cognitoAuthenticationProvider: null,
      userArn: null,
      userAgent: 'TwilioProxy/1.1',
      user: null
    },
    resourcePath: '/receive',
    httpMethod: 'POST',
    apiId: '*******'
  }
}

1 个答案:

答案 0 :(得分:1)

Twilio开发者传道者在这里。

此处的问题是,在生成签名时,查询字符串参数的处理方式与POST正文参数不同。

Notably part 3 of the steps used to generate the request signature says

  

如果您的请求是POST,Twilio将获取所有POST字段,按字母顺序按名称对它们进行排序,并将参数名称和值连接到URL的末尾(没有分隔符)

(强调我的。)

这意味着如果您尝试重建原始网址,则需要使用&=重建原始查询字符串。我在这里看到的困难是你不知道参数的原始顺序,我不知道订单是否是任意的。

问题2是请求授权者不会将POST主体发送到Lambda函数。

因此,无论您尝试使用它,自定义授权程序都不会获得Twilio请求验证程序验证请求所需的所有详细信息。

我现在唯一的建议是不再使用授权人,只是将请求验证构建到最终的Lambda函数中。它不像分离验证请求和响应请求的问题那么好,但由于自定义授权器不支持所需的所有功能,所以这是我现在唯一能想到的。

现在,引起我注意的另一件事就是说你无法在POST请求授权程序中获取标题。我浏览了一下,his Stack Overflow answer表明,只要你use the Request type authorizer而不是{{{} 1}}授权人。

所以我的建议是转换为Token授权人,来自Twilio的POST请求webhook以及你已经拥有的代码应该有效。

让我知道这是否有帮助。