Version: v0.9.0

Security

There's not doubt that Rust is a safe programming language. It was designed to prevent memory handling errors that can lead to security flaws. Furthermore, it helps developers to figure out why the software doesn't work.

However, this doesn't mean that our app is danger free. And, as every other web application, obviously is not. Here is where Kalgan comes to the rescue to help us to mitigate and cope with some of most important risks that threaten web applications.

First section of this chapter is dedicated to the top ten Web Application Security Risks list elaborated by OWASP Foundation. The following ones cover some of the most common risks, what the developer should do and how Kalgan helps to mitigate them.

OWASP Top Ten

Since 2003 the Open Web Application Security Project (OWASP) provides a list of the top 10 most critical web application security risks.

It' a standard awareness document for developers and web application security. It represents a broad consensus about the most critical security risks to web applications. Globally recognized by developers as the first step towards more secure coding.

Needless to say, Kalgan is not unfamiliar to this rank. Find the checklist below with the support provided:

Security Risks Kalgan Support
A01:2021-Broken Access Control Yes
A02:2021-Cryptographic Failures Partial
A03:2021-Injection Yes
A04:2021-Insecure Design Yes
A05:2021-Security Misconfiguration Yes
A06:2021-Vulnerable and Outdated Components Partial
A07:2021-Identification and Authentication Failures Partial
A08:2021-Software and Data Integrity Failures No
A09:2021-Security Logging and Monitoring Failures Partial
A10:2021-Server-Side Request Forgery No

Be aware that even though Kalgan provides support out of the box to mitigate most of these risks, all of them require the action of the developer.

A closer look to these risks is out of the scope of these docs. Go to the official site for more information.

SQL Injection

SQL Injection is a very popular attack based on malicious SQL queries for database manipulation. The attacker might alter or get access to information in the database that was not intended to be displayed.

This attack is mitigated through data sanitization. That is to say, by removing all dangerous characters from an input string before passing it to the SQL query.

Kalgan is not tightly coupled to any database crate/orm. However it recommends using sqlx crate and provides a collection of built-in functions to create the pool of database connections with SQLx.

SQLx provides support out of the box to migitate SQL injection attacks through the ? query placeholders. We must follow this way every time an input parameter is sent instead of just concatenating strings to build the query.

Let's see an example:

use kalgan::service::db::mysql_pool;
use sqlx::mysql::MySqlQueryResult;

#[derive(Debug)]
pub(crate) struct User {
...
}
pub(crate) async fn create(username: &str, password: &str, email: &str) -> Result {
    sqlx::query_as!(User, "INSERT INTO user (username, password, email) VALUES(?, ?, ?)",
        username, password, email).execute(&mysql_pool().await).await
}

For more information regarding databases see Database / SQLx in the docs.

XSS Attack

Cross-Site Scripting (XSS) is an attack where a malicious script (JavaScript) is injected into a web application. This script might steal data from visiting users such as their cookies, session tokens or any sensitive information transmitted to the application.

Again, this attack is mitigated through content sanitization before rendering it into the UI. For this purpose template engines usually escape all dangerous characters by default.

As we have already seen, Kalgan uses Tera crate as template engine. Every time we render ( {{ .. }} ) a variable which has been passed to the context Tera escapes it by default. For example:

...
<p>{{ my_var }}</p>
...

However, sometimes we're going to need to render the raw value of the variable. In this cases we must add filter |safe right after the variable. For example:

...
<p>{{ my_var|safe }}</p>
...

We just must be sure that the content of this variable is really safe. :)

Last but not least, there's one big drawback though as Tera does not perform contextual auto-escaping, eg by parsing the template to know whether to escape JS, CSS or HTML. See Using type inference to make web templates robust against XSS.

For more information regarding templating see Templates / Tera in the docs.

CSRF Attack

Cross-Site Request Forgery (CSRF) is anf attack that occurs when a malicious web site causes a user's web browser to perform an unwanted action on a trusted site when the user is authenticated. CSRF is one of the most common attacks known and must be taken into account every time we work with HTML forms.

Kalgan provides a simple tool to protect against CSRF attacks. This logic resides in module kalgan::service::csrf, which contains the following functions:

is_valid Checks whether the token matches with the csrf session.
get_token Return a 200 character length token to be rendered in the HTML form.

CSRF protection is based on the synchronizer token pattern. Let's see an example of the workflow:

  1. Set the csrf session and the linked cookie in our settings.yaml:

    session:
        csrf:
            cookie: csrf
        ...
    cookie:
        csrf:
            name: csrf
            max_age: 3600
            http_only: true
        ...
  2. In the controller, return the csrf token to the client and create the csrf session (this returns the cookie to the client).

    use kalgan::http::response::Response;
    use kalgan::http::request::Request;
    use kalgan::service::csrf;
    ...
    pub(crate) fn display_form(request: &Request) -> Response {
        ...
        let token = csrf::get_token();
        response::render("foo.html", context!(
            "csrf_token" => &token,
        )).add_session("csrf", Session::new(&request).create(token))
    }
  3. In the template, create in the HTML form an input field with the value of the csrf token and named csrf_token.

    ...
    <form action="/" method="post">
        <input type="text" name="user_name">
        <input type="password" name="user_password">
        <input type="hidden" name="csrf_token" value="{{ csrf_token }}">
        <input type="submit" value="Upload Data">
    </form>
    ...
  4. Finally, once the client submits the HTML form, we must check whether the input token matches our csrf session. Notice we only have to pass the request as a parameter to the function csrf::is_valid.

    use kalgan::http::response::Response;
    use kalgan::http::request::Request;
    use kalgan::service::csrf;
    ...
    pub(crate) fn parse_form(request: &Request) -> Response {
        if csrf::is_valid(request) {
            ...
        } else {
            ...
        }
    }

For more information regarding HTML forms see Handling forms data in the docs.

Password Storage

Hashing passwords is the foundation of secure password storage (password must never be stored in plain text format, right?). It is used to verify the integrity of the password (sent by the user) against the stored hash so that your actual password is never stored. However, not all cryptographic algorithms are suitable for a modern web application.

Kalgan provides in module kalgan::service::password a couple of functions based on Argon2 hash for password management:

hash Returns an Argon2 hash for the given password.
verify Checks whether the plain password matches the hash password.

Using these functions is pretty straightforward. Let's see an example:

use kalgan::service::password;
...
let my_password = password::hash("my_password");
dbg!(password::verify("my_password", my_password.as_str()));
...

Notice that Argon2 is the password-hashing function recommended by OWASP foundation.