Skip to content

Commit e75904a

Browse files
authored
Fix webhook validator (#27)
The webhook validator should consume the request timestamp as epoch seconds, not as an RFC3339 date string.
1 parent 1d1b316 commit e75904a

File tree

3 files changed

+21
-8
lines changed

3 files changed

+21
-8
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>ai.nightfall</groupId>
88
<artifactId>scan-api</artifactId>
9-
<version>1.0.2</version>
9+
<version>1.0.3</version>
1010

1111
<name>${project.groupId}:${project.artifactId}</name>
1212
<description>The Nightfall Scanner provides Java bindings for our developer platform, which allows clients

src/main/java/ai/nightfall/scan/WebhookSignatureValidator.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,16 @@ public WebhookSignatureValidator(TemporalAmount threshold) {
5252
* since the Unix epoch.
5353
* @return true if the signature is valid and the request occurred within the allowed time threshold,
5454
* otherwise false.
55+
* @throws NumberFormatException if <code>requestTime</code> is not parsable as an integer
5556
*/
5657
public boolean validate(String requestBody, byte[] signingSecret, String requestSignature, String requestTime) {
5758
if (requestBody == null || signingSecret == null || requestSignature == null || requestTime == null) {
5859
return false;
5960
}
6061

6162
Instant now = Instant.now();
62-
Instant reqTime = Instant.parse(requestTime);
63-
if (now.minus(this.threshold).isAfter(reqTime)) {
63+
Instant reqTime = Instant.ofEpochSecond(Long.parseLong(requestTime));
64+
if (now.minus(this.threshold).isAfter(reqTime) || reqTime.isAfter(now)) {
6465
return false;
6566
}
6667

src/test/java/ai/nightfall/scan/WebhookSignatureValidatorTest.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ public class WebhookSignatureValidatorTest {
1717

1818
@Test
1919
public void testHappyPath() {
20-
String timestamp = "2021-10-04T17:30:43.42Z";
20+
String timestamp = "1633368643";
2121
String reqBody = "hello world foo bar goodnight moon";
2222
byte[] secret = "super-secret-shhhh".getBytes(StandardCharsets.UTF_8);
23-
String expectedSignature = "45bf0200a2cbc02ae2595fcf9ba4a2b262d836672c4a26fc3300cc54353587cd";
23+
String expectedSignature = "641ada412da02d7df7ca59e94a556b7f5683374db614565ad3d99da1a9a779fb";
2424

2525
WebhookSignatureValidator validator = new WebhookSignatureValidator(reallyLongTime);
2626
boolean result = validator.validate(reqBody, secret, expectedSignature, timestamp);
@@ -29,10 +29,22 @@ public void testHappyPath() {
2929

3030
@Test
3131
public void testRequestTooOld() {
32-
String timestamp = "2021-10-04T17:30:43.42Z";
32+
String timestamp = "1633368643";
3333
String reqBody = "hello world foo bar goodnight moon";
3434
byte[] secret = "super-secret-shhhh".getBytes(StandardCharsets.UTF_8);
35-
String expectedSignature = "45bf0200a2cbc02ae2595fcf9ba4a2b262d836672c4a26fc3300cc54353587cd";
35+
String expectedSignature = "641ada412da02d7df7ca59e94a556b7f5683374db614565ad3d99da1a9a779fb";
36+
37+
WebhookSignatureValidator validator = new WebhookSignatureValidator(Duration.ofMinutes(1));
38+
boolean result = validator.validate(reqBody, secret, expectedSignature, timestamp);
39+
assertFalse(result);
40+
}
41+
42+
@Test
43+
public void testRequestTooFarInTheFuture() {
44+
String timestamp = "4789042243";
45+
String reqBody = "hello world foo bar goodnight moon";
46+
byte[] secret = "super-secret-shhhh".getBytes(StandardCharsets.UTF_8);
47+
String expectedSignature = "641ada412da02d7df7ca59e94a556b7f5683374db614565ad3d99da1a9a779fb";
3648

3749
WebhookSignatureValidator validator = new WebhookSignatureValidator(Duration.ofMinutes(1));
3850
boolean result = validator.validate(reqBody, secret, expectedSignature, timestamp);
@@ -41,7 +53,7 @@ public void testRequestTooOld() {
4153

4254
@Test
4355
public void testSignatureMismatch() {
44-
String timestamp = "2021-10-04T17:30:43.42Z";
56+
String timestamp = "1633368643";
4557
String reqBody = "hello world foo bar goodnight moon";
4658
byte[] secret = "super-secret-shhhh".getBytes(StandardCharsets.UTF_8);
4759
String incorrectSignature = "e05aa9a373d652b6a38fdb0e093cca3eca3d6dd803a50dbe8b98b137fd20fe87";

0 commit comments

Comments
 (0)