Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import { Request } from 'express';

import { KycConfigService } from '@/config';
import * as securityUtils from '@/utils/security';

@Injectable()
export class KycWebhookAuthGuard implements CanActivate {
Expand All @@ -18,7 +19,6 @@ export class KycWebhookAuthGuard implements CanActivate {
const request: Request = context.switchToHttp().getRequest();

const { headers, body } = request;
const apiKey = headers['x-auth-client'];
const hmacSignature = headers['x-hmac-signature'];

if (!hmacSignature) {
Expand All @@ -27,6 +27,12 @@ export class KycWebhookAuthGuard implements CanActivate {
HttpStatus.BAD_REQUEST,
);
}
if (typeof hmacSignature !== 'string') {
throw new HttpException(
'Invalid HMAC Signature type',
HttpStatus.BAD_REQUEST,
);
}

const signedPayload = createHmac(
'sha256',
Expand All @@ -35,10 +41,7 @@ export class KycWebhookAuthGuard implements CanActivate {
.update(JSON.stringify(body))
.digest('hex');

if (
signedPayload !== hmacSignature ||
this.kycConfigService.apiKey !== apiKey
) {
if (!securityUtils.safeCompare(signedPayload, hmacSignature)) {
throw new HttpException(
'HMAC Signature does not match',
HttpStatus.UNAUTHORIZED,
Expand Down
14 changes: 14 additions & 0 deletions packages/apps/reputation-oracle/server/src/utils/security.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import crypto from 'crypto';

import * as bcrypt from 'bcrypt';

export function hashPassword(password: string): string {
Expand All @@ -12,3 +14,15 @@ export function comparePasswordWithHash(
): boolean {
return bcrypt.compareSync(password, passwordHash);
}

export function safeCompare(a: string, b: string): boolean {
const bufA = Buffer.from(a);
const bufB = Buffer.from(b);

// Must be same length to avoid early return timing leaks
if (bufA.length !== bufB.length) {
return false;
}

return crypto.timingSafeEqual(bufA, bufB);
}
Loading