Disable CSRF for specific URLs SPA Spring Gateway WebFlux - spring

I have next CSRF code in WebFilterChain:
.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())
.requireCsrfProtectionMatcher(getURLsForDisabledCSRF())
I would like to turn off the CSRF check on POST methods for several URLs. I have found NegatedServerWebExchangeMatcher, which allows doing next:
return new NegatedServerWebExchangeMatcher(ServerWebExchangeMatchers.pathMatchers(
HttpMethod.POST, "/services/service1/api/some-post-endpoint1",
"/services/service1/api/some-post-endpoint2");
So overall this code works, but when I'm trying to GET request login page or domain page, I will get 'Invalid CSRF' or 'Expected CSRF cannot be found'. Also after Spa tries to redirect me to index.html there will be 403 on this GET redirect the request, which says: Invalid CSRF or no CSRF presented.

When setting the requireCsrfProtectionMatcher you override the default configuration which allows GET requests.
If you want to use both, you can return an AndServerWebExchangeMatcher from getURLsForDisabledCSRF that combines the default CSRF matcher and you custom matcher.
new AndServerWebExchangeMatcher(
CsrfWebFilter.DEFAULT_CSRF_MATCHER,
new NegatedServerWebExchangeMatcher(ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST,
"/services/service1/api/some-post-endpoint1",
"/services/service1/api/some-post-endpoint2"))
)

Related

Tymon Jwtauth & Laravel - how to intercept unauthorised route and return 401 error?

I am using the Tymon JWT auth library to protect my API routes in laravel. All is working, however when an unauthenticated API request is made, it attempts to redirect to a login route. I would instead like to catch the unauthenticated exception and a 401 JSON response to the front end.
In regards to the code, it's more or less the same as the tutorial below:
https://www.positronx.io/laravel-jwt-authentication-tutorial-user-login-signup-api/
Any help from someone who has already achieved this would be appreciated.
If you send the Accept header as application/json this will cause the Exception Handler to return JSON when handling the Unauthorized Exception that the auth middleware will throw. You can see this in the unauthenticated method of Illuminate\Foundation\Exceptions\Handler.
If you don't let the server know you want JSON back in some way, and there are other ways, it will assume this is a normal web request and return a redirect to the 'login' page by default.

Spring security - CSRF with REST methods

I have a rest api where I have exposed get, post, put and delete methods. I am using spring security and implementing basic authentication. I am allowing the GET request to be made by a user with the role USER whereas the other requests can only be made by a user with role ADMIN. I see that if I don't add the crsf().disable() line only the GET method works correctly, whereas I get a 403 Forbidden for other methods. However when I add csrf().disable() all the methods work fine. Is this expected or am I doing something wrong?
When csrf is enabled , springboot expects you to send the csrf token with every request that is made to the endpoint. If that is not included then the request is denied and you get the 403 response code. It is like an HTTP session. But rest endpoints are stateless so it's better not to use csrf with it . Rest endpoints are essentially immune to csrf attacks as they are stateless.Read doc.

Spring Boot/Security - Custom 404 page

I have created a custom 404 error page in my Spring Boot app, I also use Spring Security and I have an authentication entry point with a number of authorised URL's (error page included in that list).
What I'm finding is that if I enter a URL that doesn't exist the authentication entry point intercepts the request as it isn't an authorised URL and I end up back at my login page instead of the custom 404 error page. Any ideas?
Basic example of what I have in the security config
http
.csrf().disable()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
.and()
.authorizeRequests().antMatchers("/login", "/error-404")
Here is what Spring Security will do when you invoke /invalid-url
If /invalid-url is secure (default)
Store the request (/invalid-url -> session)
Invoke authentication entry point
Redirect to /login
User will authenticate
Upon successful authentication, redirect to stored request /invalid-url
Page not found - redirect to error handler
If /invalid-url is not secure
Page not found - redirect to error handler
So basically, you'd need to declare all your non secure URLs if you want the second flow, directly go to 404 page
.mvcMatchers("/login", "/error-404/**", "/invalid-url/**").permitAll()
Obviously doing this:
.anyRequests().permitAll()
as the last statement will solve your use case, it is also dangerous. You have then explicitly map out any endpoint that must be secured. And if you forget one, that endpoint will be left exposed.

