feat(#284): Reduce timestamp validation window to 60s with replay attack prevention
Security improvements: - Reduce timestamp tolerance from 5 minutes to 60 seconds - Add nonce-based replay attack prevention using Redis - Store signature nonce with 60s TTL matching tolerance window - Reject replayed messages with same signature Changes: - Update SignatureService.TIMESTAMP_TOLERANCE_MS to 60s - Add Redis client injection to SignatureService - Make verifyConnectionRequest async for nonce checking - Create RedisProvider for shared Redis client - Update ConnectionService to await signature verification - Add comprehensive test coverage for replay prevention Part of M7.1 Remediation Sprint P1 security fixes. Fixes #284 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -102,7 +102,7 @@ describe("ConnectionService", () => {
|
||||
provide: SignatureService,
|
||||
useValue: {
|
||||
signMessage: vi.fn().mockResolvedValue("mock-signature"),
|
||||
verifyConnectionRequest: vi.fn().mockReturnValue({ valid: true }),
|
||||
verifyConnectionRequest: vi.fn().mockResolvedValue({ valid: true }),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -441,7 +441,7 @@ describe("ConnectionService", () => {
|
||||
});
|
||||
|
||||
it("should create pending connection for valid request", async () => {
|
||||
vi.spyOn(signatureService, "verifyConnectionRequest").mockReturnValue({ valid: true });
|
||||
vi.spyOn(signatureService, "verifyConnectionRequest").mockResolvedValue({ valid: true });
|
||||
vi.spyOn(prismaService.federationConnection, "create").mockResolvedValue(mockConnection);
|
||||
|
||||
const result = await service.handleIncomingConnectionRequest(mockWorkspaceId, mockRequest);
|
||||
@@ -451,7 +451,7 @@ describe("ConnectionService", () => {
|
||||
});
|
||||
|
||||
it("should reject request with invalid signature", async () => {
|
||||
vi.spyOn(signatureService, "verifyConnectionRequest").mockReturnValue({
|
||||
vi.spyOn(signatureService, "verifyConnectionRequest").mockResolvedValue({
|
||||
valid: false,
|
||||
error: "Invalid signature",
|
||||
});
|
||||
@@ -462,7 +462,7 @@ describe("ConnectionService", () => {
|
||||
});
|
||||
|
||||
it("should log incoming connection attempt", async () => {
|
||||
vi.spyOn(signatureService, "verifyConnectionRequest").mockReturnValue({ valid: true });
|
||||
vi.spyOn(signatureService, "verifyConnectionRequest").mockResolvedValue({ valid: true });
|
||||
vi.spyOn(prismaService.federationConnection, "create").mockResolvedValue(mockConnection);
|
||||
const auditSpy = vi.spyOn(auditService, "logIncomingConnectionAttempt");
|
||||
|
||||
@@ -477,7 +477,7 @@ describe("ConnectionService", () => {
|
||||
});
|
||||
|
||||
it("should log connection created on success", async () => {
|
||||
vi.spyOn(signatureService, "verifyConnectionRequest").mockReturnValue({ valid: true });
|
||||
vi.spyOn(signatureService, "verifyConnectionRequest").mockResolvedValue({ valid: true });
|
||||
vi.spyOn(prismaService.federationConnection, "create").mockResolvedValue(mockConnection);
|
||||
const auditSpy = vi.spyOn(auditService, "logIncomingConnectionCreated");
|
||||
|
||||
@@ -492,7 +492,7 @@ describe("ConnectionService", () => {
|
||||
});
|
||||
|
||||
it("should log connection rejected on invalid signature", async () => {
|
||||
vi.spyOn(signatureService, "verifyConnectionRequest").mockReturnValue({
|
||||
vi.spyOn(signatureService, "verifyConnectionRequest").mockResolvedValue({
|
||||
valid: false,
|
||||
error: "Invalid signature",
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user