Skip to content

Conversation

@romanornr
Copy link
Contributor

What ❔

  • Add MAX_CLOCK_SKEW_SECONDS (30s) constant
  • Reject timestamps > now + 30 seconds
  • Add logging for rejected future timestamps
  • Add test for future timestamp validatio

Why ❔

Line A

let timestamp_diff = timestamp_now - parsed_timestamp;

Line B

if timestamp_diff > state.state.verifier_request_timeout.into() {  // Line B
    return Err(ApiError::Unauthorized("Timestamp is too old".into()));
}

Let's say verifier_request_timeout = 60 seconds)
The check asks:

Scenario 30 seconds ago:
timestamp_diff = +30
is it > 60 ?
result = Allowed

Scenario 90 seconds ago:
timestamp_diff = +30
Is it > 60 ?
result = Rejected too old

5 years in future
timestamp_diff
is it > 60?
result = Allowed

The negative number is always less than the postive timeout, so it always passes

Better to don't allow future timestamps.
60 seconds for verifier_request_timeout is fine to account for network delays, processing
30 seconds max_clock_skew_seconds since it only needs to handle clock sync drift

Checklist

  • PR title corresponds to the body of PR (we generate changelog entries from PRs).
  • Tests for the changes have been added / updated.
  • Documentation comments have been added / updated.
  • Code has been formatted via zkstack dev fmt and zkstack dev lint.

@gemini-code-assist
Copy link

Summary of Changes

Hello @romanornr, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a potential vulnerability in the via_verifier_coordinator's authentication middleware by preventing the acceptance of timestamps that are significantly in the future. Previously, only past timestamps were validated, leaving a loophole where extremely future timestamps could bypass the age check. The change introduces a maximum allowed clock skew, ensuring that requests with timestamps too far ahead of the server's current time are rejected, thereby enhancing the robustness of the authentication mechanism.

Highlights

  • Security Enhancement: Introduced a MAX_CLOCK_SKEW_SECONDS constant (30 seconds) to define the maximum allowed future timestamp.
  • Timestamp Validation: Implemented logic to reject incoming timestamps that are more than 30 seconds ahead of the current server time.
  • Improved Observability: Added logging for instances where future timestamps are rejected, aiding in debugging and monitoring.
  • Test Coverage: Included a new test case (test_future_timestamp_validation) to ensure the future timestamp rejection logic functions correctly, including boundary conditions.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request correctly addresses a vulnerability where far-future timestamps were not being rejected. A constant MAX_CLOCK_SKEW_SECONDS is introduced, and a check is added to validate incoming timestamps against it. My review includes a suggestion to improve the clarity of the timestamp validation logic and a more significant recommendation to refactor the new test, which currently doesn't validate the implementation, into a proper unit test by extracting the core logic into a testable function.

Comment on lines +256 to +268
#[test]
fn test_future_timestamp_validation() {
let now = chrono::Utc::now().timestamp();

// Boundary tests for MAX_CLOCK_SKEW_SECONDS (30 seconds)
assert!(now + 10 <= now + MAX_CLOCK_SKEW_SECONDS);
assert!(now + 30 <= now + MAX_CLOCK_SKEW_SECONDS);
assert!(now + 31 > now + MAX_CLOCK_SKEW_SECONDS);

// Far-future timestamps must be rejected (VIA-AUTH-003)
let far_future = now + 157_680_000;
assert!(far_future > now + MAX_CLOCK_SKEW_SECONDS);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This test doesn't validate the implementation logic. The assertions are tautological; for example, assert!(now + 10 <= now + MAX_CLOCK_SKEW_SECONDS) simplifies to assert!(10 <= 30), which is always true and doesn't depend on the code under test. This provides a false sense of security.

A more effective approach would be to extract the timestamp validation logic into a separate, easily testable function. This would allow for proper unit testing of the boundary conditions.

Here's an example of how you could refactor:

  1. Extract the logic into a new function:

    fn check_timestamp_skew(
        parsed_timestamp: i64,
        now: i64,
        max_age_secs: i64,
        max_skew_secs: i64,
    ) -> Result<(), &'static str> {
        let diff = now - parsed_timestamp;
        if diff > max_age_secs {
            return Err("Timestamp is too old");
        }
        if diff < -max_skew_secs {
            return Err("Timestamp is too far in the future");
        }
        Ok(())
    }
  2. Write a meaningful test for it:

    #[test]
    fn test_timestamp_skew_validation() {
        let now = 1_000_000;
        let max_age = 60;
        let max_skew = 30;
    
        // Valid timestamps
        assert!(check_timestamp_skew(now, now, max_age, max_skew).is_ok());
        assert!(check_timestamp_skew(now - max_age, now, max_age, max_skew).is_ok());
        assert!(check_timestamp_skew(now + max_skew, now, max_age, max_skew).is_ok());
    
        // Invalid timestamps
        assert_eq!(check_timestamp_skew(now - max_age - 1, now, max_age, max_skew), Err("Timestamp is too old"));
        assert_eq!(check_timestamp_skew(now + max_skew + 1, now, max_age, max_skew), Err("Timestamp is too far in the future"));
    }

This approach ensures your logic is correctly tested and makes the code more modular.

Comment on lines +65 to +68
if parsed_timestamp > timestamp_now + MAX_CLOCK_SKEW_SECONDS {
tracing::warn!("Reject timestamp from verifier {}: {} seconds ahead of current time", verifier_index, parsed_timestamp - timestamp_now);
return Err(ApiError::Unauthorized("Timestamp is too far in the future".into()));
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While this check is correct, it can be made more consistent with the check for old timestamps by reusing the timestamp_diff variable that is already calculated. This improves code clarity by handling both past and future timestamp checks in a more symmetrical way.

Suggested change
if parsed_timestamp > timestamp_now + MAX_CLOCK_SKEW_SECONDS {
tracing::warn!("Reject timestamp from verifier {}: {} seconds ahead of current time", verifier_index, parsed_timestamp - timestamp_now);
return Err(ApiError::Unauthorized("Timestamp is too far in the future".into()));
}
if timestamp_diff < -MAX_CLOCK_SKEW_SECONDS {
tracing::warn!("Reject timestamp from verifier {}: {} seconds ahead of current time", verifier_index, -timestamp_diff);
return Err(ApiError::Unauthorized("Timestamp is too far in the future".into()));
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant