-
Notifications
You must be signed in to change notification settings - Fork 515
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Express webhook not authenticating #924
Comments
I tried to replicate the issue your having, but was only able to find that the An issue I see in your code snippet is that your const url = 'https://ExpressWithTwilioWebhook.olegazava.repl.co' to... const url = 'https://ExpressWithTwilioWebhook.olegazava.repl.co/api/message' Should solve your failed request validation with the I'm still investigating why the |
@Hunga1 I tried with both urls and both methods fail. We're looking to migrate off if we can't verify the signature. To confirm:
Screenshot showing |
This issue has been added to our internal backlog to be prioritized. Pull requests and +1s on the issue summary will help it move up the backlog. (Internal ref: DI-2629) |
@okomarov As a potential workaround, could you try normalizing your webhook URL hostname to lowercase characters (outlined in RFC 3986 - Sec 3.2.2. Host), use that URL in both your webhook URL setting and test app (i.e. The issue looks like it's being caused by the SDK normalizing the URL hostname to lowercase before generating the signature client-side to compare against the webhook request |
Hi @Hunga1 thanks for the reply. The test case is an example. We're using in our app all lowercase URLs but I'll try in any case. What other type of normalisations might happen? We do have a '-' like |
The '-' dash character in the hostname should be fine. You'll just want to use lowercase hostnames for both your application and Twilio webhook setting. |
Hi, IDK if the problem we're facing is exactly the same as the one mentioned in this issue, but as it seems very similar, I'll try my luck here. After upgrading the lib from We use the Where previously (in What does work (in Have we misunderstood something, or does this look like a bug? For more context, here is the full code we are using: /**
* Guard the endpoints supposed to receive only signed requests.
* For the sake of the example, see signatures made by Twilio:
* https://twilio.com/docs/usage/webhooks/webhooks-security
*/
@Injectable()
export class TwilioHttpGuard implements CanActivate {
constructor(private readonly configService: ConfigService) {}
/**
* Determine whether the current request has been properly signed, otherwise it must be ignored
* @param context Nest context; allow getting the HTTP request
* @throws {ForbiddenException} When the request has not valid signature
* @return `true` if the request is signed
*/
canActivate(context: ExecutionContext) {
const req: IGojobRequest = context.switchToHttp().getRequest();
if (!this.isHttpRequestVerified(req)) {
throw new ForbiddenException('[TWILIO] Request must be signed');
}
return true;
}
private isHttpRequestVerified(req: Request): boolean {
const authToken = this.configService.get('TWILIO_AUTH_TOKEN');
const url = `${req.get('x-forwarded-proto')}://${req.get('host')}${req.url}`;
const signatureHeader = req.get('x-twilio-signature') ?? '';
return validateRequest(authToken, signatureHeader, url, req.body);
}
} |
I haven't been verified the webhook signature before (with previous version) as I'm newly integrating Twilio webhook, but I did pretty much the exact same thing as @miramo and also facing same issue, the request is not validated as expected. I also tried with the validateRequestWithBody with no success:
|
I dug a little bit more on that and find a way to validate the signature. twilio-node/src/webhooks/webhooks.ts Line 230 in d037d6f
It does fit with what @miramo said, but passing empty object as param seems wrong to validateRequest. Anyway in all cases both Instead I used twilio-node/src/webhooks/webhooks.ts Line 135 in d037d6f
That one compute the sig exactly how it's done on Twillio's side, then you'll end up with a validation function that should looks like that:
Pay also attention, don't know which framework you are using, but based on what you are using you might used sometimes Then function is returning the proper signature and just compare it to the one you are getting from the header. |
@AsabuHere given this seems a regression as pointed out by #924 (comment) and that the verification flow has multiple branches which are not clearly explained in the code, I reckon there should be at least some guidance from the twilio team on how to go about it (if PR, who's going to review it and when) or a communication of what priority this issue has internally so we can at least fork and patch. |
Since my last comment, we found something interesting in the security documentation. What we noticed is that depending on "where" the webhook is called from (studio flow, function or callback configured for a number) the behaviour is not the same. So, according to what we noticed, we implemented two different guards depending on the webhook we were trying to validate. For the webhook called in a Studio Flow (Content-Type is private isHttpRequestVerified(req: RawBodyRequest<Request>): boolean {
const authToken = this.configService.get('TWILIO_AUTH_TOKEN');
const url = `${req.get('x-forwarded-proto')}://${req.get('host')}${req.url}`;
const signatureHeader = req.get('x-twilio-signature');
const rawBody = req.rawBody?.toString('utf8') ?? '';
return validateRequestWithBody(authToken, signatureHeader, url, rawBody);
} And for the callback that is configured for a number: private isHttpRequestVerified(req: Request): boolean {
const authToken = this.configService.get('TWILIO_AUTH_TOKEN');
const url = `${req.get('x-forwarded-proto')}://${req.get('host')}${req.url}`;
const signatureHeader = req.get('x-twilio-signature');
return validateRequest(authToken, signatureHeader, url, req.body);
} IDK if it's the right solution and that's how we had to use these methods, but that's what worked for us. |
I am also having this issue (NextJS 13) but I am not seeing a difference between the two Auth Tokens? |
I'm seeing validateRequest(TWILIO_AUTH_TOKEN, sig, fullURL.href, {}) is using 4.19 |
We are also using validateRequest. We get an POST when WhatsApp message comes in, it works perfectly fine when whatsapp message comes through, until it's an "reply" to an message in a chat and the validation fails |
Issue Summary
The validation methods in webhooks won't validate messages initiated by a user on Whatsapp.
Steps to Reproduce
Pretty much an interactive replica of How to secure Twilio webhook URLs in Node.js
3. Configure a Whatsapp sender in Twilio to send messages to https://ExpressWithTwilioWebhook.olegazava.repl.co/api/message 4. Send a message from within Whatsapp to the target phone number
Code Snippet
Exception/Log
Signatures comparison fails
Technical details:
The text was updated successfully, but these errors were encountered: