Security has always been a very important factor for any kind of application, and we're only talking about software here. Since before the computerization of systems, there have been people trying to circumvent the processes. With the advance of technology, we now have applications available at all times and in a much easier way than before.
As programmers, we often worry about the usability and performance of our applications, but it is also crucial to ensure that data travels securely between clients and servers. On the web, we have several forms of attacks and several ways to prevent them. In this article, we'll focus on a specific type of attack called cross-site request forgery (CSRF) and talk about some examples and ways to prevent it. To do this, we'll use Kotlin as the programming language.
Going Further
Let's begin with an example.
If, in an application, we have a request to return some data about the user logged into the system, the browser needs to ensure that the request has the same origin. This means that a website is allowed to freely request data from its own URL but blocks anything from an external URL unless we specify this permission on the server side. We call this the same-origin policy. This prevents external websites from requesting data that they should not be allowed to have.
We also send cookies for any request made. The app needs a way to identify the user, and the standard way of identifying a user on the web is to use cookies. For example, when a user logs in to a social media site, the server sets a cookie with a unique user ID. As the user browses the site, each request to the server contains the cookie.
The server can read the cookie from the request and load user-specific data, such as the user’s timeline or access permissions.
So we use random tokens that we generate on the application back end, and we send them to the website as a way to prevent attacks like CSRF.
Since we have to validate the new token in each request, a malicious website cannot simply make the request as if it were legitimate because it doesn't have the correct token.
After that, you need to configure Spring Security’s CSRF protection within your application. We're using this tool because it plays well with Kotlin and already has a good amount of documentation. We can make customizations, but we already enable CSRF protection by default.
How Do We Protect Our Users From CSRF?
What you want to ensure by using CSRF protection is that only the front end of web applications can perform mutating operations.
A client must send an ask utilizing HTTP GET to see the webpage once in a while. When this happens, the application produces a unique token. The application considers that knowing the origin of the token is confirmation that it is the app itself making the changing ask and not another framework.
We may have the starting point of CSRF assurance as the channel within the channel chain called CsrfFilter.
The CsrfFilter intervention demands and permits all those that utilize these HTTP strategies: GET, HEAD, TRACE, and OPTIONS. For all other demands, the channel expects to get a header containing a token. On the chance that this header doesn't exist, the application rejects the ask. The CsrfFilter uses a component named CsrfTokenRepository to manage the CSRF token values that create modern tokens. By default, the CsrfTokenRepository stores the token on the HTTP session and creates the tokens as UUIDs.
A Simple Example
Let's consider a simple login form, for example, that requires a username, password, and CSRF token. For the front end, we just need to include the CSRF token in the form.
This example is available on Stone Soup Programming.
Once we finish the development of our front-end code, we want to design Spring Security to utilize this page. To render the login page, Spring requires a few controller classes.
@Configuration
class WebConfig : WebMvcConfigurerAdapter() {
override fun addViewControllers(registry: ViewControllerRegistry) {
//Default controller for the login page.
registry.addViewController("/login").setViewName("login")
}
}
Then we configure Spring Security:
@Configuration
@EnableWebSecurity //Turn on Web Security
class SecurityWebInitializer : WebSecurityConfigurerAdapter(){
override fun configure(http: HttpSecurity) {
http
.authorizeRequests()
//We need to allow anonymous users to
//access the login page (otherwise we get 403)
.antMatchers("/login").anonymous()
.anyRequest().authenticated()
.and()
//Setup a custom login page
.formLogin()
.loginPage("/login")
.usernameParameter("username")
.passwordParameter("password")
.and()
.httpBasic()
}
override fun configure(auth: AuthenticationManagerBuilder) {
//Sets up a user store in memory. Useful for debugging and development
auth
.inMemoryAuthentication()
.withUser("joe")
.password("black")
.roles("USER")
.and()
.withUser("administrator")
.password("administrator")
.roles("USER", "ADMINISTRATOR")
}
Which Sorts of Applications Ought to Utilize CSRF Protection?
You employ CSRF assurance for web apps running in a browser, where you should expect that transforming operations can be done by the browser that loads the displayed content of the app.
Since applications have different prerequisites, any implementation provided by a system should be sufficient to be effectively adjusted to different scenarios. The CSRF security instrument in Spring Security is no exception. We utilize CSRF assurance, as it were, when the page that accepts the assets delivered by the server is itself produced by the same server. It can be a web application where the consumed endpoints are uncovered by a distinctive root.
Sometimes you may need to customize the management of CSRF tokens. As you now know, by default, the application stores CSRF tokens within the HTTP session on the server side. The HTTP session is stateful and reduces the versatility of the application. Let’s assume you need to alter the way the application manages tokens and store them someplace in a database instead of within the HTTP session. Spring Security offers two ways to do this:
CsrfToken: Describes the CSRF token itself
CsrfTokenRepository: Describes the object that creates, stores, and loads CSRF tokens
Recommendations
For the most part, you simply require the occurrence of the CsrfToken to store the details in the qualities of the request. CsrfTokenRepository is dependable for overseeing CSRF tokens in Spring Security. The interface CsrfTokenRepository is the contract that speaks to the component that oversees CSRF tokens. To alter the way the application oversees the tokens, you'd need to actualize the CsrfTokenRepository interface, which allows you to plug your custom execution into the system.
In any case, a few issues with this adjustment can be found on destinations that utilize such tokens. We list a few of them below:
Only the POST method validates the secret anti-CSRF token.
When the server doesn't check the token, it can be excluded from the shape beneath the attack.
The token isn't tied to the victim's session and is basically disseminated from a worldwide pool of the application, making it conceivable for the aggressor to utilize their mystery token to perform an activity on another account.
There's the possibility of reusing this token, clearing out a settled origin in all requests.
Caveats
These are a fair few cases of issues with this fix demonstrated, since the assailant will continuously attempt to demolish the forced validations.
Among the possible solutions, one is unpredictable tokens, inserted in hidden fields in HTML forms. We need to validate the token on the application server as a way to impose a challenge. It's important that each time we make a request, a new token is provided by the server. We call this mechanism the per-page token.
We need to ensure that this token is unique, and we check it for every operation in the application.
Conclusion
In closing, we reinforce that the implementation of several layers of security is always important. A motivated attacker will always look for ways to subvert the protections in place. We recommend always following good security practices, assessing your risk, and reducing your attack surface as much as possible.
A good initial precaution is the separation of browsing profiles. It's important, at least, to separate your professional profile from your personal profile. You can also create other profiles: one just for research, another for online shopping, etc. And, of course, we must always be aware of what we install and access on our devices. CSRF is an old web application security problem, but one that still causes negative impacts on its victims.
Given the rapid pace at which our generation develops new digital products, it becomes increasingly essential to consider security. For those of you building, remember to have the security requirements plus the operational requirements of an application.
This post was written by Rhuan Souza. Ruhan is a software engineer who has experience with infrastructure. Ruhan is currently working as a full-stack web developer. He’s a passionate developer who focuses not only on code, but also wants to help change processes, and make people's lives easier.