Java Servlet如何在代码中记录请求及服务端HTTP请求的TLS版本?
Hey Brad, great question—targeted TLS version logging is way more useful than sifting through verbose VM-wide logs. Let’s break this down into two key scenarios: logging TLS versions when your app receives incoming requests and when it makes outgoing server-side HTTP calls, with practical examples for common tech stacks.
The goal here is to capture the TLS version negotiated between the client and your app’s web server (or reverse proxy) at the point your application processes the request.
Example 1: Java Spring Boot
Use a custom Filter to intercept requests and extract TLS details from the servlet context:
import jakarta.servlet.*; import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; public class TLSLoggingFilter implements Filter { private static final Logger logger = LoggerFactory.getLogger(TLSLoggingFilter.class); @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; String cipherSuite = (String) httpRequest.getAttribute("javax.servlet.request.cipher_suite"); String tlsVersion = parseTLSVersion(cipherSuite); logger.info("Incoming request TLS version: {}", tlsVersion); chain.doFilter(request, response); } private String parseTLSVersion(String cipherSuite) { if (cipherSuite == null) return "No TLS (HTTP)"; if (cipherSuite.startsWith("TLS_AES_") || cipherSuite.startsWith("TLS_CHACHA20_")) return "TLS 1.3"; if (cipherSuite.contains("_TLS1_2_")) return "TLS 1.2"; return "TLS 1.0/1.1"; } }
Register this filter in your Spring config, and adjust the filter mapping if you only want to log specific endpoints.
Example 2: Node.js (Express)
Express exposes the underlying TLS socket directly via the request object—you can grab the protocol in a middleware:
const express = require('express'); const app = express(); const logger = require('./your-app-logger'); // Use your existing logger (Winston, Pino, etc.) app.use((req, res, next) => { if (req.socket.encrypted) { const tlsVersion = req.socket.getProtocol(); logger.info(`Incoming request TLS version: ${tlsVersion}`); } else { logger.info("Incoming request uses HTTP (no TLS)"); } next(); }); // Your route handlers here app.get('/api/resource', (req, res) => res.send("Success"));
Example 3: Python (Flask)
If your app runs behind a reverse proxy (like Nginx), configure the proxy to pass the TLS version via a request header (e.g., X-SSL-Protocol), then access it in a before-request hook:
from flask import Flask, request import logging app = Flask(__name__) logger = logging.getLogger(__name__) @app.before_request def log_tls_version(): tls_version = request.headers.get('X-SSL-Protocol') or request.environ.get('SSL_PROTOCOL') if tls_version: logger.info(f"Incoming request TLS version: {tls_version}") else: logger.info("Incoming request uses HTTP (no TLS)") @app.route('/api/resource') def get_resource(): return {"status": "ok"}
For Nginx, add this to your location block to forward the header:
proxy_set_header X-SSL-Protocol $ssl_protocol;
Here, you’ll hook into your app’s HTTP client to capture the TLS version negotiated with the target server.
Example 1: Java (RestTemplate)
Use a custom ClientHttpRequestInterceptor to inspect the underlying HTTPS connection:
import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.HttpsURLConnection; import java.io.IOException; public class TLSLoggingInterceptor implements ClientHttpRequestInterceptor { private static final Logger logger = LoggerFactory.getLogger(TLSLoggingInterceptor.class); @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { ClientHttpResponse response = execution.execute(request, body); HttpsURLConnection conn = (HttpsURLConnection) ((SimpleClientHttpRequestFactory.DefaultClientHttpResponse) response).getRawConnection(); String tlsVersion = conn.getCipherSuite().contains("TLS_AES_") ? "TLS 1.3" : conn.getCipherSuite().contains("_TLS1_2_") ? "TLS 1.2" : "TLS 1.0/1.1"; logger.info("Outgoing request to {} TLS version: {}", request.getURI(), tlsVersion); return response; } } // Register the interceptor with RestTemplate RestTemplate restTemplate = new RestTemplate(); restTemplate.getInterceptors().add(new TLSLoggingInterceptor());
Example 2: Node.js (Axios)
Use a custom HTTPS agent to listen for the secureConnect event, which fires when TLS handshake completes:
const axios = require('axios'); const https = require('https'); const logger = require('./your-app-logger'); const httpsAgent = new https.Agent({ rejectUnauthorized: true }); httpsAgent.on('secureConnect', (socket) => { const tlsVersion = socket.getProtocol(); logger.info(`Outgoing request TLS version: ${tlsVersion}`); }); // Attach the agent to your Axios instance const axiosInstance = axios.create({ httpsAgent }); // Example request axiosInstance.get('https://api.target.com/data') .then(res => console.log(res.data)) .catch(err => console.error(err));
For better URL tracking, pair this with an Axios request interceptor to log the target URL alongside the TLS version.
Example 3: Python (Requests)
Create a custom HTTPAdapter to access the underlying TLS connection after the handshake:
import requests from requests.adapters import HTTPAdapter import logging logger = logging.getLogger(__name__) class TLSLoggingAdapter(HTTPAdapter): def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None): response = super().send(request, stream, timeout, verify, cert, proxies) conn = response.raw._connection if hasattr(conn, 'sock') and hasattr(conn.sock, 'version'): tls_version = conn.sock.version() logger.info(f"Outgoing request to {request.url} TLS version: {tls_version}") return response // Use the adapter with a Requests session session = requests.Session() session.mount('https://', TLSLoggingAdapter()) // Example request session.get('https://api.target.com/data')
- Stay targeted: Focus logging on specific request lifecycle points (incoming filters, outgoing client interceptors) instead of enabling broad VM-level logs.
- Leverage platform APIs: Most frameworks and HTTP clients expose access to the underlying TLS socket/connection, which holds the negotiated version.
- Proxy awareness: If using a reverse proxy, ensure it forwards TLS details to your app via request headers if you can’t access the socket directly.
内容的提问来源于stack exchange,提问作者Brad Parks

