It's common knowledge that HTTPS URLs are safer than plain HTTP. The "S" confirms some transport layer security TLS, which protects your network from middleman attacks among other threats. Implementing Rust HTTP Strict Transport Security (HSTS) is a step you should keep at the back of your mind as you develop with Rust-Lang.
This post explores just what it means when, for instance, you conduct a health scan of your Rust web application and get a "HSTS headers missing" report. We'll cover why you need to have the headers in place, how they work, and how best to implement HSTS across Rust and its frameworks.
Why You Need Rust HSTS
When you have Rust HTTP strict transport security in place, your web application redirects to HTTPS even when a user types HTTP:// in the navigation bar. Assuming your certificates and other security measures are watertight, this imbues the user experience with a significant level of security.
Now, there's only so much that browsing with the HTTPS version of your site can benefit you and your users. However, without it, hackers can do as they please with your applications. Let's explore some harms that HSTS protects your users and the application itself from.
What HSTS Protects You From
Among the space of vulnerabilities, you can avoid the following by having valid (properly implemented) HSTS headers.
Loading Unsafe Versions of Your Website
It's not new that some cPanel options lead to developers accepting both HTTP and HTTPS loading of their web applications. While it may seem convenient because now everyone that knows your domain can access your application, it's actually a security flaw.
Loading the HTTP version of your website means even the resources passed from other sources don't need any certificates. This leaves your application open to a wide range of other threats.
Man-in-the-Middle Attacks
Notice how we stressed proper implementation of HSTS headers? When you rely on manually imposed redirects (HTTP 301) instead of the HSTS header method, hackers can send visitors to your application to their own versions of your website. Then, there won't be restrictions on what they can do with the information they steal from your patrons.
Future Bugs
When you neglect to impose Rust HTTP strict transport security, your application's integrity weakens with multiple bugs. This deteriorates user experience and hints to hackers just where your application is weak when they open the console. Even when your code is perfect, not having a good redirect policy can become the weak spot in your otherwise perfect application.
Rust HSTS Won't Protect You From The Following Threats
Tempting as it is to relax once you have your Rust HTTP strict transport security in place, you're far from being safe. The header is porous to the following vulnerabilities:
Phishing
When hackers make an app to appear as if they're you, the browser won't distinguish between the two. HSTS headers, however, assist within your version of the application with restrictions that make it easy for users to detect clones. This is why banks and other reputable organizations continuously educate their visitors about the dangers of phishing.
Breaches Due to Defective Code
No matter how much you restrict users within the HTTPS fence, if your code has vulnerabilities that hackers can leverage, chances are they will.
In reality, the HSTS headers are best taken as extra coverage of some loopholes—not the fix-all security solution for Rust applications (or any other programming language). Having the headers will reinforce your security strategy.
Rust HSTS in Action
Now that you know what Rust HTTP strict transport security means and what it can accomplish, let's explore how best to implement it. Because a lot of web applications now rely on CDN platforms for better reach, as with CloudFlare, turning HSTS on and off can be a matter of toggling an option.
The same holds for hosting platforms like Heroku and any cPanel-managed Rust applications. While these options save you from the complexity of manually adding the headers to your application, always make sure HSTS headers are active. For this, you either check the source of your application in production (backend), or simply run a Mozilla Observatory check on your domain.
Typical results from an observatory scan.
This report shows that they (rust-lang) set the HSTS header to a maximum of six months. However, it's possible, and recommended, to set a longer time—even two years. For the header to take effect, a browser will need to have accessed your application and recorded the HSTS header at least once. This way, every other visit for the coming two years will redirect to HTTPS. This works even when the user has an HTTP version in their bookmarks.
Consider the header below, which shows an implementation of an "always set" HSTS header with a maximum age of one year (in seconds).
Header always set Strict-Transport-Security "max-age=31536000;
includeSubDomains; preload"
The "include subdomains" directive covers the entire domain tree—that is, its branching environments at the end of subdomains. If you create a new domain after setting this header, it too will be safe.
The "preload" directive gives consent to the browser to cache and permanently deem your domain and application pair a strict HSTS instance. This makes it possible for unknown visitors to load the HTTPS version of your application immediately, with no prior rendering requirements.
Applying Rust HSTS Through Cargos
When it comes to applying Rust HTTP strict transport security in applications built on top of frameworks (such as Rocket.rs), you have two options. The first is to create your own headers and call them where they're needed. Alternatively, you could leverage implementations in cargos with tests and documentation at your disposal.
A common solution to the HSTS conundrum is the Armor crate.
let mut headers = http::HeaderMap::new();
armor::hsts(&mut headers);
assert_eq!(headers["Strict-Transport-Security"], "max-age=time");
Replacing "time" with your duration should extend the validity of your implementation. The code above restricts users to a strict HTTPS usage. However, it can't guarantee that users can open an incognito browser to run a strictly HTTP session. For this reason, you should have a server-side implementation always on the guard.
To offset the HTTP loophole left open with some cargos, you're best implementing the single-line header within your main file. Just as follows:
use rocket::fairing::{Fairing, Info, Kind};
use rocket::http::{ContentType, Header};
use rocket::{Request, Response};
static HEADERS: &[(&str, &str)] = &[
("x-xss-protection", "1; mode=block"),
("strict-transport-security", "max-age=63072000"),
("x-content-type-options", "nosniff"),
(
"referrer-policy",
"no-referrer, strict-origin-when-cross-origin",
),
];
This way, your application can't run on HTTP even when someone tries to bypass your implementation through sneaky means.
Conclusion: Rust HSTS Best Practices
It's possible to build a Rust application with no frameworks guiding or imposing methods on your process. However, for this you'd need to pay closer attention to your headers and where they apply.
The good thing about the HSTS header is that it's a low-maintenance variable. Once you declare the time duration and any subdomain support, along with the preload option, you can rest assured that it gets read each time your application loads.
A best practice is having tests run whenever you're deploying your applications into production. StackHawk can help with that. This way, no live applications expose users to the threats that hackers are ready and eagerly waiting to inflict on your Rust applications.
This post was written by Taurai Mutimutema. Taurai is a systems analyst with a knack for writing, which was probably sparked by the need to document technical processes during code and implementation sessions. He enjoys learning new technology and talks about tech even more than he writes.