HIGH clickjackingchimutual tls

Clickjacking in Chi with Mutual Tls

Clickjacking in Chi with Mutual Tls — how this specific combination creates or exposes the vulnerability

Clickjacking is a client-side attack that tricks a user into interacting with invisible or disguised UI elements while authenticated to an application. In Chi, a Go HTTP router commonly used for APIs and web services, clickjacking typically arises when responses do not enforce frame-embedding protections. Adding Mutual TLS (mTLS) changes the threat model: the server now also verifies the client’s certificate, which ensures the client is known and trusted for transport-layer identity. However, mTLS does nothing to prevent a compromised or malicious browser from embedding the server’s protected endpoints inside an invisible frame. An authenticated client with a valid certificate can still be lured to a malicious site that performs click interactions via iframes and pointer events. Because mTLS confirms client identity, an attacker may leverage that trusted session to perform privileged actions on behalf of the client, such as changing settings or initiating transactions, without the server detecting unauthorized UI interaction. The server sees a legitimate mTLS-authenticated request, so traditional UI-level defenses like CSRF tokens can be mistakenly assumed sufficient, but they do not mitigate UI redressing. Consequently, the combination of Chi routing with mTLS can expose clickjacking risks if frame-ancestors and related browser protections are not explicitly enforced in HTTP response headers or within application logic.

Mutual Tls-Specific Remediation in Chi — concrete code fixes

Remediation requires both transport-layer mTLS configuration in Chi and explicit UI-level defenses. On the server side, enforce mTLS in Chi by configuring TLS with client certificate verification and by validating the presented certificate details before processing requests. On the client side, prevent framing by setting Content-Security-Policy frame-ancestors, and include X-Frame-Options and X-Content-Type-Options headers. Below are concrete examples for a Chi application in Go that enforces mTLS and adds security headers to mitigate clickjacking.

Mutual TLS setup in Chi

Configure Chi with a TLS configuration that requests and verifies client certificates. The server loads its own certificate and private key, and specifies a trusted CA pool to validate incoming client certificates.

package main

import (
    "crypto/tls"
    "crypto/x509"
    "io/ioutil"
    "net/http"

    "github.com/go-chi/chi/v5"
    "github.com/go-chi/chi/v5/middleware"
)

func main() {
    // Load server certificate and key
    cert, err := tls.LoadX509KeyPair("server.crt", "server.key")
    if err != nil {
        panic(err)
    }

    // Load and parse the CA that issued client certificates
    caCert, err := ioutil.ReadFile("ca.crt")
    if err != nil {
        panic(err)
    }
    caCertPool := x509.NewCertPool()
    if ok := caCertPool.AppendCertsFromPEM(caCert); !ok {
        panic("failed to add CA cert")
    }

    // Configure TLS with client certificate verification
    tlsConfig := &tls.Config{
        Certificates:       []tls.Certificate{cert},
        ClientAuth:         tls.RequireAndVerifyClientCert,
        ClientCAs:          caCertPool,
        InsecureSkipVerify: false,
    }

    r := chi.NewRouter()
    r.Use(middleware.RequestID)
    r.Use(middleware.RealIP)
    r.Use(middleware.Secure)

    // Example protected endpoint
    r.Get("/transfer", func(w http.ResponseWriter, r *http.Request) {
        // The request is already mTLS-authenticated at this point
        // Additional application-level authorization should still apply
        w.Write([]byte("secure transfer endpoint"))
    })

    server := &http.Server{
        Addr:      ":8443",
        Handler:   r,
        TLSConfig: tlsConfig,
    }

    // ServeTLS requires server.crt and server.key
    http.ListenAndServeTLS(server.Addr, "server.crt", "server.key", server)
}

Clickjacking defenses in Chi handlers

Even with mTLS, include security headers in responses to prevent framing. You can add these headers via Chi middleware or in a middleware wrapper.

func SecurityHeadersMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Prevent framing by any origin
        w.Header().Set("Content-Security-Policy", "frame-ancestors 'self'")
        // Legacy browser protection
        w.Header().Set("X-Frame-Options", "DENY")
        // Prevent MIME sniffing
        w.Header().Set("X-Content-Type-Options", "nosniff")
        next.ServeHTTP(w, r)
    })
}

func main() {
    r := chi.NewRouter()
    r.Use(SecurityHeadersMiddleware)
    // ... routes and mTLS configuration as above
}

These headers ensure that browsers do not render the application’s pages inside iframes on other origins, directly mitigating clickjacking. Combine this with per-route or global CSRF tokens for state-changing operations to provide defense-in-depth when mTLS is used for client authentication.

Frequently Asked Questions

Does mTLS alone prevent clickjacking in Chi applications?
No. Mutual TLS authenticates the client at the transport layer but does not prevent a trusted client’s browser from being embedded in an invisible frame. You must still enforce Content-Security-Policy frame-ancestors, X-Frame-Options, and related UI-level protections to prevent clickjacking.
How should I validate client certificates in Chi when using mTLS?
In Chi, enforce mTLS by configuring Go’s http.Server with a tls.Config that sets ClientAuth to tls.RequireAndVerifyClientCert and providing a trusted CA pool via ClientCAs. This ensures that only clients presenting certificates signed by the trusted CA can establish a connection.