Implementing Public Key Authentication for Web Servers: Apache HTTP/HTTPS Client Certificate Setup


1 views

Traditional username/password authentication presents several challenges: password management overhead, phishing risks, and brute force vulnerabilities. Public key authentication, commonly used in SSH, offers a more secure alternative for web servers.

Apache's mod_ssl module supports client certificate authentication through these steps in httpd.conf or ssl.conf:

# Enable SSL client verification
SSLVerifyClient require
SSLVerifyDepth 1

# Point to CA certificate that issued client certs
SSLCACertificateFile /path/to/ca.crt

# Optional: Map certificates to users
SSLRequire %{SSL_CLIENT_S_DN_CN} in {"user1", "user2"}

Create client certificates using OpenSSL:

# Generate user key
openssl genrsa -out user.key 2048

# Create CSR
openssl req -new -key user.key -out user.csr

# Sign with CA (or self-sign)
openssl x509 -req -in user.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out user.crt -days 365

Users import the PKCS#12 bundle into their browser:

openssl pkcs12 -export -in user.crt -inkey user.key -out user.p12

Different browsers handle client certificates differently:

  • Chrome/Firefox: Prompt to select certificate from OS store
  • Safari: Requires certificates in macOS Keychain
  • Mobile: May need additional configuration for certificate deployment

For more flexibility, consider these architectures:

# Using TLS Client Auth with JWTs
if (req.headers['x-client-cert']) {
  const cert = verifyClientCertificate(req.headers['x-client-cert']);
  const jwt = generateSessionToken(cert.subject);
  res.setHeader('Authorization', Bearer ${jwt});
}
  • Implement certificate revocation (OCSP/CRL)
  • Set appropriate certificate lifetimes
  • Combine with additional factors for sensitive operations
  • Monitor for unusual certificate usage patterns

Enable detailed logging in Apache:

LogLevel debug
SSLOptions +StdEnvVars +ExportCertData

Check for common issues:

openssl verify -CAfile ca.crt user.crt
openssl s_client -connect example.com:443 -cert user.crt -key user.key

Password-based authentication creates multiple pain points:

- Credential management overhead
- Phishing vulnerability 
- Brute-force attack surface
- User experience friction

HTTPS client certificate authentication leverages the same PKI infrastructure used for server certificates. The workflow:

1. Server requests client cert during TLS handshake
2. Browser presents user's certificate
3. Server verifies against CA and authorized keys
4. Access granted without password exchange

Enable client cert verification in httpd.conf or virtual host:

SSLCACertificateFile /path/to/ca.crt
SSLVerifyClient require
SSLVerifyDepth 2
SSLOptions +StdEnvVars

Create user keys and sign with your CA:

# Generate user key
openssl genrsa -out user.key 2048

# Create CSR
openssl req -new -key user.key -out user.csr

# Sign with CA
openssl x509 -req -in user.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out user.crt -days 365

For Firefox/Chrome certificate import:

- Navigate to about:preferences#privacy
- Click "View Certificates" → "Your Certificates"
- Import PKCS#12 (.p12) file containing private key

Fine-grained access using SSL environment variables:

<Files "secure-area">
  SSLRequire (%{SSL_CLIENT_S_DN_CN} eq "authorized_user")
</Files>

For non-PKI scenarios consider:

- WebAuthn for hardware key authentication
- Mutual TLS (mTLS) with short-lived certificates
- JWT with asymmetric signatures

Enable verbose logging when troubleshooting:

LogLevel debug ssl:trace2
ErrorLog /var/log/httpd/ssl_error_log