On production environments, most websites are running under Hypertext Transfer Protocol Secure (HTTPS). This is an encrypted channel that is designed to keep the data between a client browser and server secured.
When deploying a new website or application, we need to ensure that all traffic coming into the application is via the secure protocol (HTTPS). We should note that this is not available by default. For the most part, this is usually, and the preferred approach, a server side and/or domain registrar redirect rule.
In some cases, there are some difficulties which limits
using the server side options. This can include limitations on what can be done
on the cloud hosting environment or even lack of access to the domain registrar
records. For those cases, we can detect the current protocol and redirect the
traffic using client-side JavaScript code.
Let us review an approach by looking at this small snippet.
if (location.host.indexOf("localhost") < 0 && location.protocol.toLowerCase() !== "https:") { const url = `https://${location.host}`; location.replace(url); } |
This code snippet uses the location interface to
validate the host name and protocol. If the protocol being used is not under a
secured channel (HTTPS), it replaces the current location, essentially
redirects, to the same host name, but it forces the secured channel.
Location Interface
The location interface is available globally and accessible
via JavaScript. When using it, we could either use window.location or just
location. It represents the location (URL, internet address) with all the
relevant information that is visible on the browser address bar. This includes
the host name and protocol information.
Host Name
The host name contains the current address or domain
including port number. We need this
information to check that we are not running on localhost which is the case
when we are running on development mode. We just want this rule to be enforced on
production environments.
Protocol
The protocol indicates if we are using HTTP or HTTPS which
is really what we are interested in finding out. We check that property, and If
it does not match the secured channel, we compose a new address using the
secured protocol and the host information. Once we have the information, we are ready to
execute a redirect.
Location Replace
With the new address information, we use location.replace to
essentially redirect to a new location under the HTTPS protocol. It is
important to use the replace method because we do not want to save the
unsecured visit to our app in the session history. By using replace, we prevent
the user from going back to that page via the back button. Now that we have the
approach, where do we add this code?
Where to Place the Snippet
The snippet should run at the very start of the application
bootstrapping process. Depending on the
application and framework being used (Angular, React, Vue etc.), we
could choose to place this on the App.js file, but in most cases, we would prefer
not to load our application instance yet and perform the redirect eagerly. For
those cases, just include this file as a script reference on the main/index
HTML page before loading the application code. Since JavaScript is single-threaded,
the snippet executes first and forces the browsers to load the new secured
location.
<head> <meta http-equiv="Content-Security-Policy"
content="upgrade-insecure-requests"> </head> <body> <div id="root"></div> <script src="/js/redirect.js"></script>
<script src="/js/app-bundle.js"></script> </body> |
Content Security Policy (CSP)
We should also consider that by forcing the secured channel for our application, we should make sure that all the content (images, CSS) be requested via the secured channel. To make sure this is done, we add the upgrade-insecure-requests policy as a meta tag in our page. This directive is evaluated to prevent the mixed-content warnings or even blocking due to a block-all-mixed-content policy enforce by browsers.
The solution to redirect HTTP to HTTPS from JavaScript is
very simple but understanding the security policy implications on why we need
to use a secured channel is a bit more complex. When evaluating that we need to
redirect the requests, we need to consider other security concerns and validate
that the redirect provides the intended results for the overall user experience.
Thanks for reading.