fix(auth): normalize bearer-token comparison to fixed-size digests - #790
fix(auth): normalize bearer-token comparison to fixed-size digests#790seonghobae wants to merge 6 commits into
Conversation
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
|
Important Approval pendingCodeRabbit has no unresolved comments, but it has not reviewed the latest commit. Use the checkbox below to review the latest commit. CodeRabbit will approve the changes if it finds no blocking issues.
📝 WalkthroughWalkthroughBearer 토큰 검증이 토큰 길이를 먼저 비교하도록 변경되었습니다. 길이가 다르면 더미 ChangesBearer 토큰 인증
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: 🔵 Low · up to Authentication continues to reject invalid credentials with 401 responses, but the unequal-length comparison path may still expose token-length timing information, so the security hardening needs explicit owner follow-up before or alongside merge. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 2 files. (1 skipped: 1 unsupported.) ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| def test_authentication_constant_time_comparison_differing_lengths(): | ||
| '''Verify that tokens of different lengths do not leak length information.''' | ||
| settings = RuntimeSettings(api_token="valid_token") | ||
| app = create_app(settings) | ||
| client = TestClient(app) | ||
|
|
||
| response = client.post( | ||
| "/parse", | ||
| headers={"Authorization": "Bearer too_short"}, | ||
| files={"file": ("test.pdf", b"%PDF-1.4\n", "application/pdf")}, | ||
| ) | ||
| assert response.status_code == 401 |
|
|
||
| from fastapi.testclient import TestClient | ||
|
|
||
| import newsdom_api.main as main_module |
| "The configured parser authentication token is too long" | ||
| ) | ||
| object.__setattr__(self, "api_token", normalized_token) | ||
| object.__setattr__(self, "api_token_digest", hashlib.sha256(token_bytes).digest()) |
Security boundary
Python documents that
hmac.compare_digest()avoids content-based short-circuiting but can theoretically reveal operand type or length when the inputs have different lengths. The first version of this branch checked raw credential length and then calledcompare_digest(credentials, credentials)on the mismatch path. That self-comparison does not normalize the secret-dependent comparison boundary and a 401 response does not prove wall-clock equality.The repaired boundary keeps the existing 4 KiB Authorization-header admission limit, precomputes the configured token's SHA-256 digest once when immutable
RuntimeSettingsis created, hashes each bounded presented credential to the same 32-byte size, and invokeshmac.compare_digest()once on equal-length digests.RED → GREEN
faedf8d9103f8a510b35b49570124071cc875a36: require a precomputed fixed-size configured-token digest, equal-size operands atcompare_digest()for a mismatched credential, and preservation of exact-token authentication semantics.1d4e61de2a879561cfeeb7871c1d01cc37114fad: precompute the configured token digest outside the request path after normalization and length validation.139c8440b894690a2f0d6dea2d183409bbf5361f: hash the bounded presented credential and compare the two fixed-size digests exactly once.e35b37e858b8fafd272d1428b5bceb97e16ae45c: replace the inaccurate self-comparison/constant-time claim with the actual Python contract and implementation boundary.97e821d7575014de6580ed6e43307e8ede0799d1: record the current authentication contract, evidence, acceptance boundary, official Python traceability, and the remaining Keyverse identity-integration decision indocs/product-technical-gap-baseline.md.Exact current authority
develop@e06b1f3fb10903569124af011da213951e6e247397e821d7575014de6580ed6e43307e8ede0799d1Predecessor checks/reviews do not transfer after these commits. Keep Draft until this unchanged exact head has terminal tests, lint/type/quality and repository security checks plus current review/thread evidence. Do not add source-neutral retrigger commits, restore raw unequal-length comparison, claim a 401 latency test proves constant-time HTTP behavior, suppress findings, or weaken required gates.
Primary reference
Python Software Foundation. (2026). hmac — Keyed-hashing for message authentication. Python 3.14.7 documentation. Retrieved September 3, 2026, from https://docs.python.org/3/library/hmac.html