Связывание `AuthenticationFailureBadCredentialsEvent` с удаленным адресом при наличии заголовков XFF - PullRequest
1 голос
/ 14 мая 2019

Итак, я написал это ...

@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 заголовков при установке удаленного адреса в контексте безопасности.

Так ли?

Или как мне связать AuthenticationFailureBadCredentialsEvent с удаленным адресом, с которого он произошел?

1 Ответ

1 голос
/ 14 мая 2019

С Spring Security # 15.4 Конфигурация прокси-сервера :

При использовании прокси-сервера важно убедиться, что вы правильно настроили свое приложение. Например, многие приложения будут иметь балансировщик нагрузки, который отвечает на запрос https://example.com/ путем пересылки запроса на сервер приложений на https://192.168.1:8080. Без правильной конфигурации сервер приложений не будет знать, что существует балансировщик нагрузки, и будет обрабатывать запрос как хотя https://192.168.1:8080 был запрошен клиентом.

Чтобы исправить это, вы можете использовать RFC 7239, чтобы указать, что используется балансировщик нагрузки. Чтобы приложение знало об этом, вам нужно либо настроить свой сервер приложений на X-Forwarded заголовки . Например, Tomcat использует RemoteIpValve, а Jetty использует ForwardedRequestCustomizer. В качестве альтернативы пользователи Spring 4.3+ могут использовать ForwardedHeaderFilter.

.

Ни среда Spring, ни сама Spring Security не делают ничего особенного в X-Forwarded* заголовках.

Таким образом, наши варианты применения такой информации:

К сожалению ForwardedHeaderFilter не проверяет X-Forwarded-For заголовок с 5.1.7.RELEASE.

Таким образом, оставленный вариант - настроить сервер.

Поскольку вы используете tomcat, вы можете указать свойство server.tomcat.remote-ip-header, чтобы учесть заголовок.

См. Также ServerProperties

application.yml

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

затем getRemoteAddr вернет IP-адрес, присутствующий в заголовке X-Forwarded-For, который используется WebAuthenticationDetails сам

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"])
    }
}
...