Common Vulnerabilities
- SQL Injections
- Cross-Site Request Forgery (CSRF)
- Cross-Site Scripting (XSS)
- Java Serialization Vulnerability
SQL Injections
Since Vaadin is a back-end-agnostic UI framework, it doesn’t deal directly with back-end access. Instead, choosing a back-end framework (for example, Spring Data) is left to the developer. Vaadin doesn’t provide mitigation for SQL injections; this is left to the back-end provider and developer.
However, following the data validation and escaping guidelines (see the Cross-Site Scripting (XSS) section), as well as standard secure database access practices, SQL injections can be completely blocked in Vaadin applications.
Most providers have their own ways of dealing with injections out of the box and you should follow those guides.
However, if the developer uses pure JDBC, they have to deal with injection risks themselves.
Here is an example with pure JDBC, demonstrating an SQL injection mitigation using the value from a TextField
in a prepared statement:
new TextField("Set new username:", valueChangeEvent -> {
String value = valueChangeEvent.getValue();
// 'value' can contain malicious content!
// This is the correct way
String sql = "UPDATE app_users WHERE id=? SET name=?";
try {
// Use prepared statement to safely call the DB
PreparedStatement ps = dbConnection.prepareStatement(sql);
ps.setLong(1, user.getId());
ps.setString(2, value);
ps.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
}
// This is the INCORRECT way, Don't USE!
// sql = "UPDATE app_users WHERE id="+ user.getId() +" SET name=\"" + value +
// "\"";
});
Cross-Site Request Forgery (CSRF)
All requests between the client and the server are included with a user-session-specific CSRF token. All communication between the server and the client is handled by Vaadin, so you don’t need to remember to include and verify CSRF tokens manually.
The CSRF token is passed inside the JSON message in the request body:
Sending xhr message to server:
{"csrfToken":"0bd61cf8-0231-455b-b39a-434f054352c5","rpc":[{"type":"mSync","node":5,"feature":1,"property":"invalid","value":false},{"type":"publishedEventHandler","node":9,"templateEventMethodName":"confirmUpdate","templateEventMethodArgs":[0]}],"syncId":0,"clientId":0}
In Vaadin services requests, the CSRF token is passed in the X-CSRF-Token
HTTP header:
X-CSRF-Token: 0bd61cf8-0231-455b-b39a-434f054352c5
The CSRF token mechanism can be overridden on the server to enable, for example, repeatable load test scripts using Gatling or similar tools. This is strongly discouraged when running in production.
Cross-Site Scripting (XSS)
Vaadin has built-in protection against cross-site scripting (XSS) attacks.
Vaadin uses browser APIs that make the browser render content as text instead of HTML, such as using innerText
instead of innerHTML
.
This negates the chance of inserting, for example, <script>
tags into the DOM by binding insecure string values.
Some Vaadin components explicitly allow HTML content for certain attributes, in which case your application needs to ensure that the data doesn’t contain XSS payloads. Allowing insecure HTML content is never the default; it’s an explicit choice by developers. Vaadin recommends using, for example, jsoup for sanitation and escaping.
Here are a few examples of built-in escaping, and some where escaping is left to the developer:
Div div = new Div();
// These are safe as they treat the content as plain text
div.setText("<b>This won't be bolded</b>");
div.getElement().setText("<b>This won't be bolded either</b>");
div.setTitle("<b>This won't be bolded either</b>");
// These aren't safe
div.getElement().setProperty("innerHTML", "<b>This IS bolded</b>");
div.add(new Html("<b>This IS bolded</b>"));
new Checkbox().setLabelAsHtml("<b>This is bolded too</b>");
The developer can use helpers to mitigate the risk when data isn’t trusted. Here is an example that transforms data that might have dangerous HTML to a safe format:
String safeHtml = Jsoup.clean(dangerousText, Whitelist.relaxed());
new Checkbox().setLabelAsHtml(safeHtml);
Running Custom JavaScript
Sometimes application developers need to run custom scripts inside the application. Running any script is an inherently unsafe operation, because scripts have full access to the entire client side. It’s especially dangerous if the script is stored somewhere other than the application code and loaded dynamically:
// The script below can do whatever it wants, use the method with care!
UI.getCurrent().getPage().executeJs("window.alert('This method is inherently unsafe');");
// This is especially dangerous!
// We can't know what the script contains, nor can we make it safe.
String script = getExternalScript();
UI.getCurrent().getPage().executeJs(script);
Scripts can’t be automatically escaped, since any escaping would cause the script not to work, which would defeat the purpose of running a script. Vaadin can’t know which scripts are dangerous and which aren’t. It’s up to the application developer to make sure that the scripts that are run are safe. However, the developer can pass parameters to JS execution safely by using the following syntax:
// If the script is known:
String script = "window.alert($0)";
// These parameters are treated in a safe way
String scriptParam = getScriptParamFromDB();
UI.getCurrent().getPage().executeJs(script, scriptParam);
Using Templates
When using Polymer Templates in Vaadin applications, the developer needs to be extra careful when inserting data into the DOM, as well as using JavaScript.
Vaadin automatically uses String values safely when using a TemplateModel
from the server side, but the framework has no control over what the developers do using HTML or JavaScript inside the template itself.
An example is binding a TextField
with a JavaScript value directly to client-side logic; there is no guarantee that the input is safe, and it should be sanitized before use.
Reading values from template models and receiving Remote Procedure Calls (RPC) in server-side methods has the same caveats as discussed in the Data Validation section. The developer should never trust values sent from the client.
Java Serialization Vulnerability
A general security issue has been identified in programming language mechanics where the language allows execution of code that comes from serialized objects. The Java language isn’t immune to this; at least the Java Serialization framework, Remote Method Invocation (RMI), Java Management Extensions (JMX), and Java Message Service (JMS) features are vulnerable to it.
If the application is set up to deserialize Java objects (for example, using the libraries previously mentioned), an attacker can feed the system a malicious payload that gets deserialized into Java objects. The attacker can then execute arbitrary code using specific language features (such as reflection).
Vaadin has published a security alert for this vulnerability.
The vulnerability can’t be fixed in Vaadin, but developers must instead mitigate the risk using the methods described in the alert appendices.
CB8041B3-5938-419F-A6C1-999F713A2A99