Getting security right is critical when building web apps. The upside of building a web app is that people can use it wherever they are, on any device. But you need to ensure that only the right people are able to access it, and that they have access to only the features you intended.
In this month's Vaadin webinar, I hosted Petter Holmström, Principal Software Engineer at Vaadin. Petter has more than a decade of experience in architecting and building some of the largest customer projects Vaadin has delivered over the years. In this webinar, he shares some of his hard-learned lessons for securing Vaadin apps.
You can find the webinar recording on YouTube, or continue reading for the highlights:
1. Don't reinvent the wheel when it comes to security
Petter strongly encourages you to use existin
g, battle-tested security solutions, instead of trying to build your own. It's hard to get security right, so you can give yourself a head start by using industry-leading solutions like Spring Security and Keycloak.
2. Understand how Vaadin handles sessions
When using a single sign-on (SSO) provider like Keycloak, there are three different sessions you need to be aware of: the Vaadin session, the HTTP session, and the SSO session. For instance, only invalidating the Vaadin session when logging out would allow the user right back into the application, as the HTTP session still contains the authentication token.
3. Understand how and when to log out through OIDC
If you have a single application using Keycloak for SSO, you may want to close the OIDC (OpenID Connect) session when logging out. But if several apps use the same SSO, you probably want to keep the OIDC session open to continue allowing access to all the other applications using it.
4. Handle back-channel log-outs
Some enterprises and organizations require support for single sign-out, that is, telling applications to close any associated HTTP and other sessions when the OIDC server is logged out. Although Spring Security doesn't support back-channel log-outs out-of-the-box, Petter shares an example implementation in his code repository.
5. Handle cross-site request forgery (CSRF) right
Vaadin and Spring both handle CSRF independently, and these implementations are not compatible. Prior to Vaadin 21, the solution was usually to turn off CSRF in Spring Security and let Vaadin handle it. The Vaadin 21 security helper is finer-grained, only disabling Spring CSRF for the paths Vaadin uses, and keeping it enabled for all other paths.
6. Prevent cross-site scripting (XSS) attacks
Vaadin has built-in support against XSS attacks, as it renders all content as text instead of HTML. You need to pay special attention when you need to render HTML or execute custom JavaScript. Ensure that all HTML is sanitized and that you trust the JS.
7. Prevent injection attacks
As with all SQL apps, use query parameters instead of concatenating user input into a SQL query string, so that the input gets sanitized before being executed.
8. Enable HTTPS
Always enable HTTPS. It's simple and should be done as early as possible in the project, so you don't forget about it.
9. Role-based authentication
In order to use role-based authentication with OIDC and Spring Security, you need to extract the roles from the OIDC token into the Spring Security authentication token. You can use the roles to restrict access to views and services. Vaadin 21 includes support for the @RolesAllowed annotation to specify which roles are allowed to navigate to a certain view.
10. User-based authentication
Often, you need finer-grained control than roles. Defining access permissions for specific users is something you need to take into account when designing the domain model of your application, and is another reason why you should take securing the application into consideration right from the start of a project.
11. Leaking the Security Context
You need to pay special attention to how you handle events in your application to avoid leaking the Security Context. The Spring Security Context is bound to the thread, so executing listeners for other users in the same thread will cause them to get executed with the authorities of the user that triggered the event.
12. Missing the Security Context
Another common problem is that asynchronous code triggered by the backend does not have an active HTTP session that contains the Spring Security Context. You will most often run into this when you are using UI.access() and notice that you don't have access to a service. In this case, you can create a custom strategy for storing the Security Context in the Vaadin session instead.
Watch the entire webinar for more details
You can find the complete webinar on YouTube. You can find the source code for the example application on Petter's GitHub.
You can learn more about Vaadin’s framework security and security practices in the technical documentation.