Password Protect a Static Website

17 Mar, 2021
Static websites are on rising again, In the early days of Internet HTML, CSS with some JavaScript is all the website, since then a number of Backend Frameworks like Django, Larvel, Ruby on Ralis have been developed along with looks like WordPress which now powers one-third of websites have been also gained popularity. Website Builders are also exploded so that anyone can have webpages whether they have technical skills or not. 
The development of all these new technologies also gave new security challenges. Poorly coded Authentication Backends, Passwords Reuse, Limited usage of Multi-Factor Authentication to outdated WordPress plugins, vulnerable JavaScript libraries, and unreliable hosting providers made Security a major aspect of the web. As developers always tend to solve existing problems to create new ones to solve in the future, Most of the developers went back to old good static websites but in a different manner.
JAM stands for JavaScript API’s and Markup. The term was coined by Mathias Biilmann founder of Netlify(A popular JAMstack host also pioneer of JAMstack). In this word, “JAM stack is a modern website architecture based on Client-Side JavaScript, reusable API’s and prebuilt Markup”. 
JavaScript provides interactability and Dynamic nature for the website
API’s helps to add some Server Side abilities securely
Markup helps to generate a website from source files such as markdown files, HTML templates, and CSS using a Static Site Generator like Jekyll, Gatsby, Hugo, and more
The most popular reasons for adaptation of JAMstack by developers is
Faster performance because there is no server-side rendering and most of the HTML already pre-built, Webpages load faster using CDN
Since there is no server to process it itself makes webpages More Secure
Less expensive than normal websites, most of the Static Hosting providers like Netlify, Vercel, Render, GitHub Pages, GitLab Pages, Cloudflare Pages have a free plan which is more than enough for most the developers
Scalability is easy because all it needs is to upgrade the bandwidth we are paying
But one of the most useful we generally miss while using Static Websites is password protection while many providers offer password protection it generally comes with a price but again we are developers we always try to find a way out. Static websites include JavaScript we will also use a JavaScript library Staticrypt by Robinmoisson to protect our static website.
This article requires nodejs and npm to be installed on your computer, you can learn more about it from Installation of Node.js on Linux and Installation of Node.js on Windows
Installing staticrypt:
StatiCrypt generates a static, password-protected page using AES -256 by utilizing a crypto-js library that can be decrypted in-browser you can upload the encrypted page as a normal file in your website and when the file is requested the JavaScript will prompt users for a password, decrypt the page and load your HTML.
Open your PowerShell or terminal and install staticrypt using npm
npm -g install staticrypt
For this article, I have taken an HTML template, in general, the website without password protection loads normally like below
index.html
<!DOCTYPE html><html lang="en">  <head>    <meta charset="utf-8">    <meta name="viewport"           content="width=device-width,                   initial-scale=1.0">    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css"           rel="stylesheet"           integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl"           crossorigin="anonymous">    <title>Password Protect Site using staticrypt</title></head>  <body class="text-center">    <div class="jumbotron text-center">        <h1>Welcome to GeeksForGeeks</h1>    </div>    <div class="card-body">        <h4 class="h4 card-title">            This article explains a simple technique             to password protect static websites        </h4>      </div>    <div class="jumbotron text-center">        <h6 class="h6 card-text">Thank You for Reading</h6>    </div></body>  </html>
Without Password Protection
Now go into your project directory and open terminal from the directory and type in the below command
staticrypt index.html geeksforgeeks -o index.html
The command is as follows
staticrypt is the name of the library
index.html is the index file of our website, the file we need to encrypt
geeksforgeeks is the password for the website, you can use any password you want
-o index.html is a way of telling to name the output file as index.html
As soon as we run the above command we would be asked for a password while accessing the website
password prompt
As soon as we give the right password we will be given access to that page
If you don’t want the default password template to create your own HTML form and add the following JavaScript.
Javascript
var keySize = 256;var iterations = 1000;function access(protectedText, pass) {    var salt = CryptoJS.enc.Hex.parse(protectedText.substr(0, 32));    var iv = CryptoJS.enc.Hex.parse(protectedText.substr(32, 32));    var protected = protectedText.substring(64);      var key = CryptoJS.PBKDF2(pass, salt, {        keySize: keySize / 32,        iterations: iterations,    });      var decrypted = CryptoJS.AES.decrypt(protected, key, {        iv: iv,        padding: CryptoJS.pad.Pkcs7,        mode: CryptoJS.mode.CBC,    }).toString(CryptoJS.enc.Utf8);    return decrypted;}  document.getElementById(  "static-pass-form").addEventListener("submit", function (e) {    e.preventDefault();      var passphrase = document.getElementById("static-pass").value,        // Add encrypt string of the Passphrase        protectedText ="Encrypt Passphrase",        protectedHMAC = protectedText.substring(0, 64),        protectedHTML = protectedText.substring(64),        decryptedHMAC = CryptoJS.HmacSHA256(          protectedHTML, CryptoJS.SHA256(            passphrase).toString()).toString();    // If passphrase is wrong    if (decryptedHMAC !== protectedHMAC) {        alert("Bad passphrase!");        return;    }      var plainHTML = access(protectedHTML, passphrase);      document.write(plainHTML);    document.close();});
Replace the protectedText value with the value of your HTML, You can get the HTML value using this online tool. The full custom HTML template code is below
index.html
<!DOCTYPE html><html lang="en">  <head>    <meta charset="utf-8">    <meta name="viewport"           content="width=device-width, initial-scale=1.0">    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css"           rel="stylesheet"           integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl"           crossorigin="anonymous">    <title>Password Protect Site using staticrypt</title>    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"             integrity="sha384-lp4k1VRKPU9eBnPePjnJ9M2RF3i7PC30gXs70+elCVfgwLwx1tv5+ctxdtwxqZa7"             crossorigin="anonymous"></script></head>  <body class="text-center">    <form id="static-pass-form">        <div class="mb-3">            <label for="password"                    class="form-label">Password</label>            <input id="static-pass"                   type="password"                    class="form-control"                   id="Password"                   aria-describedby="PasswordHelp">            <div id="PasswordHelp"                  class="form-text">                 You need Password to access the page.                </div>        </div>        <input type="submit"                class="btn btn-primary"               value="Access" />    </form>    <script>        var keySize = 256;        var iterations = 1000;          function access(protectedText, pass) {            var salt = CryptoJS.enc.Hex.parse(protectedText.substr(0, 32));            var iv = CryptoJS.enc.Hex.parse(protectedText.substr(32, 32))            var protected = protectedText.substring(64);              var key = CryptoJS.PBKDF2(pass, salt, {                keySize: keySize / 32,                iterations: iterations            });              var decrypted = CryptoJS.AES.decrypt(protected, key, {                iv: iv,                padding: CryptoJS.pad.Pkcs7,                mode: CryptoJS.mode.CBC            }).toString(CryptoJS.enc.Utf8);            return decrypted;        }          document.getElementById(            'static-pass-form').addEventListener('submit', function(e) {            e.preventDefault();              var passphrase = document.getElementById('static-pass').value,                protectedText = "Encrypt Passphrase",                protectedHMAC = protectedText.substring(0, 64),                protectedHTML = protectedText.substring(64),                decryptedHMAC = CryptoJS.HmacSHA256(                    protectedHTML, CryptoJS.SHA256(                        passphrase).toString()).toString();              if (decryptedHMAC !== protectedHMAC) {                alert('Bad passphrase!');                return;            }              var plainHTML = access(protectedHTML, passphrase);              document.write(plainHTML);            document.close();        });    </script></body>  </html>
custom template
If you use a default template or custom template, you will get your original HTML if you enter the correct password
Decrypted page
GBlog
JavaScript
Node.js
TechTips
Web Technologies
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.