@@ -202,80 +202,61 @@ def self.valid_timestamp?(headers, config)
202202 return false if timestamp_value . strip . empty?
203203
204204 parsed_timestamp = parse_timestamp ( timestamp_value . strip )
205- return false unless parsed_timestamp
205+ return false unless parsed_timestamp . is_a? ( Integer )
206206
207- # parsed_timestamp is a Time object
208- now = Time . now . utc
207+ now = Time . now . utc . to_i
209208 ( now - parsed_timestamp ) . abs <= tolerance
210209 end
211210
212211 # Parse timestamp value supporting both ISO 8601 UTC and Unix formats
213- #
214- # Attempts to parse the timestamp in the following order:
215- # 1. ISO 8601 UTC format (e.g., "2025-06-12T10:30:00Z")
216- # 2. Unix timestamp (e.g., "1609459200")
217- #
218- # @param timestamp_value [String] The timestamp string to parse
219- # @return [Time, nil] Time object if parsing succeeds, nil otherwise
220- # @note Security: Strict validation prevents various injection attacks
221- # @api private
222212 def self . parse_timestamp ( timestamp_value )
223- # Try ISO 8601 first, then Unix
213+ # Reject if contains any control characters, whitespace, or null bytes
214+ if timestamp_value =~ /[\u0000 -\u001F \u007F -\u009F ]/
215+ log . warn ( "Auth::HMAC validation failed: Timestamp contains invalid characters" )
216+ return nil
217+ end
218+ if timestamp_value != timestamp_value . strip
219+ log . warn ( "Auth::HMAC validation failed: Timestamp contains leading/trailing whitespace" )
220+ return nil
221+ end
224222 ts = parse_iso8601_timestamp ( timestamp_value )
225223 return ts if ts
226224 ts = parse_unix_timestamp ( timestamp_value )
227225 return ts if ts
228- nil
226+
227+ # If neither format matches, return nil
228+ log . warn ( "Auth::HMAC validation failed: Timestamp (#{ timestamp_value } ) is not valid ISO 8601 UTC or Unix format" )
229+ return nil
229230 end
230231
231- # Check if timestamp string looks like ISO 8601 UTC format
232- #
233- # @param timestamp_value [String] The timestamp string to check
234- # @return [Boolean] true if it appears to be ISO 8601 format
235- # @api private
232+ # Check if timestamp string looks like ISO 8601 UTC format (must have UTC indicator)
236233 def self . iso8601_timestamp? ( timestamp_value )
237- # Accepts Z, +00:00, or +0000, and T or space as separator
238- !!( timestamp_value =~ /\A \d {4}-\d {2}-\d {2}[T ]\d {2}:\d {2}:\d {2}(?:\. \d +)?(Z|\+ 00:00|\+ 0000)\z / )
234+ !!( timestamp_value =~ /\A \d {4}-\d {2}-\d {2}[T ]\d {2}:\d {2}:\d {2}(?:\. \d +)?(Z|\+ 00:00|\+ 0000)?\z / )
239235 end
240236
241- # Parse ISO 8601 UTC timestamp string
242- #
243- # @param timestamp_value [String] ISO 8601 timestamp string
244- # @return [Time, nil] Time object if parsing succeeds, nil otherwise
245- # @note Only accepts UTC timestamps (ending with 'Z' or explicit UTC)
246- # @api private
237+ # Parse ISO 8601 UTC timestamp string (must have UTC indicator)
247238 def self . parse_iso8601_timestamp ( timestamp_value )
248- # Normalize 'YYYY-MM-DD HH:MM:SS(.fraction)? +0000' to 'YYYY-MM-DDTHH:MM:SS(.fraction)?+00:00'
249239 if timestamp_value =~ /\A (\d {4}-\d {2}-\d {2}) (\d {2}:\d {2}:\d {2}(?:\. \d +)?)(?: )\+ 0000\z /
250240 timestamp_value = "#{ $1} T#{ $2} +00:00"
251241 end
252242 return nil unless iso8601_timestamp? ( timestamp_value )
253- t = Time . iso8601 ( timestamp_value ) rescue nil
243+ t = Time . parse ( timestamp_value ) rescue nil
254244 return nil unless t
255- # Only accept UTC (Z, +00:00, or +0000)
256- return t if t . utc? || t . utc_offset == 0
257- nil
245+ ( t . utc? || t . utc_offset == 0 ) ? t . to_i : nil
258246 end
259247
260- # Parse Unix timestamp string
261- #
262- # @param timestamp_value [String] Unix timestamp string
263- # @return [Time, nil] Time object if parsing succeeds, nil otherwise
264- # @api private
248+ # Parse Unix timestamp string (must be positive integer, no leading zeros except for "0")
265249 def self . parse_unix_timestamp ( timestamp_value )
266250 return nil unless unix_timestamp? ( timestamp_value )
267251 ts = timestamp_value . to_i
268252 return nil if ts <= 0
269- Time . at ( ts ) . utc
253+ ts
270254 end
271255
272- # Check if timestamp string looks like Unix timestamp format
273- #
274- # @param timestamp_value [String] The timestamp string to check
275- # @return [Boolean] true if it appears to be Unix timestamp format
276- # @api private
256+ # Check if timestamp string looks like Unix timestamp format (no leading zeros except "0")
277257 def self . unix_timestamp? ( timestamp_value )
278- !!( timestamp_value =~ /\A \d +\z / ) || timestamp_value == "0"
258+ return true if timestamp_value == "0"
259+ !!( timestamp_value =~ /\A [1-9]\d *\z / )
279260 end
280261
281262 # Compute HMAC signature based on configuration requirements
0 commit comments