Broken Authentication in Phoenix with Mutual Tls
Broken Authentication in Phoenix with Mutual Tls — how this specific combination creates or exposes the vulnerability
Broken Authentication in a Phoenix API combined with Mutual TLS (mTLS) can create a scenario where strong transport-layer authentication exists, but application-level identity validation remains weak. mTLS ensures that both client and server present valid certificates, establishing a secure channel. However, if Phoenix endpoints rely solely on the presence of a client certificate without mapping it to a verified user or role, authentication is incomplete. An attacker who obtains a valid client certificate can bypass credential-based checks and access privileged endpoints because the server trusts the certificate but does not enforce proper authorization.
For example, consider a Phoenix controller that retrieves the client certificate from the connection and assumes it contains the user identity. If the certificate Common Name (CN) is used directly as a user identifier without server-side verification against an identity store, this creates an authentication bypass. A compromised certificate or a misconfigured CA that issues certificates to unauthorized parties leads to Broken Authentication. Additionally, if session tokens or cookies issued after mTLS authentication lack proper rotation, expiration, or binding to the certificate context, they can be reused or hijacked.
This pattern is distinct from standard OAuth or JWT-based flows because mTLS provides transport assurance but does not automatically enforce application-level permissions. The OWASP API Top 10 category for Broken Authentication applies here when mTLS is treated as the single source of truth for identity. Real-world cases include systems that expose administrative endpoints under /api/admin and rely only on mTLS without checking scopes or roles encoded in certificate extensions. Without additional checks, any holder of a trusted certificate can perform actions intended for specific users or service accounts.
middleBrick can detect such misconfigurations by scanning the unauthenticated attack surface and correlating endpoint behavior with the OpenAPI specification. For instance, if an endpoint requires a client certificate but does not validate input beyond certificate presence, middleBrick flags this as a Broken Authentication finding with severity and remediation guidance. This helps teams avoid treating mTLS as a complete authentication solution.
Mutual Tls-Specific Remediation in Phoenix — concrete code fixes
To remediate Broken Authentication in Phoenix when using mTLS, you must bind the certificate to a verified identity and enforce role-based access control at the application layer. Below are specific code examples that demonstrate a secure approach.
1. Retrieve and verify the client certificate in a plug, then map it to a user in your data store:
defmodule MyAppWeb.Plugs.VerifyCertificate do
import Plug.Conn
def init(opts), do: opts
def call(conn, _opts) do
case get_peer_cert(conn) do
nil ->
conn
|> put_status(:forbidden)
|> Phoenix.Controller.json(%{error: "client certificate required"})
|> halt()
cert_der ->
subject = extract_subject(cert_der)
case MyApp.Accounts.lookup_by_certificate(subject) do
nil ->
conn
|> put_status(:forbidden)
|> Phoenix.Controller.json(%{error: "certificate not authorized"})
|> halt()
user ->
assign(conn, :current_user, user)
end
end
end
defp get_peer_cert(conn) do
conn.private[:ssl_peer_cert]
end
defp extract_subject(cert_der) when is_binary(cert_der) do
{:ok, cert} = :public_key.pkix_decode_cert(cert_der, :otp)
{:rdn_sequence, rdn} = cert.tbs_certificate.subject
# Extract CN from RDN for simplicity; in production use OTP certificate parsing robustly
List.flatten(rdn)
|> Enum.find_value(fn {"2.5.4.3", common_name} -> common_name end)
end
end
2. Use the verified user in your controller and apply role checks:
defmodule MyAppWeb.AdminController do
use MyAppWeb, :controller
alias MyAppWeb.Plugs.VerifyCertificate
plug VerifyCertificate when action in [:index, :create]
def index(conn, _params) do
if MyApp.Accounts.admin?(@conn.assigns.current_user) do
json(conn, %{admins: MyApp.Accounts.list_admins()})
else
conn
|> put_status(:forbidden)
|> json(%{error: "insufficient permissions"})
end
end
end
3. In your endpoint configuration, ensure mTLS is enforced at the connection level and that the client certificate is not trusted implicitly:
# config/runtime.exs
import Config
config :my_app, MyAppWeb.Endpoint,
https: [
port: 443,
cipher_suite: :strong,
keyfile: System.fetch_env!("SSL_KEY_PATH"),
certfile: System.fetch_env!("SSL_CERT_PATH"),
# Verify client certificates but do not rely solely on transport identity
verify: :verify_peer,
fail_if_no_peer_cert: true
]
These steps ensure that mTLS is used for transport security while application-level authentication validates identity and permissions. middleBrick supports this workflow by scanning your OpenAPI spec and runtime behavior; with the Pro plan you can enable continuous monitoring so that changes to certificate handling or endpoint permissions are flagged promptly.
Related CWEs: authentication
| CWE ID | Name | Severity |
|---|---|---|
| CWE-287 | Improper Authentication | CRITICAL |
| CWE-306 | Missing Authentication for Critical Function | CRITICAL |
| CWE-307 | Brute Force | HIGH |
| CWE-308 | Single-Factor Authentication | MEDIUM |
| CWE-309 | Use of Password System for Primary Authentication | MEDIUM |
| CWE-347 | Improper Verification of Cryptographic Signature | HIGH |
| CWE-384 | Session Fixation | HIGH |
| CWE-521 | Weak Password Requirements | MEDIUM |
| CWE-613 | Insufficient Session Expiration | MEDIUM |
| CWE-640 | Weak Password Recovery | HIGH |