X-SSL-Client-DN trust gated only on isLoopback() — split into a dedicated certAuthTrusted() hook #5
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Location:
include/oatpp-authkit/auth/AuthInterceptor.hpp:120-130andIRuntimeConfig.hppCert-DN auth is granted whenever
IRuntimeConfig::isLoopback()is true. Operators binding to127.0.0.1but exposing the port via SSH tunnel or a non-TLS proxy that forwardsX-SSL-Client-DNfrom untrusted clients can be impersonated. Add a dedicatedcertAuthTrusted()hook (or stripX-SSL-Client-DNfrom untrusted ingress before downstream handlers see it).From audit #1.
Agent Evaluation
Feasibility: Small. The current trust path is a single
if (m_runtime->isLoopback() && certDnH && !certDnH->empty())inAuthInterceptor.hpp:120-130. The remediation is two small additions: a new policy/runtime hook and (optionally) stripping the header on untrusted ingress.Impact: High if exploited, low probability. The audit framing is right: a misconfigured nginx that copies
X-SSL-Client-DNfrom untrusted clients, an SSH tunnel to a loopback bind, or an operator who flipsbindAddresswithout realising — any of those turns a single forgeable header into full impersonation of any cert user. The cost of fixing is low and the failure mode is silent (no log line, no test catches it), so the cost/benefit is good.Effort: Small.
Recommendation: Accept.
Implementation plan
IRuntimeConfig::certAuthTrusted()— a new virtual returningbool. Default impl:return isLoopback();so existing consumers keep their behaviour. Consumers that want stricter gating override it (e.g. "trust X-SSL-Client-DN only when both bound to loopback AND the consumer-controlledTRUST_CERT_DNenv var is set").AuthInterceptor::interceptfromisLoopback()→certAuthTrusted().X-SSL-Client-DNfrom the request whencertAuthTrusted()returns false, so downstream handlers cannot accidentally read it either. (oatpp'sIncomingRequestexposes mutable headers viagetHeaders()/putHeader— a remove API may not exist; in that case set to empty string and document.)IRuntimeConfig::isLoopback()to clarify it is the binding gate (used for trusted XFF / X-Real-IP); cert-DN trust now flows through the new hook.certAuthTrusted=false+ a forgedX-SSL-Client-DNheader → expect the interceptor to ignore it and fall through to token auth.Decision needed
Check one (edit this comment):
IRuntimeConfig::certAuthTrusted(), defaults toisLoopback()— backwards compatible, no consumer break, opt-in stricter behaviour.isLoopback()→certAuthTrusted()— single concept; cleaner long-term but a breaking change for every downstream that overridesisLoopback()(currently fewo-webapp does). Bump major version.isLoopback()deprecated — A's API surface plus a[[deprecated]]warning onisLoopback()to migrate consumers over a release cycle. Most polite, slightly more code to remove later.Default recommendation: A (cheapest, no downstream churn). Option C if the library is heading toward v1.0 soon and we want a deprecation window.
Evaluated #5 — Small, recommend accept; A/B/C decision on new hook vs rename vs deprecate.
Implemented #5 → commit
bccd57f, tag v0.3.5 (Option A: new certAuthTrusted() hook defaulting to isLoopback(); AuthInterceptor consults the hook).