ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

HSTS配置指南:从SSL剥离攻击到IIS/Tomcat实战部署与排错

HSTS配置指南:从SSL剥离攻击到IIS/Tomcat实战部署与排错 1. HSTS到底解决什么问题先弄懂它为什么存在我第一次真正认真研究HSTS不是因为主动学习安全加固而是被一个诡异的故障逼的。网站部署了HTTPS证书浏览器也显示小锁图标一切看起来正常。但过了一周用户陆续反馈网页打不开我打开一看浏览器直接提示你无法访问该网站因为网站使用的是HSTS。网络错误和攻击通常是暂时的此页面可能无法正常工作。翻遍了服务器日志查遍了证书配置最后发现是自己之前加的一条响应头惹的祸。1.1 SSL剥离攻击为什么光有HTTPS还不够先理清一个概念HTTPS协议本身是安全的问题出在用户第一次访问网站的那一刻。假设你访问http://example.com如果网站做了301跳转到https://example.com在这个过程中第一个HTTP请求是裸奔的。中间人拦截到这个请求后可以偷偷把你的连接降级成HTTP而服务器和浏览器都以为自己在用安全通道通信。这就是经典的SSL剥离攻击SSL Stripping。简单做个类比你去银行办理业务银行保安把你领到VIP室但你在路上被坏人换了个方向带到了假柜台。你以为自己在和银行打交道其实对面是骗子。HSTSHTTP Strict Transport SecurityHTTP严格传输安全的出现就是为了堵住这个入口。它通过服务器返回的响应头告诉浏览器这个网站只允许使用HTTPS访问你在任何情况下都不要尝试HTTP明文连接。1.2 HSTS的工作机制一次握手终身约束HSTS的运作逻辑并不复杂。当浏览器第一次通过HTTPS访问一个网站时服务器会在响应头里带上Strict-Transport-Security字段。浏览器记住这个信息之后在指定时间内由max-age参数控制只要用户再访问这个域名浏览器会自动把HTTP重写为HTTPS且这个过程发生在任何网络请求发出之前。关键点在于这个记住发生在浏览器本地不需要经过网络请求。所以即使中间人试图拦截他看到的只是一次HTTPS连接请求用HTTP协议根本无法和浏览器完成通信。Strict-Transport-Security响应头的完整格式如下Strict-Transport-Security: max-age31536000; includeSubDomains; preload三个参数的作用参数作用推荐值max-age浏览器记住只走HTTPS的时长单位是秒至少31536000即1年不宜太短includeSubDomains子域名是否同样强制HTTPS视情况添加添加后所有子域名都被约束preload允许域名提交到浏览器内置的HSTS预加载列表确认无误后再加加了很难撤销顺便说一句preload是为了解决第一次访问那个问题而生的。刚才提到HSTS要等浏览器访问过一次HTTPS才生效但如果域名被收录到浏览器的预加载列表里即使从没访问过浏览器也天然就知道这个域名只能走HTTPS。提交流程在hstspreload.org官网进行需要满足一定的审核条件。1.3 HSTS生效的一个关键前提这个点特别容易忽略HSTS响应头必须通过HTTPS连接返回。换句话说用户第一次用HTTP访问你的网站时服务器返回的响应头即使带上了Strict-Transport-Security浏览器也会直接忽略。原因不难理解HTTP是明文传输中间人可以随意篡改响应头。如果浏览器信任明文通道里的HSTS指令那攻击者直接伪造一条max-age999999999的HSTS响应头就能让用户彻底无法访问这个网站。初次部署时我建议先用浏览器开发者工具F12打开Network面板确认HTTPS响应的响应头里真的出现了Strict-Transport-Security再去考虑后续的推广和运维。2. IIS上配置HSTS三种方案按场景选型IISInternet Information Services是Windows Server上常用的Web服务器配置HSTS可以根据IIS版本和对灵活度的要求选择不同的方案。2.1 前置条件先确保HTTPS已经跑通在IIS上加HSTS之前必须先完成两件事在服务器上安装有效的SSL证书可以是企业级证书、Lets Encrypt免费证书或云服务商提供的证书。在IIS管理器里为网站绑定HTTPS协议443端口和对应的证书。证书这块我多说一句HSTS强制浏览器只能走HTTPS如果证书本身有问题过期、域名不匹配、证书链不完整用户就会被完全挡在门外想回退到HTTP都不行。所以在开启HSTS之前务必确认HTTPS访问一切正常。验证方法也很简单浏览器无痕窗口打开https://你的域名能正常加载且地址栏有小锁标志就算过关了。2.2 方案一web.config添加自定义响应头最简单这是IIS上最直接的配置方式适合只需添加静态响应头的场景。打开站点根目录下的web.config文件在system.webServer节点内加入httpProtocol配置configuration system.webServer httpProtocol customHeaders remove nameStrict-Transport-Security / add nameStrict-Transport-Security valuemax-age31536000; includeSubDomains / /customHeaders /httpProtocol /system.webServer /configuration保存文件后IIS会立即生效不需要重启站点或服务器。remove指令是为了防止重复添加同名响应头特别是当你在IIS管理器界面手动添加过之后再来改配置文件这个防御动作有备无患。验证方式刷新HTTPS页面F12在Network里找到主文档请求查看Response Headers里是否出现了Strict-Transport-Security。2.3 方案二URL Rewrite模块动态添加推荐如果站点已经有URL Rewrite规则比如做了HTTP到HTTPS的301跳转那么直接在现有规则集合里加一条HSTS响应头规则会更统一方便后续集中管理。前提是服务器已安装IIS URL Rewrite模块下载和安装自行搜索微软官方支持。在web.config的rewrite节点中加入rewrite rules rule nameHTTP to HTTPS Redirect stopProcessingtrue match url(.*) / conditions add input{HTTPS} patternoff ignoreCasetrue / /conditions action typeRedirect urlhttps://{HTTP_HOST}/{R:1} redirectTypePermanent / /rule rule nameAdd HSTS Header stopProcessingtrue match serverVariableRESPONSE_Strict_Transport_Security pattern.* / conditions logicalGroupingMatchAll add input{HTTPS} patternon ignoreCasetrue / /conditions action typeRewrite valuemax-age31536000; includeSubDomains / /rule /rules /rewrite这个方案的好处是HSTS响应头只在HTTPS请求时被写入HTTP请求不会触发这条规则。使用serverVariable和Rewrite动作配合比在customHeaders里写死更灵活——将来想调整max-age、增删includeSubDomains只改一处即可。注意URL Rewrite的serverVariable写法是RESPONSE_Strict_Transport_Security不是HTTP_前缀写错了规则不会生效这个坑我自己踩过。2.4 方案三IIS 10版本上的原生支持如果你用的是Windows Server 2016或更高版本IIS 10开始原生支持HSTS配置不需要辅助模块直接在IIS管理器里操作。操作路径IIS管理器 → 选择站点 → 双击HTTP响应头 → 右侧添加 → 填写名称Strict-Transport-Security值max-age31536000; includeSubDomains这种方法最直观适合不太想碰配置文件的运维同学。实际项目中我个人更推荐方案二URL Rewrite因为可以同时管理HTTP跳转和HSTS响应头而且规则本身是声明式的放到配置管理工具里也好维护。方案一适合快速验证方案三则适合图形化操作偏好者。2.5 配置后的自检清单不管用哪个方案配完都建议跑一遍自检curl -I https://你的域名重点看返回头里有没有Strict-Transport-Security字段值是否正确。同时检查HTTP请求curl -I http://你的域名是否正常301跳转到HTTPS——注意HTTP请求的响应头里不应该出现HSTS出现也没用浏览器不认。3. Tomcat上配置HSTS三条路线各有利弊Tomcat和IIS的架构思路完全不同配置HSTS的姿势也更多样。3.1 前置条件HTTPS连接器就绪Tomcat要支持HTTPS需要先去conf/server.xml里配置SSL连接器。核心配置大致如下Connector port8443 protocolorg.apache.coyote.http11.Http11NioProtocol maxThreads150 SSLEnabledtrue schemehttps securetrue SSLHostConfig Certificate certificateKeystoreFileconf/keystore.jks certificateKeystorePasswordyourpassword typeRSA / /SSLHostConfig /Connector证书可以用JKS格式keytool命令生成也可以用PKCS12格式更推荐兼容性更好。无论哪种先确认https://你的域名:8443能正常打开。3.2 路线一用Tomcat内置的HttpHeaderSecurityFilter推荐Tomcat从8.0版本开始就提供了一个现成的过滤器叫HttpHeaderSecurityFilter它不仅能加HSTS响应头还顺手帮你处理了X-Content-Type-Options、X-Frame-Options这些常见安全头性价比很高。在应用的web.xml里注册过滤器filter filter-namehttpHeaderSecurity/filter-name filter-classorg.apache.catalina.filters.HttpHeaderSecurityFilter/filter-class init-param param-namehstsEnabled/param-name param-valuetrue/param-value /init-param init-param param-namehstsMaxAgeSeconds/param-name param-value31536000/param-value /init-param init-param param-namehstsIncludeSubDomains/param-name param-valuetrue/param-value /init-param init-param param-namehstsPreload/param-name param-valuefalse/param-value /init-param /filter filter-mapping filter-namehttpHeaderSecurity/filter-name url-pattern/*/url-pattern /filter-mapping如果你不希望启用某些默认开启的安全头可以查看Tomcat官方文档通过对应的init-param关闭它们。比如antiClickJackingEnabled、blockContentTypeSniffingEnabled等等。注意hstsPreload参数当你准备提交到浏览器预加载列表并且所有子域名都确定能走HTTPS时再设为true。否则先保持false。3.3 路线二自写Filter实现更灵活如果项目里没有用Tomcat的原生web.xml而是Spring Boot内嵌Tomcat或者希望在不同环境里动态控制HSTS策略自己写一个Filter更好用。import javax.servlet.*; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class HSTSFilter implements Filter { private long maxAgeSeconds 31536000L; private boolean includeSubDomains true; Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse httpResponse (HttpServletResponse) response; if (request.isSecure()) { StringBuilder hstsValue new StringBuilder(max-age).append(maxAgeSeconds); if (includeSubDomains) { hstsValue.append(; includeSubDomains); } httpResponse.setHeader(Strict-Transport-Security, hstsValue.toString()); } chain.doFilter(request, response); } }注意request.isSecure()判断只有HTTPS请求才写入HSTS响应头。如果忽略了这层判断HTTP响应里也能看到这个头虽然浏览器不会理会但总归不规范。在Spring Boot里用Configuration类注册这个Filterimport org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class SecurityConfig { Bean public FilterRegistrationBeanHSTSFilter hstsFilterRegistration() { FilterRegistrationBeanHSTSFilter registration new FilterRegistrationBean(); registration.setFilter(new HSTSFilter()); registration.addUrlPatterns(/*); registration.setOrder(1); return registration; } }3.4 路线三通过安全约束强制HTTPSHSTS只是让浏览器想走HTTPS但服务器本身也要能拒绝HTTP明文请求才算闭环。Tomcat的web.xml中可以配置安全约束security-constraint web-resource-collection web-resource-nameAll Resources/web-resource-name url-pattern/*/url-pattern /web-resource-collection user-data-constraint transport-guaranteeCONFIDENTIAL/transport-guarantee /user-data-constraint /security-constraint加上这段之后用户访问HTTP端口时Tomcat会根据server.xml里的配置自动跳转到HTTPS端口。需要特别说明的是transport-guarantee是服务器端的强制跳转HSTS是浏览器端的强制行为两者配合才是完整方案transport-guarantee负责把不听话的客户端拉回HTTPSHSTS负责让浏览器以后不再发起HTTP请求。3.5 Tomcat配置后的验证方法配置完成后通过以下命令验证效果curl -I https://你的域名:8443/正常返回里应包含Strict-Transport-Security: max-age31536000; includeSubDomains同时再测试HTTP请求头看是否会正确302到HTTPS。4. 配置完反而访问不了HSTS排错专项这一节是我个人觉得最值得细看的因为几乎所有搜HSTS相关关键词的人一半是配置前学习另一半是配置后救火。4.1 最常见的三个故障原因先看下HSTS导致网站无法访问的三种常见原因故障现象根本原因紧急处理浏览器提示HSTS错误页面无法打开证书失效、域名不匹配或证书链不完整先修复证书再考虑是否降低max-ageHTTP访问时没有正确跳转到HTTPS服务器端缺少301跳转或transport-guarantee配置补全跳转规则部分用户升级后无法访问浏览器本地缓存的HSTS记录尚未过期等max-age自然过期或让用户清除浏览数据HSTS最麻烦的地方在于一旦浏览器在本地缓存了只走HTTPS的指令即使你立刻把服务器配置改回来用户端的浏览器依然会坚持到max-age过期为止。普通设置是31536000秒一年也就是说配置错了但没察觉未来整整一年里这个域名在用户浏览器里都会被强制HTTPS。这就是为什么我强调测试阶段要先用很小的max-age比如300秒5分钟确认全部正常后再逐步加大。4.2 教你如何清除浏览器的HSTS缓存用户端访问不了首先要做的是清除浏览器里的HSTS记录。Chrome和Edge浏览器在地址栏输入chrome://net-internals/#hsts在Delete domain security policies区域输入你的域名点击Delete。清除之后浏览器会忘记这个域名有过HSTS记录下次访问时可以重新经历一次HTTP跳HTTPS的正常流程。Firefox浏览器没有类似的隐藏页面需要到设置 → 隐私与安全 → Cookie和网站数据 → 清除数据勾选Cookie和网站数据并确认清除。提醒一下清除浏览数据这个操作会连登录态一起清掉用户操作成本不低。所以运维侧排查时先确认服务器本身没问题再让客户操作浏览器。4.3 服务器端排查链路我自己遇到HSTS后无法访问的场景通常会按照以下顺序排查确认证书有效性用在线SSL检测工具或本地openssl命令检查证书是否到期域名是否包含www和裸域。证书这步出错HSTS模式下用户连继续访问的按钮都点不到。确认HTTPS响应头curl -I https://域名看HSTS响应头是否真实存在。有时你只是加了配置但没生效比如IIS的web.config节点位置写错或Tomcat的Filter没加载。检查HTTP是否跳转curl -I http://域名看是否有301或302Location是否指向HTTPS地址。如果HTTP直接200返回了页面内容用户侧就永远无法通过HSTS进入HTTPS。用无痕窗口测试普通窗口可能受HSTS缓存影响无痕窗口是干净的能更准确反映新用户视角下的访问体验。分享一个我处理过的真实案例客户反馈手机微信里打不开网站电脑正常。排查后发现客户的域名在hstspreload.org被提交到了预加载列表而服务器只给主域名申请了证书子域名m.domain.com没有覆盖到导致移动端访问时被HSTS强制跳转HTTPS但证书校验不过直接白屏。费了好大劲最快的处理方式不是等列表更新而是先补齐子域名证书。4.4 日志里怎么定位HSTS问题IIS和Tomcat的日志里其实看不出HSTS错误这个敏感信息但可以通过以下线索判断大量HTTP请求根本没有到达服务器浏览器拦截了没发出来。HTTPS访问日志里出现大量4xx或5xx证书错误说明TLS握手阶段就失败了。如果网站本身就是纯HTTPS还要看有没有客户端重复请求HTTP导致404。多学一个排查工具没有坏处。PC上用chrome://net-internals/#hsts页面还能在Query domain输入框里查出当前浏览器对该域名的HSTS状态会显示是否static预加载或dynamic动态缓存这个功能排查时很好用。5. 从280分到90分HSTS的踩坑经验与部署建议说完了配置和排错最后聊点实际部署时才用得到的经验。5.1 先短后长的灰度策略用HSTS最忌讳一上来就max-age31536000万一中间出了岔子整个域名的访问问题会持续一年。更稳妥的做法是分三步走第一阶段max-age300测试几天观察有没有异常。第二阶段max-age864001天运行一周。第三阶段max-age31536000; includeSubDomains正式生效。每次调整时浏览器会在下一次HTTPS访问时刷新该域名的HSTS记录所以逐步加长不会增加额外负担。5.2 includeSubDomains一定要慎重includeSubDomains这个词看着不起眼但它会把你所有的子域名一起拉进强制HTTPS的范围。如果你的企业还有其他子域名正在跑HTTP服务比如内部测试环境、旧版接口平台、静态资源服务器开启之后它们会一起瘫痪。所以这里有一个非常实用的建议开启includeSubDomains之前先梳理一遍DNS记录里所有的子域名确认每个都能通过HTTPS正常访问。如果实在无法保证所有子域名都支持HTTPS就只配置Strict-Transport-Security: max-age31536000不带includeSubDomains安全性打了折但不至于误伤。5.3 提交到预加载列表之前想清楚把域名提交到浏览器的预加载列表意味着即使浏览器从没访问过你的网站也天然知道这个域名必须用HTTPS。这样做彻底解决了首次访问时的安全问题但代价是你几乎不可能从预加载列表中移除自己。根据Chrome的规范如果域名出现在预加载列表中想要申请移除需要等待至少两个版本周期而且Chrome团队并不保证一定会处理。所以我的建议是先在正式环境跑1~2个月确认HSTS稳定。所有涉及的子域名都覆盖了有效证书。确定未来一年内不会因为业务拆分导致子域名改用HTTP。最后再去hstspreload.org提交。5.4 HSTS与其他安全头的配合HSTS只是安全响应头体系中的一个环节。在IIS或Tomcat上同时配置以下响应头能组成更完善的安全防线响应头作用X-Content-Type-Options: nosniff禁止浏览器猜测文件类型防止MIME混淆攻击X-Frame-Options: SAMEORIGIN禁止页面被其他站点iframe嵌套防点击劫持Content-Security-Policy限制页面资源加载来源缓解XSSReferrer-Policy控制跳转时Referer传递范围这些头的配置方式和HSTS类似在IIS里可以统一放在customHeaders中在Tomcat里可以用HttpHeaderSecurityFilter一并处理不需要额外开发。5.5 我在实际运维中总结的几个习惯配置HSTS这件事次数多了之后我养成了几个习惯这里一并分享一是每次修改配置前备份web.config或server.xml。IIS那边一个空格写错站点马上罢工有备份能快速还原。Tomcat的server.xml修改后虽然需要重启才生效但配置文件的备份同样不能省。二是用本机curl做冒烟测试不要只依赖浏览器。浏览器有缓存、有HSTS状态、有代理设置干扰因素太多。curl请求能直观看清楚响应头比F12更直接。三是关注证书到期提醒。HSTS开启后证书到期不再是用户看到不安全警告那么简单而是用户完全打不开网站的严重故障。给SSL证书设置提前30天、7天、1天的提醒哪怕是用最简单的日历提醒都行。四是跟团队约定好HSTS变更需要走变更流程。这个头影响范围大、持续时间长一旦上线出问题回滚成本很高。最后再补充一个重要提醒HSTS是自己把路走窄的一种安全策略——它主动否决了HTTP这条退路。配置得当它能帮你挡住SSL剥离攻击配置失误它会让你连自己网站的首页都打不开。希望这篇文章能帮你把前者变成现实避开后者那些坑。
返回列表