簡體   English   中英

在反向代理后面需要帶有 Spring Security 的 HTTPS

[英]Require HTTPS with Spring Security behind a reverse proxy

我有一個使用 Spring Security 保護的 Spring MVC 應用程序。 大多數應用程序使用簡單的 HTTP 來節省資源,但一小部分處理更機密的信息並需要 HTTPS 通道。

security-config.xml提取:

<sec:http authentication-manager-ref="authenticationManager" ... >
    ...
    <sec:intercept-url pattern="/sec/**" requires-channel="https"/>
    <sec:intercept-url pattern="/**" requires-channel="http"/>
</sec:http>

一切正常,直到我們決定將其遷移到主服務器,應用服務器在反向代理之后運行。 現在 HTTPS 由反向代理處理,應用程序服務器只能看到 HTTP 請求,並且不允許訪問/sec/**層次結構。

經過一番研究,我發現代理添加了X-Forwarded-Proto: https標頭(*) ,但在 Spring Security 中HttpServletRequest.isSecure()用於確定提供的通道安全性(摘自SecureChannelProcessor javadoc)。

我如何告訴 Spring Security X-Forwarded-Proto: https標頭足以滿足安全請求?

我知道我可以報告關於代理配置的那部分,但是代理管理員真的不喜歡這個解決方案,因為代理背后有很多應用程序,並且配置可能會增長到不可管理的狀態。

我目前使用帶有 XML 配置的 Spring Security 3.2,但我准備接受基於 Java 配置和/或更新版本的答案。

(*)當然,如果傳入請求中存在標頭,代理會刪除標頭,因此應用程序可以對其有信心。

對 NeilMcGuigan 的回答的一種跟進,表明解決方案是 servlet 容器端。

Tomcat 甚至更好。 有一個閥門專門用於掩蓋反向代理的副作用。 摘自遠程 IP Valve 的Tomcat 文檔:

此閥的另一個功能是用代理或負載均衡器通過請求標頭(例如“X-Forwarded-Proto”)呈現的方案替換明顯的方案(http/https)、服務器端口和 request.secure。

閥門配置示例:

<Valve className="org.apache.catalina.valves.RemoteIpValve"
    internalProxies="192\.168\.0\.10|192\.168\.0\.11"
    remoteIpHeader="x-forwarded-for" proxiesHeader="x-forwarded-by"
    protocolHeader="x-forwarded-proto" />

這樣,在沒有應用程序本身的其他配置的情況下,如果請求包含X-Forwarded-Proto=https的標頭字段,則對Request.isSecure()的調用將返回 true。

我曾想過另外兩種可能性,但絕對更喜歡那個:

  • 在 Spring Security ChannelProcessingFilter之前使用激活的過濾器,用覆蓋isSecure()HttpServletRequestWrapper包裝請求以處理X-Forwarded-Proto標頭 - 需要編寫和測試過濾器和包裝器
  • 使用 Spring BeanPostProcessor查找ChannelProcessingFilter並手動注入一個ChannelDecisionManager能夠考慮X-Forwarded-Proto標頭 - 真的太低級了

Spring Boot 使它變得非常簡單(至少對於嵌入式 Tomcat)。

1. 將以下行添加到您的 application.properties:

server.forward-headers-strategy=native
server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=x-forwarded-proto

2. 使用您的HttpSecurity配置執行以下技巧。

// final HttpSecurity http = ...
// Probably it will be in your `WebSecurityConfigurerAdapter.configure()`

http.requiresChannel()
            .anyRequest().requiresSecure()

來源是 Spring Boot 參考指南

84.3 在代理服務器后面運行時啟用 HTTPS

另請查看下面的答案以了解與 Spring Boot 2.2 相關細節

如果您的站點是 HTTPS 並且您在另一個處理 TLS 終止的系統后面運行 Apache Tomcat,您可以告訴 Tomcat“假裝”它正在處理 TLS 終止。

這使得request.isSecure()返回true

為此,您需要將secure="true"添加到server.xml的連接器配置中。

https://tomcat.apache.org/tomcat-7.0-doc/config/http.html

另請參閱scheme屬性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM