You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Strict-Transport-Security(HSTS)不生效?还是测试方式有误?

解决Jetty添加HSTS后浏览器仍可HTTP访问的问题

看起来你已经迈出了第一步——在Jetty里添加HSTS头并通过curl验证成功,但浏览器这边没按预期工作,这其实是HSTS的特性和配置细节导致的,我来帮你拆解问题并给出解决方案:

核心原因分析

HSTS(HTTP Strict Transport Security)的生效逻辑有几个关键前提,你可能刚好踩中了其中一点:

  • HSTS头必须通过HTTPS返回:浏览器会直接忽略HTTP响应里的HSTS头,这是为了防止中间人攻击。如果你的测试是先访问HTTP,那浏览器根本不会记住这个规则;
  • 需要先通过HTTPS访问一次:HSTS是浏览器端的规则,只有当用户(或测试者)通过HTTPS访问过你的站点,浏览器才会把这个域名加入强制HTTPS列表,后续的HTTP请求才会自动跳转到HTTPS;
  • 头参数不完整:如果你的HSTS头缺少max-age(必填)或者配置不正确,浏览器也不会生效这个规则。

具体修复步骤

1. 确保Jetty已配置HTTPS连接器

首先你得让Jetty支持HTTPS,没有SSL证书的话,HSTS完全发挥不了作用。你可以在代码里添加SSL连接器配置:

Server server = new Server();

// 配置HTTPS连接器
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath("/path/to/your/keystore.jks");
sslContextFactory.setKeyStorePassword("your-keystore-password");
HttpConfiguration httpsConfig = new HttpConfiguration();
httpsConfig.addCustomizer(new SecureRequestCustomizer());
ServerConnector httpsConnector = new ServerConnector(server, 
    new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), 
    new HttpConnectionFactory(httpsConfig));
httpsConnector.setPort(443);
server.addConnector(httpsConnector);

// 保留HTTP连接器用于重定向
ServerConnector httpConnector = new ServerConnector(server);
httpConnector.setPort(80);
server.addConnector(httpConnector);

2. 正确设置完整的HSTS头

补全你的BlockingServlet代码,确保返回的HSTS头参数完整合规:

public class BlockingServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置HSTS头:有效期1年,包含子域名(可根据需求调整参数)
        response.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
        response.getWriter().write("HSTS Test Page");
    }
}

注:max-age单位为秒,includeSubDomains是可选参数,若你的子域名也需要强制HTTPS则添加。

3. 添加HTTP到HTTPS的重定向

HSTS是让后续访问强制HTTPS,但第一次访问HTTP时,需要主动重定向到HTTPS,不然浏览器还是会加载HTTP页面。你可以用Jetty的RewriteHandler实现:

RewriteHandler rewriteHandler = new RewriteHandler();
rewriteHandler.setRewriteRequestURI(true);
rewriteHandler.setRewritePathInfo(true);

// 添加HTTP转HTTPS的重定向规则
RedirectPatternRule redirectRule = new RedirectPatternRule();
redirectRule.setPattern("/*");
redirectRule.setLocation("https://your-domain.com$0"); // 替换为你的实际域名
rewriteHandler.addRule(redirectRule);

// 关联你的Servlet处理器
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
context.addServlet(new ServletHolder(new BlockingServlet()), "/*");
rewriteHandler.setHandler(context);

server.setHandler(rewriteHandler);

4. 正确测试流程

  1. 启动配置完成的Jetty服务器;
  2. 先通过HTTPS访问你的站点(比如https://localhost:443),让浏览器接收并保存HSTS规则;
  3. 再尝试访问HTTP地址(比如http://localhost:80),此时浏览器应该会自动跳转到HTTPS,或直接阻止HTTP访问。

为什么curl能抓到头但浏览器不行?

curl只是单纯读取响应头,不管是HTTP还是HTTPS返回的头都会显示;但浏览器会严格遵循HSTS规范:只有HTTPS返回的HSTS头才会被信任并生效,而且需要至少一次HTTPS访问来触发浏览器记录规则。

内容的提问来源于stack exchange,提问作者curiousengineer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:22:45