我已经使用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: '*******'
}
}
答案 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以及你已经拥有的代码应该有效。
让我知道这是否有帮助。