Although we don’t use session cookies with our Spring Security with OAuth 2.0 and OIDC web app, we may have to implement them to hold our tokens. In these perilous times, you must know a little bit about securing your sessions and cookies.
With the way Spring Security works, setting up your session security will, in turn, secure your cookies.
Understanding Cookies
Let’s review why you need session cookies in Java web applications. A user logs into an e-commerce site without cookies and starts clicking on links. With each clicked link, the user would have to log in again, over and over. Cookies were created to save a user’s session in the browser so they could stay authenticated at least until they log out.
Ultimately, you are protecting a user’s session after they have authenticated to the browser. The browser saves a user’s authentication on the browser with a cookie or a token. Malicious users have a habit of stealing useful information about a user by using information from cookies. The way the cookie information is stored and safeguarded is vital for the front-end developer to configure correctly. On the flip side, the backend developer must ensure these credentials are encrypted in the database and secure how all queries to the database are configured.
OAuth 2.0 uses token-based authentication. Why do I need to know how to configure a cookie?
A token can carry a cookie that holds the session information, and if it does, it is automatically encrypted. Score! So, if you are not configuring cookies, you can always add security rules to manage your session.
Securing Your Session
The SessionManagementFilter can be configured in your security filter chain to give more control over your sessions. Typically, the cookie does the job for you, but if there isn't one or it's not configured securely, this filter can add another layer of security.
By default, Spring Security uses SessionManagementFilter. A session is only created if it’s required using if_required. It checks to see if the user is authenticated while on a specific URL. The options if the user is not authenticated is:
Always creates a session at all times.
Never won't create a session through Spring Security (the web app may have another means to start a session).
Stateless means that no session will be created by any means; whether through Spring Security or the web app.
If you want to custom configure the sessionManagement()
options in your security filter chain, there are several methods that also allow for custom pages based on your session status.
@Override
protected void configure(HttpSecurity http)throws Exception{
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.sessionFixation().migrateSession()
.expiredUrl("/sessionExpired.html")
.invalidSessionUrl("/invalidSession.html");
}
Let’s talk about concurrent sessions. The .sessionFixation().migrateSession()
methods can be used to prevent users from being logged in more than once. If a user is logged into a session on Computer A, and then logs in on Computer B, the session on Computer A migrates to Computer B. This makes Computer A’s session invalid.
It helps if you want to prevent people from sharing logins or a malicious user with unauthorized access because this is the configuration that blocks concurrent sessions.
Also, adding customized error pages is a good practice because it ensures that default exception handling mechanisms don’t reveal too much information about your client web app. You can add a customized error page to notify the user of why they cannot reach the page with the expiredURL()
method and invalidSessionUrl()
method.
So how about making session times shorter to help prevent attacks? If you don’t set the configuration in a the cookie, you can also limit session time by specifying it in the application.properties file. The line of code below will specify that a session expires after 20 minutes:
server.servlet.session.timeout=20m
Lastly, the session ID was in the URL of the user’s page while authenticated. How can you secure this session from getting hijacked? Store the session ID in the cookie rather than on the URL! Add this to the application.properties file:
server.session.tracking-modes=cookie
Securing Session Cookies (Just in Case)
If you custom configure your session cookie, there are some security methods you should know. So let’s talk about how you should configure your cookie for optimal security. We’ll look at some bad cookies and solutions for fixing them.
1) The Cookie That Tells All
A user logs into an e-commerce site, and now their credentials are stored in plaintext on the cookie. If anyone obtains access to the cookie, they have the user’s username and password to gain unauthorized access to that e-commerce site.
What is the fix?
Use encryption for user’s session data to include their credentials. This is done by setting the HTTPonly
flag to true.
First, make sure that HTTPonly
is set to true. HTTPonly
renders the saved cookie in the browser, making it inaccessible to third party scripts that attempt to access the cookies. Think of it as a lock on that cookie jar that blocks XSS scripts from collecting cookies and sending this data back to malicious hosts.
2) The Cookie That Stays Forever
A user’s cookie is set to keep them logged in forever. Now the user can always count on being logged in instead of constantly having to remember a password. That’s convenient, but if a malicious user gains access to the browser, he/she won’t need to try a password because the session is still ongoing!
What is the fix?
Configure the cookie to expire. Use cookie.setMaxAge()
method to set your cookie expiration time.
3) The Cookie in a Glass Jar
A user’s cookie has given the user a session ID number 1234. Conveniently, the session number is also in the URL to denote that the user is authenticated and still in session. But wait - now the hacker knows the session ID, can go to that URL, and look like he/she is authenticated using a session hijacking attack. Whoops.
What is the fix?
Create random URLs when a user is authenticated and protect the session ID when it's in the cookie.
You can prevent session hijacking with a few cookie settings that can protect that session ID that’s stored on the cookie. You can use cookie.setSecure()
so it is always transmitted in an encrypted HTTPS connection. You can also use cookie. setHttpOnly ()
to prevent your cookie from being accessed by third party scripts. Finally, use cookie.setPath()
to set the scope of where the cookie is sent and saved.
Putting all of that together, here are some ideas for secure programming options for your new cookie:
public String setCookie(HttpServletResponse response) {
Cookie cookie = new Cookie("username", “cookiemonster”);
cookie.setMaxAge(60); //sets expiration after one minute
cookie.setSecure(true);
cookie.setHttpOnly(true);
cookie.setPath("/vault");
}
If you create a method to delete your cookies, you can set the following options:
public String setCookie(HttpServletResponse response) {
Cookie cookie = new cookie(“username”, “null”);
setMaxAge(0);
}
Although these are set to true by default, you can ensure that they are flagged as true by putting these settings in your applications.properties file:
server.servlet.session.cookie.http-only=true
server.servlet.session.cookie.secure=true
You learned some commonly used techniques to secure your sessions and cookies for your Spring web application when you have OAuth 2.0 implemented. Since we mostly worked with tokens in our demo, I put more emphasis on securing our sessions. It's is a great place to start and works great regardless of whether you use cookies in your app or not!
Let’s Recap!
Cookies are stored on your browser and often get used by hackers to steal credentials and sessions.
Tokens are stored in local storage and are a bit harder to hack since they don’t carry credentials.
You can secure your session using the SessionManagementFilter with expiration time, allowing one session at a time, store session ID securely, and manage using Spring Security to protect your session.
You can secure a session cookie by setting an expiration, only allowing encrypted network transmission, blocking third party with the
Httponly
flag, and configuring where it is stored.
Now that you've learned some additional security, let's configure some OAuth servers!