Spring Social losing auth token on redirect

I'm trying to use Spring Social Facebook login along side form login, more or less following the guide here: http://www.baeldung.com/get-user-in-spring-security, only using header-based session management rather than cookies. Right now the login is successful. Facebook sends a 302 to my server at /api/signin/facebook, and my server sends a 302 to the post-sign-in url I've set on my ProviderSignInController along with the x-auth-token header. The issue is that when following the last redirect my browser throws away the auth token.
I think I want to just add the auth token as a query param on the final redirect uri, but I don't know how to intercept the final response. I've called setSignInInterceptors on my ProviderSignInController but that seems to be ignored after the first sign in. How can I keep my session information when it's not a cookie?
Just added the token as a query parameter and returned it from my custom SignInAdapter.signIn method. I feel like there's probably a better solution but I needed something.

How do I send spring csrf token from Postman rest client?

I have csrf protection in spring framework. So in each request I send csrf token in header from ajax call, which is perfectly working.
<meta name="_csrf" content="${_csrf.token}"/>
<meta name="_csrf_header" content="${_csrf.headerName}"/>
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
In ajax
beforeSend: function(xhr) {
xhr.setRequestHeader(header, token),
xhr.setRequestHeader("username", "xxxx1"),
xhr.setRequestHeader("password", "password")
}
I haven't any idea to generate csrf token and include in header section of Postman Rest Client ? Would you please help me to send csrf token from Postman Rest Client?
The Easiest way to do this consistently so you don't have to get the token each time:
NOTE:you need to install PostMan Interceptor and activate it to have access to the browsers cookies
Create a new environment so environment variables can be stored
Create a login method with a test to store the XSRF cookie in an environment variable, in the test tab post this code
//Replace XSFR-TOKEN with your cookie name
var xsrfCookie = postman.getResponseCookie("XSRF-TOKEN");
postman.setEnvironmentVariable("xsrf-token", xsrfCookie.value);
EDIT
For anyone using the 5.5.2 postman or later you will also have to decode the cookie, and they have also provided alternative ways to obtain cookies as #Sacapuces points out
pm.environment.set("xsrf-token", decodeURIComponent(pm.cookies.get("XSRF-TOKEN")))
Now you will have an environment variable with xsrf-token in it.
Save your login method
Create the new post you want to create and in the headers add your XSRF-Token-Header Key, and the environment variable in handle bars to access it{{}}
Now before running your new request make sure you run your login, it will store the environment variable, and then when you run the actually request it will automatically append it.
I am able to send REST with csrf token by following the steps below:
The CSRF token generated automatically by spring security when you logged in. It will be shown at the response header.
The CSRF token can be used on subsequent request by setting X-CSRF-TOKEN with CSRF token on header.
Firstly you need to install PostMan Interceptor and activate it to have access to the browsers cookies.
You have to fetch the CSRF Token by making a GET Request:
Header: "XSRF-TOKEN" and Value: "Fetch"
You should see the Token in the cookie tab and can copy it (Notice: You can configure spring how the cookie should be named. Maybe your cookie has another name than "XSRF-TOKEN". Attention: You have the remove this blank char in the token from the newline)
Now make your POST Request and set the header to: Header: "X-XSRF-TOKEN" and Value: "Your copied Token without blanks"
For me works variant with adding X-CSRF-TOKEN to headers.
Please put X-CSRF-Token as key and FETCH as the value in the GET request header and you will receive the token in the response header
If you don't want to configure environment variables etc. here is the quickest solution
https://stackoverflow.com/a/49249850/3705478
I've used csrfTokenRepository() to allow spring security to generate csrf token
#EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
// your code
}
}
After adding these lines of code, use GET request to generate csrf token. I've used postman and I got token in the response cookies section. Copy the token and use it in POST call.
Official documentation link :
https://docs.spring.io/spring-security/site/docs/5.0.x/reference/html/csrf.html

Resources