java - 在存在 XFF header 的情况下将 `AuthenticationFailureBadCredentialsEvent` 与远程地址关联

标签 java spring kotlin spring-security x-forwarded-for

所以我写了这个......

@Component
class AuthenticationFailureListener : ApplicationListener<AuthenticationFailureBadCredentialsEvent>{

    private val bruteForceProtection : BruteForceProtection

    @Inject
    constructor(bruteForceProtection: BruteForceProtection){
        this.bruteForceProtection = bruteForceProtection
    }

    override fun onApplicationEvent(event: AuthenticationFailureBadCredentialsEvent) {
        val webDetails = event.authentication.details as WebAuthenticationDetails
        val remoteAddress = webDetails.remoteAddress

        bruteForceProtection.recordFailedAttempt(remoteAddress)
    }
}

然后意识到我不知道 Spring 在安全上下文中设置远程地址时是否考虑了 X-Forwarded-For header 。

是吗?

或者我如何将 AuthenticationFailureBadCredentialsEvent 与其源自的远程地址相关联?

最佳答案

来自Spring Security#15.4 Proxy Server Configuration :

When using a proxy server it is important to ensure that you have configured your application properly. For example, many applications will have a load balancer that responds to request for https://example.com/ by forwarding the request to an application server at https://192.168.1:8080 Without proper configuration, the application server will not know that the load balancer exists and treat the request as though https://192.168.1:8080 was requested by the client.

To fix this you can use RFC 7239 to specify that a load balancer is being used. To make the application aware of this, you need to either configure your application server aware of the X-Forwarded headers. For example Tomcat uses the RemoteIpValve and Jetty uses ForwardedRequestCustomizer. Alternatively, Spring 4.3+ users can leverage ForwardedHeaderFilter.

Spring 框架和 Spring Security 本身都没有对 X-Forwarded* header 做任何特殊的事情。

因此,我们应用此类信息的选项是:

不幸的是ForwardedHeaderFilter没有inspect X-Forwarded-For header 5.1.7.RELEASE 起。

所以剩下的选项是配置服务器。

由于您使用的是 tomcat,因此您可以提供 server.tomcat.remote-ip-header 属性来考虑 header 。

另请参阅 ServerProperties

application.yml:

server:
  tomcat:
    remote-ip-header: X-Forwarded-For

然后getRemoteAddr将返回 WebAuthenticationDetails 使用的 X-Forwarded-For header 中存在的 IP 地址本身

WebAuthenticationDetails.java

public WebAuthenticationDetails(HttpServletRequest request) {
    this.remoteAddress = request.getRemoteAddr();

    HttpSession session = request.getSession(false);
    this.sessionId = (session != null) ? session.getId() : null;
}

这是一个简单的测试:

IpController.kt:

@RestController
class IpController {
    @GetMapping("/ip")
    fun getIp(request: HttpServletRequest) = mapOf("ip" to request.remoteAddr)
}

IpControllerTest.kt

@SpringBootTest(properties = ["server.tomcat.remote-ip-header=X-Forwarded-For"],
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class IpControllerTest {
    @Autowired
    private lateinit var testRestTemplate: TestRestTemplate

    @Test
    fun `uses ip from x-forwarded-for`() {
        val httpHeaders = HttpHeaders()
        httpHeaders["X-Forwarded-For"] = "8.8.8.8"
        val httpEntity = HttpEntity<Any>(httpHeaders)
        val map = testRestTemplate.exchange<Map<String, *>>("/ip", HttpMethod.GET, httpEntity)
                .body!!
        assertEquals("8.8.8.8", map["ip"])
    }
}

关于java - 在存在 XFF header 的情况下将 `AuthenticationFailureBadCredentialsEvent` 与远程地址关联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56133593/

相关文章:

java - Integer.parseInt 不会将 String 解析为 int

java - 正则表达式理解\b

java - 如何使用不带注释的Spring Data JDBC?

spring - 带有Spring Boot 2的Docker Stack “configs”

android - 更新 ArrayList 内容后,DiffUtil 不更新 ListAdapter

kotlin - 如何分解对象并将其简洁地添加到列表中?

java - 无法在 glassfish 中运行,日志中出现奇怪的输入流错误

java - jpa标准错误或放错地方

java - 我们可以配置 Hibernate 没有 hibernate.cfg.xml

android - Kotlin 协程使用 runBlocking 进行单元测试不等待执行