Spring Boot HTTPS API:为何允许不安全客户端连接?如何阻止?
问题背景
我使用Spring Boot Web(2.7.9)创建了一个仅作POC用途的REST API,它接受空POST请求并返回字符串响应,代码如下:
@RestController @RequestMapping("api/v1") public class Endpoint { @PostMapping("/start") public ResponseEntity<String> start(){ System.out.println("Came to start method"); return ResponseEntity.ok("Ok response"); } }
该API原本可通过HTTP正常访问:
curl --location --request POST 'http://endpointserver.mayanktests.in:8981/api/v1/start'
(endpointserver.mayanktests.in在hosts文件中映射到127.0.0.1)
之后我将其转换为HTTPS:使用OpenSSL生成本地根CA,创建由该CA签名的服务器证书,并导入到密钥库,配置如下:
server.port=8981 server.ssl.enabled=true server.ssl.key-store=classpath:keystore.p12 server.ssl.key-store-password=****** server.ssl.keyStoreType=PKCS12
此时原HTTP请求失败,使用HTTPS请求时,若不指定信任的CA会报错,但通过curl的--cacert指定rootCA.pem可正常访问:
curl --cacert rootCA.pem --location --request POST 'https://endpointserver.mayanktests.in:8981/api/v1/start'
然而客户端使用curl的-k(不安全)选项也能成功连接:
curl -k --location --request POST 'https://endpointserver.mayanktests.in:8981/api/v1/start'
疑问
- 为何不信任CA的客户端仍被允许建立连接?
- 如何阻止这类客户端访问我的HTTPS API?
解答
1. 不信任CA的客户端能连接的原因
当前的HTTPS配置仅开启了服务器单向认证:服务器会向客户端出示证书证明自身身份,但不会要求客户端提供可信证书来验证其身份。
curl的-k(或--insecure)选项的作用是跳过客户端对服务器证书的校验——即便客户端不认可服务器证书的签发CA,也会忽略证书验证错误,继续完成TLS握手并建立连接。此时服务器只完成了自身身份验证,并未校验客户端的信任状态,因此会允许连接建立。
2. 阻止这类客户端的方法
要拒绝跳过证书校验或未被信任的客户端,必须开启双向TLS认证(Mutual TLS, mTLS),让服务器同时验证客户端身份。具体步骤如下:
- 生成客户端证书:使用OpenSSL创建由你的本地根CA签名的客户端证书及密钥
- 配置服务器信任库:将根CA证书导入到服务器的信任库(用于验证客户端证书的合法性)
- 修改Spring Boot配置,强制开启双向认证:
在application.properties中添加以下配置:# 强制要求客户端提供证书 server.ssl.client-auth=required # 指定信任库路径及密码 server.ssl.trust-store=classpath:truststore.p12 server.ssl.trust-store-password=你的信任库密码 server.ssl.trust-store-type=PKCS12
配置完成后,只有携带合法客户端证书的请求(例如通过curl --cert 客户端证书.pem --key 客户端密钥.pem发起的请求)才能成功连接;使用-k的客户端会因无法提供有效客户端证书(或证书不被服务器信任)而被拒绝。
补充:无法仅通过配置阻止“跳过证书校验”的客户端,因为跳过校验是客户端的主动行为,服务器无法直接检测该操作。只有通过mTLS强制客户端提供可信证书,才能确保连接双方均为可信主体。
内容的提问来源于stack exchange,提问作者Mayank Madhav

