mirror of
https://github.com/imgfloat/server.git
synced 2026-02-05 03:39:26 +00:00
Fix CSRF bugs
This commit is contained in:
@@ -18,6 +18,7 @@ import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
|
||||
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
|
||||
import org.springframework.security.web.csrf.CsrfToken;
|
||||
import org.springframework.security.web.csrf.CsrfException;
|
||||
import org.springframework.security.web.csrf.CsrfFilter;
|
||||
@@ -41,6 +42,9 @@ public class SecurityConfig {
|
||||
HttpSecurity http,
|
||||
OAuth2AuthorizedClientRepository authorizedClientRepository
|
||||
) throws Exception {
|
||||
CsrfTokenRequestAttributeHandler csrfRequestHandler = new CsrfTokenRequestAttributeHandler();
|
||||
csrfRequestHandler.setCsrfRequestAttributeName("_csrf");
|
||||
|
||||
http
|
||||
.authorizeHttpRequests((auth) ->
|
||||
auth
|
||||
@@ -89,6 +93,7 @@ public class SecurityConfig {
|
||||
.csrf((csrf) ->
|
||||
csrf
|
||||
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
|
||||
.csrfTokenRequestHandler(csrfRequestHandler)
|
||||
.ignoringRequestMatchers("/ws/**")
|
||||
)
|
||||
.addFilterAfter(csrfTokenCookieFilter(), CsrfFilter.class);
|
||||
@@ -140,7 +145,10 @@ public class SecurityConfig {
|
||||
HttpServletResponse response,
|
||||
FilterChain filterChain
|
||||
) throws java.io.IOException, jakarta.servlet.ServletException {
|
||||
CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
|
||||
CsrfToken csrfToken = (CsrfToken) request.getAttribute("_csrf");
|
||||
if (csrfToken == null) {
|
||||
csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
|
||||
}
|
||||
if (csrfToken != null) {
|
||||
String token = csrfToken.getToken();
|
||||
Cookie existingCookie = WebUtils.getCookie(request, "XSRF-TOKEN");
|
||||
|
||||
@@ -438,6 +438,7 @@ function connect() {
|
||||
},
|
||||
(error) => {
|
||||
console.warn("WebSocket connection issue", error);
|
||||
fetchAssets();
|
||||
setTimeout(
|
||||
() => showToast("Live updates connection interrupted. Retrying may be necessary.", "warning"),
|
||||
1000,
|
||||
@@ -2086,7 +2087,7 @@ function uploadAsset(file = null) {
|
||||
return;
|
||||
}
|
||||
if (selectedFile.size > UPLOAD_LIMIT_BYTES) {
|
||||
showToast(`File is too large. Maximum upload size is ${UPLOAD_MAX_BYTES / 1024 / 1024} MB.`, "error");
|
||||
showToast(`File is too large. Maximum upload size is ${UPLOAD_LIMIT_BYTES / 1024 / 1024} MB.`, "error");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -352,7 +352,7 @@
|
||||
const broadcaster = /*[[${broadcaster}]]*/ '';
|
||||
const username = /*[[${username}]]*/ '';
|
||||
const UPLOAD_LIMIT_BYTES = /*[[${uploadLimitBytes}]]*/ 0;
|
||||
const SETTINGS = /*[[${settingsJson}]]*/;
|
||||
const SETTINGS = JSON.parse(/*[[${settingsJson}]]*/);
|
||||
</script>
|
||||
<script src="/js/cookie-consent.js"></script>
|
||||
<script src="/js/toast.js"></script>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.kruhlmann.imgfloat;
|
||||
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.oauth2Login;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
@@ -48,6 +49,7 @@ class ChannelApiIntegrationTest {
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"username\":\"helper\"}")
|
||||
.with(oauth2Login().attributes((attrs) -> attrs.put("preferred_username", broadcaster)))
|
||||
.with(csrf())
|
||||
)
|
||||
.andExpect(status().isOk());
|
||||
|
||||
@@ -70,6 +72,7 @@ class ChannelApiIntegrationTest {
|
||||
multipart("/api/channels/{broadcaster}/assets", broadcaster)
|
||||
.file(file)
|
||||
.with(oauth2Login().attributes((attrs) -> attrs.put("preferred_username", broadcaster)))
|
||||
.with(csrf())
|
||||
)
|
||||
.andExpect(status().isOk())
|
||||
.andReturn()
|
||||
@@ -96,6 +99,7 @@ class ChannelApiIntegrationTest {
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(visibilityRequest))
|
||||
.with(oauth2Login().attributes((attrs) -> attrs.put("preferred_username", broadcaster)))
|
||||
.with(csrf())
|
||||
)
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.hidden").value(false));
|
||||
@@ -113,7 +117,7 @@ class ChannelApiIntegrationTest {
|
||||
.perform(
|
||||
delete("/api/channels/{broadcaster}/assets/{id}", broadcaster, assetId).with(
|
||||
oauth2Login().attributes((attrs) -> attrs.put("preferred_username", broadcaster))
|
||||
)
|
||||
).with(csrf())
|
||||
)
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
@@ -126,6 +130,7 @@ class ChannelApiIntegrationTest {
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"username\":\"helper\"}")
|
||||
.with(oauth2Login().attributes((attrs) -> attrs.put("preferred_username", "intruder")))
|
||||
.with(csrf())
|
||||
)
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user