mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-24 22:45:19 +00:00
fix(security): reduce timestamp validation window to ±5 minutes
BCH-01-011: Reduces replay attack window from ±1 hour to ±5 minutes. The previous 1-hour window allowed extended replay attacks. A 5-minute window is industry standard for replay protection while accommodating reasonable clock drift. - Updated InputValidator.validateTimestamp to use 300-second window - Updated tests to verify new boundary conditions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -52,11 +52,13 @@ struct InputValidator {
|
|||||||
// MessageType/NoisePayloadType enums; keeping validator free of stale lists.
|
// MessageType/NoisePayloadType enums; keeping validator free of stale lists.
|
||||||
|
|
||||||
/// Validates timestamp is reasonable (not too far in past or future)
|
/// Validates timestamp is reasonable (not too far in past or future)
|
||||||
|
/// BCH-01-011: Reduced from ±1 hour to ±5 minutes to limit replay attack window
|
||||||
static func validateTimestamp(_ timestamp: Date) -> Bool {
|
static func validateTimestamp(_ timestamp: Date) -> Bool {
|
||||||
let now = Date()
|
let now = Date()
|
||||||
let oneHourAgo = now.addingTimeInterval(-3600)
|
// 5 minutes = 300 seconds (industry standard for replay protection)
|
||||||
let oneHourFromNow = now.addingTimeInterval(3600)
|
let fiveMinutesAgo = now.addingTimeInterval(-300)
|
||||||
return timestamp >= oneHourAgo && timestamp <= oneHourFromNow
|
let fiveMinutesFromNow = now.addingTimeInterval(300)
|
||||||
|
return timestamp >= fiveMinutesAgo && timestamp <= fiveMinutesFromNow
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ struct InputValidatorTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Timestamp Validation Tests
|
// MARK: - Timestamp Validation Tests
|
||||||
|
// BCH-01-011: Window reduced from ±1 hour to ±5 minutes
|
||||||
|
|
||||||
@Test func currentTimestampIsValid() throws {
|
@Test func currentTimestampIsValid() throws {
|
||||||
let now = Date()
|
let now = Date()
|
||||||
@@ -138,31 +139,48 @@ struct InputValidatorTests {
|
|||||||
#expect(result == true)
|
#expect(result == true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func timestampWithinOneHourIsValid() throws {
|
@Test func timestampWithinFiveMinutesIsValid() throws {
|
||||||
|
// 2 minutes ago should be valid (within 5-minute window)
|
||||||
|
let twoMinutesAgo = Date().addingTimeInterval(-2 * 60)
|
||||||
|
let result = InputValidator.validateTimestamp(twoMinutesAgo)
|
||||||
|
#expect(result == true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test func timestampThirtyMinutesAgoIsInvalid() throws {
|
||||||
|
// BCH-01-011: 30 minutes is now outside the 5-minute window
|
||||||
let thirtyMinutesAgo = Date().addingTimeInterval(-30 * 60)
|
let thirtyMinutesAgo = Date().addingTimeInterval(-30 * 60)
|
||||||
let result = InputValidator.validateTimestamp(thirtyMinutesAgo)
|
let result = InputValidator.validateTimestamp(thirtyMinutesAgo)
|
||||||
#expect(result == true)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test func timestampTwoHoursAgoIsInvalid() throws {
|
|
||||||
let twoHoursAgo = Date().addingTimeInterval(-2 * 3600)
|
|
||||||
let result = InputValidator.validateTimestamp(twoHoursAgo)
|
|
||||||
#expect(result == false)
|
#expect(result == false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func timestampTwoHoursInFutureIsInvalid() throws {
|
@Test func timestampTenMinutesAgoIsInvalid() throws {
|
||||||
let twoHoursFromNow = Date().addingTimeInterval(2 * 3600)
|
// 10 minutes is outside the 5-minute window
|
||||||
let result = InputValidator.validateTimestamp(twoHoursFromNow)
|
let tenMinutesAgo = Date().addingTimeInterval(-10 * 60)
|
||||||
|
let result = InputValidator.validateTimestamp(tenMinutesAgo)
|
||||||
#expect(result == false)
|
#expect(result == false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func timestampAtOneHourBoundaryIsValid() throws {
|
@Test func timestampTenMinutesInFutureIsInvalid() throws {
|
||||||
// Just slightly within the one-hour window
|
// 10 minutes in future is outside the 5-minute window
|
||||||
let almostOneHourAgo = Date().addingTimeInterval(-3599)
|
let tenMinutesFromNow = Date().addingTimeInterval(10 * 60)
|
||||||
let result = InputValidator.validateTimestamp(almostOneHourAgo)
|
let result = InputValidator.validateTimestamp(tenMinutesFromNow)
|
||||||
|
#expect(result == false)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test func timestampAtFiveMinuteBoundaryIsValid() throws {
|
||||||
|
// Just slightly within the five-minute window (299 seconds)
|
||||||
|
let almostFiveMinutesAgo = Date().addingTimeInterval(-299)
|
||||||
|
let result = InputValidator.validateTimestamp(almostFiveMinutesAgo)
|
||||||
#expect(result == true)
|
#expect(result == true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test func timestampJustOutsideFiveMinuteWindowIsInvalid() throws {
|
||||||
|
// Just outside the five-minute window (301 seconds)
|
||||||
|
let justOverFiveMinutesAgo = Date().addingTimeInterval(-301)
|
||||||
|
let result = InputValidator.validateTimestamp(justOverFiveMinutesAgo)
|
||||||
|
#expect(result == false)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Edge Cases
|
// MARK: - Edge Cases
|
||||||
|
|
||||||
@Test func singleCharacterStringIsAccepted() throws {
|
@Test func singleCharacterStringIsAccepted() throws {
|
||||||
|
|||||||
Reference in New Issue
Block a user