[HN Gopher] Password protect a static HTML page
       ___________________________________________________________________
        
       Password protect a static HTML page
        
       Author : mooreds
       Score  : 246 points
       Date   : 2023-02-18 17:44 UTC (5 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | Karellen wrote:
       | Or... http authentication.
        
         | edent wrote:
         | How do you use that on something like GitHub pages?
        
           | marginalia_nu wrote:
           | Turns out when you give up the work of hosting your up stuff,
           | you also give up some of the benefits from doing so.
        
             | forrestthewoods wrote:
             | Which is why a project that returns some of those benefits
             | is genuinely cool and useful.
        
               | johannes1234321 wrote:
               | And even can give benefits by storing it encrypted at
               | rest.
        
         | Dma54rhs wrote:
         | You can email or hand out physical copies on usb would be one
         | use case where server auth can't compete.
        
           | Karellen wrote:
           | Aren't existing encryption tools more flexible for sending
           | out copies via those methods? e.g. by making more cipher
           | suites available? Or by allowing you to encrypt with the
           | intended recipients' public keys, so you don't need to worry
           | about distributing the passphrase securely? And might allow
           | better integration with password managers, as the OS would
           | recognise the files as being encrypted?
        
             | layer8 wrote:
             | Supposedly browsers are more ubiquitous on the recipient
             | side than whatever other tools you might use.
        
               | Karellen wrote:
               | I was thinking of editing my comment to add "Or be able
               | to support filetypes other than HTML", but I suppose in
               | our glorious "everything is the browser" future,
               | filetypes other than HTML are as anachronistic as 8"
               | floppy disks.
               | 
               | Sigh.
        
               | layer8 wrote:
               | FWIW, you can use data URLs to include any type of file
               | in your HTML, and with <a download='filename'
               | href='data:...'> browsers will allow you to save the
               | file.
        
       | ipaddr wrote:
       | Use apache to serve your page and htpasswd to provide basic
       | authentication. Easy 1994 answer
        
         | mik1998 wrote:
         | Also NGINX auth basic option. I use it on my personal website.
         | 
         | https://docs.nginx.com/nginx/admin-guide/security-controls/c...
        
         | Gordonjcp wrote:
         | I thought that too, but this appears like it works to password
         | protect an html file that's *not* being served off a server.
         | This ought to work with a file on disk too.
        
           | userbinator wrote:
           | The more general solution is to use a password-protected
           | archive.
        
       | fabiensanglard wrote:
       | A more lightweight solution would be to hash the password and
       | have a copy of that file at this url.
       | 
       | windows.location = hash(password);
        
         | hosteur wrote:
         | Wow I like that. So simple and elegant. Could be combined with
         | a username to produce unique urls per user.
        
           | pyrolistical wrote:
           | A miss configured http server that allows directory listing
           | would compromise everything.
           | 
           | Also now all intermediate things that have access to the
           | hashed url would suddenly have access to a secure piece of
           | information.
           | 
           | Don't be clever with security
        
             | cozzyd wrote:
             | You can always put an index.html to prevent that mistake.
        
         | pyrolistical wrote:
         | Their solution intends for the static file to be copied offline
        
         | pdq wrote:
         | Client side decryption has the benefit that no machine or
         | router in the middle can view or cache the decrypted page
         | without the password.
        
           | tptacek wrote:
           | You mean, unless they tamper with the Javascript to capture
           | the password (or the derived key).
        
             | dividuum wrote:
             | I designed a similar tool with that threat model in mind:
             | the resulting HTML/JS is as minimal as possible so it's
             | possible to inspect before entering the password. Of course
             | assumes safe browser and client machine..
             | https://github.com/dividuum/html-vault
        
         | madduci wrote:
         | A more lightweight solution would be to let the Webserver
         | (nginx, https, whatever) password-protect the site.
         | 
         | No JavaScript required a d highly efficient
        
           | fragmede wrote:
           | Requiring some sort of VM or container to run this webserver
           | on? Is it possible that's way more onerous than a static html
           | file which can be emailed around? Are you sure nginx is even
           | going to be around in, say, 15 years? (think password
           | protected PDF but in html and allowing for JavaScript.)
        
         | [deleted]
        
       | victorbjorklund wrote:
       | Wow. This is really cool. I wonder if it would be possible to
       | kind of build a site with personal pages etc for different user
       | each encrypted by their own password
       | 
       | Like domain.com/user1 and domain.com/user2 each are encrypted but
       | with their own passwords. So user 1 can only visit his own page
       | and not other users.
       | 
       | (I know there would be much easier to just do a traditional
       | webapp but as a concept it is super cool).
        
         | efrecon wrote:
         | I am using it in exactly that context and it is good enough for
         | the level of security I need to achieve. I understand this can
         | be brute forced, but this is a risk I am willing to take given
         | the level of "secrecy" of the content.
        
       | eduction wrote:
       | Hey look it's a "static" HTML file that decrypts itself using AES
       | 256 CBC. Sure, that sounds static and simple and good for the
       | web. What could go wrong.
       | 
       | Some obvious limitations:
       | 
       | -requires users to re-authenticate for every protected file on
       | your site
       | 
       | -assets loaded by the page not password protected
       | 
       | -uses a single password globally shared by everyone who wants to
       | read the doc
       | 
       | -archiving the page itself is useless unless you also archive the
       | password, which must be done out of band
       | 
       | -this doesn't compose or integrate with the web: none of the
       | common tools you would use to download, spider, archive, spindle,
       | mutilate web pages know how to deal with this
       | 
       | It's certainly one solution. The http basic auth built into every
       | popular webserver is another, with none of the above limitations.
       | But I guess that would require spending 5 minutes learning and
       | implementing some server config, and why do that when you can
       | further ruin the web by shoving yet more user hostile complexity
       | into client side JavaScript.
       | 
       | Sorry to sound bitter I just feel this is a really bad idea if
       | you think about it for any length of time.
        
         | dakiol wrote:
         | > The http basic auth built into every popular webserver is
         | another, with none of the above limitations.
         | 
         | The obvious advantage of OP's approach is that one doesn't need
         | to control the server that serves the HTML (e.g., static site
         | served via GitHub pages would be enough)
        
       | superkuh wrote:
       | [flagged]
        
         | tptacek wrote:
         | If that's wrong, so is the name of every "static site
         | generator". Also: please don't make the same point in two
         | separate top-level comments.
        
           | superkuh wrote:
           | A static site generator can be used to create an .html file
           | that's dependent on the user to execute a javscript web
           | application to show the content. That makes that generated
           | page dynamic. It doesn't change the nature of the static site
           | generator.
        
         | [deleted]
        
         | tantalor wrote:
         | The js is static too
        
         | minusf wrote:
         | funnily enough in certain circles "static pages" rather mean
         | "static on server side" but "dynamic on client side".
        
       | danShumway wrote:
       | Hah, this is another thing I've been thinking about recently :)
       | It's cool to see tools like this popping up.
       | 
       | An approach I've played around with, but never sat down to
       | actually build, was to use service workers to be able to encrypt
       | large sites -- the entire site would be encrypted locally from
       | the command line using libsodium's `crypto_secretbox_easy`[0],
       | and all of the data would be concatenated into a series of padded
       | files to try and somewhat hide the number of files/size of the
       | site. That key would be merged with a lookup table that would
       | also be encrypted with a separate key, that would be stuck in the
       | url hash. Then once the site was decrypted (ie, the secretbox key
       | was sent to the service worker from the url) the service worker
       | would intercept any requests the the front-end made and decrypt
       | the original map that would tell it which file chunks to fetch,
       | and then it would decrypt them on the fly and cache them for the
       | duration of the session. Whenever you updated the site, the files
       | would be re-encrypted with another key, but the "user facing" key
       | in the URL would stay the same.
       | 
       | The linked project (and other projects people have linked) are a
       | lot more portable, but I was thinking less about being able to
       | have a single file that I carried around and more about being
       | able to put up a full website where I could have something
       | approximating user accounts (ie, possibly having multiple lookup
       | tables that could be decrypted separately per-user), and where I
       | could build full-featured projects that could fetch their own
       | resources.
       | 
       | But, I haven't ever gotten around to actually building it, I only
       | ever built some tests to make sure that it would technically
       | work, and I got nervous about rolling my own solution even though
       | I was just going through the libsodium APIs.
       | 
       | ----
       | 
       | [0]: I've seen a couple of people recommend using Web Crypto
       | instead, which I've avoided because I thought libsodium ported to
       | the browser was harder to shoot myself in the foot with; is that
       | a bad instinct?
        
       | CM30 wrote:
       | Oh neat, this is a neat concept. Always wanted a secure way to
       | password protect a page without server side coding, and this is
       | definitely the closest we've gotten in years.
       | 
       | Not sure I'd trust it myself, but it definitely seems like a good
       | option for those with limited hosting options (like GitHub pages
       | or Neocities) and a need to secure some content.
        
       | snake_doc wrote:
       | Similar to portable-secret? https://github.com/mprimi/portable-
       | secret
        
       | realPubkey wrote:
       | Should have used the WebCrypto API instead of the crypto-js npm
       | package. https://developer.mozilla.org/en-
       | US/docs/Web/API/Web_Crypto_...
        
         | fifafu wrote:
         | WebCrypto only works in secure contexts (https), which is a
         | significant limitation for some use cases. But I agree it
         | should be an option.
        
         | iamben wrote:
         | I spent some time Googling this about 6 months ago. Lots of
         | tutorials on Crypto-js, not so many (and almost zero "here's a
         | super simple implementation") for WebCrypto API. I can
         | understand if this is a hobby project why you'd lean into one
         | rather than the other, I probably would have done the same.
        
           | cgb223 wrote:
           | Sounds like a golden opportunity for someone with a developer
           | blog to make useful content
        
           | trusz wrote:
           | Not going to pretend that I know what the most of the stuff
           | mean, or if it is even safe enough, but I've followed the MDN
           | articles and put together this TypeScript snippet [1]. Maybe
           | somebody could comment on it?
           | 
           | Also sorry for the long link. Is there any accepted way to
           | post a shorted URL?
           | 
           | Edit: added a corrected version [2]
           | 
           | [1]: https://www.typescriptlang.org/play?#code/DYUwLgBAbiDGYH
           | sBOE...
           | 
           | [2]: https://www.typescriptlang.org/play?#code/FAiGGcE8DsGMAI
           | BmBX...
        
             | tptacek wrote:
             | If you call "encrypt" more than once in that code, you'll
             | leak the authentication key. Every invocation of GCM
             | encryption needs a unique nonce. Cryptography nerds will
             | chastise you for using a random nonce (there theoretically
             | isn't enough room in the GCM nonce space to safely encrypt
             | large numbers of message with random nonces), but the
             | alternative (using a counter) is even more hazardous. This
             | problem motivates a lot of people to use other AEADs like
             | XChapoly, which has an extended nonce space that safely
             | admits random nonces. Isn't cryptography fun?
        
               | ThePhysicist wrote:
               | It's still considered safe to call AES-GCM with a single
               | key and a randomly generated nonce 2^32 times [1], most
               | practical systems don't come anywhere near this limit.
               | And there's AES-GCM-SIV that solves nonce reuse (mostly),
               | though it's not available in the Web Cryptography API at
               | the moment.
               | 
               | 1: https://csrc.nist.gov/csrc/media/Projects/crypto-
               | publication...
        
               | tptacek wrote:
               | I don't personally care, and probably wouldn't even
               | sev:info a random GCM nonce in an assessment, but I would
               | also choose extended-nonce Chapoly in preference to GCM
               | in part because of this issue.
        
               | majou wrote:
               | From what I shallowly researched; GCM's nonce seems
               | limited to 12 bytes by convention only. That nonce reuse
               | is so fatal seems absurd to me.
               | 
               | Would "salting" the key safely tackle the problem?
               | 
               | Put explicitly;                 send <- nonce || salt ||
               | ciphertext       recv -> decrypt(ciphertext, nonce,
               | pbkdf(pass) || salt)
               | 
               | [edit: apply salt outside of the kdf]
        
               | tptacek wrote:
               | As I remember it, the balance of the bytes in the AES
               | block are used for the counter. At any rate, the
               | convention is essentially universal.
        
               | majou wrote:
               | Sounds above my (current) head.
               | 
               | Here I thought GCM was some modern foolproof/footgunless
               | design.
        
               | tptacek wrote:
               | It is sort of infamously footgunny.
        
               | trusz wrote:
               | Oh yes! Thank you for the feedback. I've added a new
               | version where the `iv` and the `salt` is random. Maybe a
               | followup question: Because you need both the `iv` and
               | `salt` to decrypt the message is it ok in an E2E scenario
               | to send all three: `iv`, `salt` and the encrypted
               | message?
        
               | tptacek wrote:
               | I didn't look to see what "salt" means in your design,
               | but the idiom for using GCM in message encryption is to
               | send ciphertexts that take the form `nonce ||
               | ciphertext`, and to decrypt by reading the nonce off the
               | front of the message.
        
         | dividuum wrote:
         | Mine does: https://github.com/dividuum/html-vault/
        
         | paulpauper wrote:
         | What is the major difference? Isn't crypto-js still secure?
        
           | Xeoncross wrote:
           | One is a Javascript package, the other is a browser library
           | following a spec that is implemented by all the major browser
           | companies.
           | 
           | Web Crypto is faster and has many more devs working in the
           | different implementations between all the companies and
           | doesn't require any includes.
        
           | lucideer wrote:
           | It might be. Whereas the native lib should be.
           | 
           | Just levels of trust. I'd happily use the former if the
           | latter didn't exist.
        
           | irrational wrote:
           | Why use a library (thus incurring the need for the user to
           | download more JS) instead of using what is already in their
           | browser?
        
           | tptacek wrote:
           | I don't know what "secure" means. Is their implementation of
           | OFB correct? Probably. But using OFB mode is itself a
           | problem. From what I can see, crypto-js implements no
           | authenticated modes, and exposes all sorts of crufty old
           | things nobody should be using. The parent comment suggesting
           | WebCrypto is correct in this case. Avoid crypto-js.
        
         | [deleted]
        
       | bitexploder wrote:
       | The use case for a document like this is a little different from
       | .htaccess. This is something you can share, email, host, etc and
       | have some security in transit and at rest. Yes, .htaccess
       | password protects on the web server, but that is one specific use
       | case and requires a lot of machinery and specific environment.
       | JavaScript is everywhere. And this is a static HTML document in
       | the sense that there is no server side rendering.
        
         | ipaddr wrote:
         | Why not use a password protected word document if those are
         | your use-cases?
        
           | creata wrote:
           | You definitely could. But I think there are more computers
           | with web browsers than there are computers that can read
           | encrypted Microsoft Word documents.
        
       | [deleted]
        
       | adamcharnock wrote:
       | I saw a super simple example of this back in the 90s when I was
       | first leaning web development (was in Web Development for Dummies
       | or some such).
       | 
       | The page prompted the user for the password, and then used the
       | password to generate the URL for the hidden page and redirected
       | the user there. Of course this wasn't over HTTPS, and you got a
       | 404 if you entered the wrong password, but it was still a neat
       | hobbyist trick for the era. I think the author even wagered that
       | readers couldn't defeat it.
        
         | aflag wrote:
         | That was very popular back then. Besides the 404, it has the
         | side effect that if that URL leaked, then your password system
         | broke. With this implementation leaking the page is not a big
         | deal (assuming you're not using it to store state secrets or
         | anything like that)
        
       | VincentEvans wrote:
       | Can someone explain a bit more how "remember me" works? If
       | symmetric encryption requires a "key" to decrypt - one might
       | expect that you will need to store that key to auto-decrypt. But
       | here it claims that the key is stored salted and hashed. But to
       | auto-decrypt - you need to reverse that salt and hash because you
       | need that key back. How would that work?
        
       | worldsavior wrote:
       | The title is a bit misleading. The title implies ONLY HTML when
       | it uses some JS. I guess it's not possible (in anyway I know)
       | without some JS, but still.
        
       | VoidWhisperer wrote:
       | The downside to this method is that since the resulting
       | cryptographic hash and salt have to be in the resulting file, so
       | there is nothing stopping someone from pulling the hash/salt out
       | and bruteforcing it locally (as opposed to being able to
       | ratelimit login attempts on a server) if they are so inclined and
       | have the required resources.. which may not be that much in the
       | way of resources as the tool uses 1000 iterations of PBKDF2[1].
       | This is magnitudes lower than what OWASP recommends[2].
       | 
       | I wouldn't personally put anything you want secure behind this.
       | 
       | [1]:
       | https://github.com/robinmoisson/staticrypt/blob/5dac008ba644...
       | [2]:
       | https://cheatsheetseries.owasp.org/cheatsheets/Password_Stor...
        
         | 411111111111111 wrote:
         | The linked readme agrees with that
         | https://github.com/robinmoisson/staticrypt#is-it-secure
        
         | [deleted]
        
         | dakiol wrote:
         | Is it a downside if the password is a 100 characters-long
         | string?
        
         | [deleted]
        
         | tialaramex wrote:
         | Right but all that's happening here is stretching. So the
         | difference only matters in the middle. Regardless of the
         | strategy bad guys will guess "1234" or "sesame" (too easy) and
         | they won't guess a random 128-bit key I just generated with my
         | hexadecimal dice (impossible). This weakness only means it's
         | easier than expected to guess your password is "suckitelon" or
         | "GoCowboys1978" or whatever
         | 
         | We put a lot of effort into teaching people to do better
         | stretching, but it feels like the result was they put even
         | _more_ passwords on things, rather than using the breathing
         | room to get off passwords. If your project for 2023 is  "Use a
         | fancier password hash" instead of "Get rid of passwords" you
         | are Doing It Wrong(tm).
         | 
         | If you wanted to do something like this seriously, consider
         | hmac-secret extension to FIDO, which means Security Keys (so
         | the things you'd use to log in to say Google or Facebook) can
         | present an arbitrary always-identical secret value which would
         | be more than adequate to secure such a thing unlike a human
         | memorable password. Today hmac-secret is mostly used to
         | authenticate to an off-line laptop PC or similar.
        
           | ipaddr wrote:
           | Your 128 key is difficult for users to enter manually.
        
           | d-z-m wrote:
           | Last I heard WebAuthn didn't have access to hmac-secret or
           | prf outside of a Chrome canary. Has this changed recently?
        
       | maxlaumeister wrote:
       | I'm going to plug my project PageCrypt here too, which predates
       | StatiCrypt, has a web UI that's good for one-off page encryption,
       | and _does_ use the WebCrypto API.
       | 
       | https://github.com/MaxLaumeister/pagecrypt
       | 
       | https://www.maxlaumeister.com/pagecrypt/
        
       | charles_f wrote:
       | Shameless plug, I did something similar in a markdown processor
       | (which processes any folder with some markdown into an html
       | website). You can either protect some of the pages, or the entire
       | thing
       | 
       | https://github.com/cfe84/plaf
        
       | Retr0id wrote:
       | For anyone else wondering what the KDF is, it appears to be
       | PBKDF2 with 1000 iterations:
       | 
       | https://github.com/robinmoisson/staticrypt/blob/5dac008ba644...
        
         | benatkin wrote:
         | Here's one w/ 100_000. Perhaps it's missing a couple zeroes.
         | 
         | https://github.com/yjs/y-webrtc/blob/master/src/crypto.js#L2...
        
       | superkuh wrote:
       | If you have to run javascript it is not a static page anymore.
       | I've seen a lot of this particularly weird overloading of "static
       | HTML" lately. Static HTML, or static webpage, is meant to
       | describe the experience from the person who is trying to look at
       | the page. It does not describe the experience of the dev.
       | 
       | Using a dynamic script or application to generate a static html
       | page that requires no JS execution is a static page.
       | 
       | Using a static HTML page and then hiding it behind javascript
       | execution is explicitly not a static HTML page.
       | 
       | Use .htaccess. And if you can't, reconsider the choices you made
       | that restrict your abilities so significantly.
        
         | cubefox wrote:
         | I would call any server side or client side code which alters
         | the HTML non-static. A static HTML page is just an HTML file
         | which is stored on the server and displayed as-is in the
         | browser.
        
           | superkuh wrote:
           | Exactly. I don't know where the confusion is, but I'm saying
           | that it doesn't matter how the page is generated. It is sent
           | to the website visitor as just HTML. When the user views it
           | it is all there, just html. No changes.
           | 
           | For example, I have a perl script that generates a set of
           | .html files every night to show new additions to my library.
           | They are static .html files on disk and never modified before
           | the user views them. Just because a perl script (not
           | connected to the web server in any way) made it does not
           | "taint" the HTML so it is not static. The program, or the
           | person, that wrote the HTML does not matter. All that matters
           | is that it's just static unchanging HTML.
        
             | drowsspa wrote:
             | Everyone is allowed to give their own meaning to words, but
             | you can't expect to just change a widely agreed meaning to
             | match it. "Static" means it is just a set of files. Not
             | that the page is stationary. Do you think that a blink tag
             | in a HTML page makes it non-static? A hover effect? An
             | :after pseudoelement in CSS?
             | 
             | If your perl script is saving the HTML to the disk, then
             | yeah, your website is static. If it's generating HTML on
             | the fly, it's dynamic. That's the widely agreed upon
             | meaning, and that's it.
        
           | scarface74 wrote:
           | That's not a generally accepted as the definition of a static
           | page.
           | 
           | https://docs.aws.amazon.com/AmazonS3/latest/userguide/Websit.
           | ..
           | 
           | > You can use Amazon S3 to host a static website. On a static
           | website, individual webpages include static content. They
           | might also contain client-side scripts.
           | 
           | By contrast, a dynamic website relies on server-side
           | processing, including server-side scripts, such as PHP, JSP,
           | or ASP.NET. Amazon S3 does not support server-side scripting,
           | but AWS has other resources for hosting dynamic websites. To
           | learn more about website hosting on AWS, see Web Hosting.
        
         | mtlynch wrote:
         | > _If you have to run javascript it is not a static page
         | anymore. I 've seen a lot of this particularly weird
         | overloading of "static HTML" lately. Static HTML, or static
         | webpage, is meant to describe the experience from the person
         | who is trying to look at the page. It does not describe the
         | experience of the dev._
         | 
         | I don't think this has been the common meaning of "static page"
         | for at least 10 years.
         | 
         | From Wikipedia [0]:
         | 
         | > _A static web page (sometimes called a flat page or a
         | stationary page) is a web page that is delivered to the user 's
         | web browser exactly as stored_
         | 
         | Static refers to the fact the files are served without any
         | application-level processing on the server side beyond simple
         | file serving. A page can depend on CSS/JS/WASM and still be a
         | static page.
         | 
         | [0] https://en.wikipedia.org/wiki/Static_web_page
        
           | RobotToaster wrote:
           | OP said static _HTML_ page though, that very much means
           | something only using static as opposed to dynamic HTML.
           | 
           | https://en.wikipedia.org/wiki/Dynamic_HTML
           | 
           | "DHTML allows scripting languages to change variables in a
           | web page's definition language, which in turn affects the
           | look and function of otherwise "static" HTML page content
           | after the page has been fully loaded and during the viewing
           | process. Thus the dynamic characteristic of DHTML is the way
           | it functions while a page is viewed, not in its ability to
           | generate a unique page with each page load.
           | 
           | By contrast, a dynamic web page is a broader concept,
           | covering any web page generated differently for each user,
           | load occurrence, or specific variable values. This includes
           | pages created by client-side scripting and ones created by
           | server-side scripting (such as PHP, Python, JSP or ASP.NET)
           | where the web server generates content before sending it to
           | the client."
        
           | superkuh wrote:
           | >A static web page (sometimes called a flat page or a
           | stationary page) is a web page that is delivered to the
           | user's web browser exactly as stored"
           | 
           | Right. "exactly as stored" It doesn't matter who or what
           | wrote the HTML. I could do it by hand or maybe use a WYSIWYG
           | editor to make it or maybe it's generated by a script. The
           | point is that there's an html file sitting on disk and the
           | server delivers it without modification and it's viewable in
           | the browser as it. It's just the webserver sending the
           | contents of the file.
           | 
           | Whereas this "Password protected a static HTML page" cannot
           | be viewed in the browser without a "web application", the
           | javascript, dynamically changing the file. It's pretty clear
           | cut. So it fails the test of the very link you posted:
           | 
           | >in contrast to dynamic web pages which are generated by a
           | web application
        
             | [deleted]
        
             | Bytewave81 wrote:
             | It's really not "clear cut." By the definition which you
             | agree with, an HTML file containing JavaScript is served to
             | the client without modification, and is viewable in any
             | modern browser with a functioning JavaScript engine. The
             | "web application" in reference is a server-sided
             | application which controls and renders the content, as can
             | be assumed based on context from the rest of that page.
             | Namely:
             | 
             | > Any personalization or interactivity has to run client-
             | side, which is restricting.
        
             | mtlynch wrote:
             | >>A static web page (sometimes called a flat page or a
             | stationary page) is a web page that is delivered to the
             | user's web browser exactly as stored"
             | 
             | >Right. "exactly as stored" It doesn't matter who or what
             | wrote the HTML. I could do it by hand or maybe use a
             | WYSIWYG editor to make it or maybe it's generated by a
             | script.
             | 
             | Yes, agree.
             | 
             | >The point is that there's an html file sitting on disk and
             | the server delivers it without modification and it's
             | viewable in the browser as it.
             | 
             | No, I don't think that's the widely understood
             | interpretation of "static web page."
             | 
             | Even the definition you agree with just says the file is
             | _delivered_ as-is. It says nothing about how the browser
             | renders the page.
        
           | snowwrestler wrote:
           | The title says "static HTML page" not "static web page".
           | 
           | JavaScript is not HTML.
        
             | RobotToaster wrote:
             | Neither is CSS, if you want to be pedantic.
        
         | matsemann wrote:
         | I think your definition of a static web page is different from
         | the common one?
         | 
         | In my head, a static page is something that's served verbatim,
         | without some backend generating it or inserting things into a
         | template.
         | 
         | Wikipedia seems to agree with that view:
         | https://en.wikipedia.org/wiki/Static_web_page
        
           | superkuh wrote:
           | That's exactly what I said. It doesn't matter if I wrote the
           | HTML by hand or I had a perl, or bash, or compiled c program
           | make it. It's just an HTML file.
        
             | [deleted]
        
             | meghan_rain wrote:
             | Lol no. If you HTML is generated, it's by definition not
             | static anymore.
             | 
             | Otherwise, all of the React server side rendering is static
             | HTML.
        
               | superkuh wrote:
               | Oh, so when I make an .html file in Dreamweaver WYSIWYG
               | HTML editor and save the .html file to my websever ~/www/
               | dir it is automatically not a static page anymore because
               | I used a program to generate it? This is a very wild and
               | weird interpretation of 'static site' that does not fit
               | with existing usage.
        
               | Kiro wrote:
               | You are the last person to have a say in that considering
               | your incorrect take that JS can't be static. You're
               | clearly misaligned with common usage of terms.
        
               | GeneralTspoon wrote:
               | No, because React is dynamically generating the HTML on
               | the fly.
               | 
               | If you pre-compile the HTML using something like Jekyll,
               | so that the webserver is just serving HTML files without
               | any dynamic/on-the-fly processing at request time, then
               | it's considered static.
        
               | matsemann wrote:
               | React server side rendering: most likely dynamic
               | 
               | React on the client side: static, as you still got the
               | same files served, how they dynamically alter the page
               | runtime doesn't count.
        
             | shawabawa3 wrote:
             | You're incorrect
             | 
             | CSS and JavaScript and images are also static, it doesn't
             | have to be just HTML
             | 
             | If you have a perl or bash or c backend generating html in
             | response to http requests it's not static
        
               | superkuh wrote:
               | You're assuming this is a backend. It is not. Do you
               | consider generating an HTML file in a WYSIWYG editor
               | like, say, "Dreamweaver" that outputs an .html no longer
               | static because it was made by a program? That's absurd.
        
             | vore wrote:
             | You can put client-side JavaScript fine in "just an HTML
             | file"?
        
             | [deleted]
        
             | mytailorisrich wrote:
             | It can be html, css, javascript, whatever.
             | 
             | 'Static' means it's only made of static files that can be
             | served by just a vanilla Web server (i.e. just by serving
             | static files).
        
             | swatcoder wrote:
             | HTML includes the content of style and script elements
             | (among many others) and the results of whatever they do.
             | 
             | The combination of _all_ of these direct a browser in how
             | to render a page.
             | 
             | Traditionally, a static site or static page is one whose
             | data can be delivered to the client directly as stored,
             | with no _server-side_ alterations or generation.
             | 
             | This is/was a meaningful distinction because a server that
             | can stream stored data is fundamentally much simpler than
             | one that executes programs. Such a server can run in
             | different contexts, be optimized in different ways, and
             | satisfies constraints that allow further optimizations
             | downstream.
        
         | creatable wrote:
         | This is nonsense semantics. Words and phrases change meaning
         | over time.
        
           | scarface74 wrote:
           | It didn't even "change meaning"
           | 
           | As far back as I remember (and I played with JavaScript when
           | it was first introduced in beta for Netscape), a "static web
           | page server" always meant that there was no backend server
           | generating pages on the fly.
        
         | Karellen wrote:
         | I think "static" and "dynamic" can reasonably be used to
         | describe both server-side and client-side behaviour, and I
         | don't think that the dual meaning is particularly new.
         | 
         | Yes, "Dynamic HTML" vs "Static HTML" to refer to JS-dependent
         | and JS-free pages respectively has been around since the dawn
         | of javascript, but my copy of the 1996 O'Reilly _CGI
         | Programming on the World Wide Web_ by Gundavaram contains
         | sentences like
         | 
         | "Virtual, or dynamic, document creation is at the heart of CGI"
         | (p.4)
         | 
         | "A common use for [server redirection] is to return a generic
         | document that contains static information. [...] Suppose you
         | have an HTML file ( _thanks.html_ ) like the one below, that
         | you want to display after the user fills out one of your forms:
         | [...] You could use the programs discussed earlier to return
         | static documents, but [...] it is much quicker and simpler to
         | [redirect with a "Location" header]." (pp.44-45)
         | 
         | ...without mentioning javascript anywhere.
        
         | Timon3 wrote:
         | You're interpreting the title as "a static HTML page with
         | password protection", but the way I understood it is
         | "statically hostable version of a static HTML page with
         | password protection", which seems to be exactly what this
         | implements. I'm probably biased because I would have frequently
         | had use for this, and all the paid offerings mention "private
         | hosting of static pages", but I feel you're a bit uncharitable
         | with your interpretation.
         | 
         | If you want to just have a free small private static page which
         | is easily updated by public CI offerings this is a great
         | solution, and the title transports this clearly.
        
         | [deleted]
        
         | pierrec wrote:
         | That is not correct. As long as the javascript is run on the
         | client-side, it's a static page. Static simply means the files
         | on the server are sent directly to the client. The client can
         | then do whatever they want with the files.
         | 
         | The expression "dynamic" was trending a decade or two ago to
         | vaguely refer to javascript+HTML5. It was never the opposite of
         | "static" in this domain.
        
         | dymk wrote:
         | Title is still accurate, the tool is for password protecting a
         | static HTML page. The page starts out as a static HTML page.
         | Then this tool generates something that has password protected
         | it.
        
         | voytec wrote:
         | > If you have to run javascript it is not a static page anymore
         | 
         | I understand static pages as files sent to a browser without
         | having to be generated server-side.
        
           | rwalle wrote:
           | Right. This concept has existed for decades, and people
           | should figure out what it actually means before complaining.
        
         | [deleted]
        
       | anurag wrote:
       | Pagecrypt does the same thing, but with the Web Crypto API. More
       | (including a sample repo) at https://render.com/blog/static-site-
       | auth-pagecrypt.
        
         | sowbug wrote:
         | Similar here: https://github.com/sowbug/quaid
         | 
         | It works with a GPG-encrypted file. I figured that was safer
         | than developing my own encryption format. As it is, any
         | vulnerability in the decryption process is equivalent to a
         | vulnerability in GPG.
        
       | [deleted]
        
       | Yenrabbit wrote:
       | Does anyone know of a way to do something like this but with
       | OAuth? E.g. log in with GitHub to view these docs.
        
         | denysvitali wrote:
         | I'd say it's not possible in pure HTML + JS (as in, encryption/
         | access control performed entirely there).
         | 
         | The solution (with a server) is:
         | https://oauth2-proxy.github.io/oauth2-proxy/
        
       | pier25 wrote:
       | Anyone remembers .htaccess files from Apache? Good times.
        
         | johannes1234321 wrote:
         | Those would be quite nice, if web browsers were good HTTP
         | clients.
         | 
         | The user experience with basic auth is not so good. The dialogs
         | give little way to customize and providing information for
         | user. No support for logout or any form of password changes.
        
           | marginalia_nu wrote:
           | Isn't that sort of a feature? Customizable HTTP auth dialogs
           | are a security liability, as they blur the line between
           | content and browser.
        
             | johannes1234321 wrote:
             | Yes and no. There is some part of it which helps to
             | identify where you are connecting to. Meanwhile those
             | dialogs aren't modal anymore, which allows access to https
             | certificate info, but it is still complicated to provide
             | trust for average users.
        
           | tqkxzugoaupvwqr wrote:
           | Logout is possible: The server has to send http status 401 if
           | I recall correctly. The browser treats this as logout.
        
             | johannes1234321 wrote:
             | This requires some server side handling. The web browser
             | could have a logout button so I can end my session.
             | Probably that should be combined with a configured target
             | page for the user.
             | 
             | And well, my experience there is about 20 years old, but
             | back then sending 401 wasn't enough. You had to send a
             | different auth request, which then would pop up a new
             | password dialog first. Indoubt 401 is enough today as well,
             | as the browser can't distinguish whether a specific
             | resource is restricted or whether the whole session should
             | be invalidated.
        
       | eduction wrote:
       | Take one shot if you thought this was going to be about .htaccess
       | and a second if you're confused why it wasn't.
        
         | ab8 wrote:
         | This solution has no street cred
        
       | Xeoncross wrote:
       | I'm not a cryptographer, but I'm pretty sure that CBC
       | (https://github.com/robinmoisson/staticrypt/blob/main/lib/cry...)
       | should be replaced with GCM (https://developer.mozilla.org/en-
       | US/docs/Web/API/SubtleCrypt...) since this is not a stream.
       | 
       | https://security.stackexchange.com/questions/184305/why-woul...
       | 
       | (also, use the built-in WebCrypto API instead of the crypto-js
       | package)
        
         | dragontamer wrote:
         | CBC is far easier to implement than GCM mode.
         | 
         | I bet that most programmers cannot implement a Galois Field in
         | Javascript. Meanwhile, CBC is just "encrypt then xor".
        
           | tptacek wrote:
           | Nobody implements GCM themselves; they get it from a library.
           | CBC, implemented the way you're describing, is almost always
           | insecure.
        
             | dragontamer wrote:
             | And the library they use doesn't have GCM mode.
             | 
             | So now what?
             | 
             | https://cryptojs.gitbook.io/docs/
             | 
             | Because CBC mode is easier to implement, you'll find it in
             | far more libraries. And honestly, if your underlying block-
             | cipher is secure (that's the hard part: where your side-
             | channels all exist), then CBC mode is really the easy part
             | and can be safely implemented yourself. It really is that
             | simple.
             | 
             | -----------------
             | 
             | CBC doesn't have authentication. So add on an HMAC. Done.
             | It takes up a few more bytes but that's not a big deal
             | these days.
        
               | tptacek wrote:
               | So use WebCrypto, instead of the cabinet of curiosities
               | that is crypto-js. (Or, better yet, don't do stuff like
               | this at all, because a browser window is simply an awful
               | setting for serious cryptography).
        
               | fifafu wrote:
               | WebCrypto only works in secure contexts which is a
               | significant limitation (https origins only)
        
               | tptacek wrote:
               | Your next best bet might be sjcl.
        
               | d-z-m wrote:
               | If you're talking about sending these files around via
               | email/messenger, most browsers treat localhost as a
               | secure context, so this doesn't seem like _that_
               | significant of a limitation.
               | 
               | If you are serving out an encrypted HTML page insecurely,
               | your users are already hosed, because someone on the path
               | could inject a script that sends the password to
               | evil[.]com when they type it in.
        
           | password11 wrote:
           | > _CBC is far easier to implement..._
           | 
           | Never implement your own cryptography.
           | 
           | Edit:
           | 
           | In fact an incorrect implementation _of CBC mode_ famously
           | caused a vulnerability in Microsoft 's ASP.NET in 2010
           | (https://learn.microsoft.com/en-us/security-
           | updates/securityb...). The margin for error is small and even
           | subtle mistakes or incorrect design can cripple security.
           | Even Microsoft got it wrong once (although they handled
           | remediation very well).
        
             | dragontamer wrote:
             | Or... you can have a more nuanced viewpoint and note that
             | CBC is really, really, really easy to implement, and
             | _really_ doesn't fall into that category of discussion.
             | 
             | The reason you don't implement your own block ciphers is
             | because side-channel attacks are damn near impossible for
             | normal programmers to understand. Especially timing
             | attacks.
             | 
             | But block-modes of operation? Some of them are really easy.
             | I've ever heard of a bad implementation of CBC causing a
             | security bug.
             | 
             | -------
             | 
             | I'd say you shouldn't implement your own GCM mode. GCM is
             | quite complex, and the Galois Field's authentication bits
             | could be side-channeled if you don't know what you're
             | doing.
             | 
             | CBC? Where's the flaw? Its so stupid simple I don't think
             | that even a novice would make a critical error.
        
               | tptacek wrote:
               | You keep saying "the Galois Field" as if that was a
               | thing. It's GCM. The components of GCM are CTR mode and
               | the GMAC authentication code, which is based on GHASH. If
               | you're afraid of Galois fields, you don't get to use AES
               | at all! Nobody should be implementing _any_ of these
               | primitives themselves, very much including CBC, which, as
               | you saw downthread, left both you and the author of this
               | project with an insecure cryptosystem.
               | 
               | Vulnerabilities in CBC systems were for a long time
               | during the 2000s _the most common crypto vulnerabilities
               | on the Internet_. There are more things that go wrong
               | with CBC mode than just forgetting to authenticate it!
        
               | dragontamer wrote:
               | > You keep saying "the Galois Field" as if that was a
               | thing
               | 
               | You're kidding, right? You've never looked at how GCM-
               | mode works? The entire set of math is inside of the
               | GF(2^128) field. That's why its called a Galois Counter
               | Mode.
               | 
               | I don't think anyone should be implementing their own GCM
               | mode. Its very subtle and potentially full of traps. CBC
               | on the other hand is pretty dumb and simple, and
               | surprisingly secure and robust
               | 
               | > Vulnerabilities in CBC systems were for a long time
               | during the 2000s the most common crypto vulnerabilities
               | on the Internet. There are more things that go wrong with
               | CBC mode than just forgetting to authenticate it!
               | 
               | If they're so common, you shouldn't have much of an issue
               | naming one such vulnerability.
        
               | tptacek wrote:
               | I think some of my comment went over your head.
        
               | [deleted]
        
               | password11 wrote:
               | > _Or... you can have a more nuanced viewpoint_
               | 
               | The nuanced viewpoint is never implement your own
               | cryptography.
               | 
               | > _Its so stupid simple I don 't think that even a novice
               | would make a critical error._
               | 
               | Ask Microsoft about that one:
               | https://learn.microsoft.com/en-us/security-
               | updates/securityb...
        
               | dragontamer wrote:
               | That's a Padding Oracle vulnerability, not a CBC error.
        
               | password11 wrote:
               | Padding is an important part of CBC.
        
               | dragontamer wrote:
               | There is a huge difference.
               | 
               | A padding oracle attack can attack any system that uses
               | CBC + padding, even when CBC is perfectly implemented.
               | 
               | What I asked for earlier was a vulnerability due to an
               | improper implementation of CBC.
               | 
               | -----
               | 
               | Furthermore, padding oracles are completely irrelevant to
               | data at rest, like as described in this topics use case.
               | So it really is a bit of a non sequitur too.
        
               | tptacek wrote:
               | No, to all of this.
        
               | [deleted]
        
               | tptacek wrote:
               | It's a CBC padding oracle, intrinsic to the operation of
               | CBC --- if you PKCS7-pad some other mode, you do not get
               | the same attack --- the single best-known cryptographic
               | vulnerability on the Internet, and the parent commenter
               | took the time to give you the most famous instance of it.
               | For the record: that's _also_ not the only CBC
               | vulnerability.
        
           | ThePhysicist wrote:
           | AES-GCM is part of the Web Cryptography API and supported in
           | all modern browsers, so no need to implement anything.
        
         | tptacek wrote:
         | I don't know what "being a stream" has to do with anything (you
         | should virtually always use "stream" modes of AES); the
         | meaningful distinction between CBC and GCM is that GCM
         | authenticates the ciphertext, so you can't tamper with it.
        
           | tialaramex wrote:
           | > so you can't tamper with it.
           | 
           | ... if the API provided is correctly designed, and either the
           | language made it practical to design the API in a misuse-
           | resistant way /or/ the programmer was actually careful and
           | used it properly.
           | 
           | We both know it's _way_ more likely the problem in your
           | actual system is  "Oops, we use the bogus plaintext here
           | despite the validation error" than "Dastardly enemy
           | cryptographers have made a breakthrough in cryptanalysis to
           | attack our product".
        
             | tptacek wrote:
             | I'm not thinking very hard about it; there is just never a
             | reason to use unauthenticated encryption modes. When I
             | wrote that comment, I hadn't even looked to see if they'd
             | manually authenticated their ciphertext (spoiler alert: you
             | can guess).
        
             | ThePhysicist wrote:
             | SubtleCrypto (Web Cryptography API) will simply throw an
             | exception if the authentication fails for AES-GCM, so
             | there's no way to even get at the bogus plaintext.
        
         | [deleted]
        
         | 411111111111111 wrote:
         | The readme links to this issue wrt that decision
         | https://github.com/robinmoisson/staticrypt/issues/19
         | 
         | It seems that the hmac validation makes the GCM unnecessary in
         | their thread model
        
         | pluc wrote:
         | Leave it to full-stack devs to take care of cryptography
        
       | [deleted]
        
       | NKosmatos wrote:
       | I came here for the comments and sure enough I wasn't
       | disappointed :-)
        
       | jrexilius wrote:
       | This is a great utility and has a lot of meaningful use-cases.
       | Thanks for puting this out there!
        
       | avip3d wrote:
       | Wouldn't .htaccess solve this issue?
        
         | bertman wrote:
         | No, this is strictly client-side, ie. encryption and decryption
         | happen in the user's browser.
        
       | ebfe1 wrote:
       | Hah! I did a similar thing for a fun friday afternoon security
       | challenge with AES256 encryption on static website using the
       | answer to challenges as the key here if anyone wanna play with
       | it... :)
       | 
       | https://challenge.surge.sh/
       | 
       | It should take you no less than 10 minutes ;)
        
       | userbinator wrote:
       | I'll echo the other sentiments here that I wouldn't consider this
       | "static HTML", and I was expecting something about .htaccess.
       | That said, this seems to be a strengthening of what used to be
       | somewhat common "protection", namely variations consisting of:
       | 
       | - Password in plaintext in the source e.g.
       | "if(password=='hunter2') ..."
       | 
       | - No correlation between password and page contents (either the
       | content is merely hidden and shown when the password check
       | succeeds, or lightly obfuscated/encrypted using key independent
       | of knowing the password)
       | 
       | - Hiding content by using "display:none" or similar
        
       | DanielBMarkham wrote:
       | Gad! I have spent all morning trying to --- password protect a
       | static html page. How in the hell does HN have a story about the
       | exact topic I've been struggling with appear just a dozen or so
       | hours after I started working on it. Wow.
       | 
       | I was _extremely_ happy to see this posted.
       | 
       | However when I click the link I am taken to the library I had
       | initially tried and had to reject. Without getting into the
       | crypto side of things (which very well may resolve to "just make
       | it tough enough for most folks") I crashed and burned using this
       | tool once my page reached certain sizes. (I was cramming
       | everything I needed into one page and I had a big hunk of bytes
       | that I didn't want hanging out on the filesystem)
       | 
       | As I understand it, this is a known issue in V8. V8 limits the
       | number of properties/collection members an object can have.
       | There's a flag you can use with node to get a little more
       | headspace, I believe it's something like "--max-old-space-
       | size=8192" but it's a V8 problem, not a node problem. The
       | staticrypt coders could also switch to a streaming cryptography
       | instead of block, but that's far too much to ask of the casual
       | user who only wants to lock up a page or two.
       | 
       | This is a really cool tool, and I wished I could have used it.
       | Good luck to the team going forward. I've gotta find something
       | else as this doesn't work for me.
        
         | snowstormsun wrote:
         | Something similar has been posted before some time ago:
         | https://news.ycombinator.com/item?id=34083366
        
           | doodlesdev wrote:
           | Which in turn has inspired the creation of PrivacyProtect
           | [0]. It allows to do basically the same thing as the other
           | applications, but in my opinion the interface is better, it
           | also allows you to directly select a file which I guess is
           | easier than copying the contents, it also means you can just
           | select an image file for instance or some other type of file
           | other than a web page.
           | 
           | [0]: https://www.privacyprotect.dev/
        
             | DanielBMarkham wrote:
             | Why is everybody forcing me to upload to the web the very
             | files I want to keep private to myself? If any code in the
             | universe should run locally, it's this kind of code.
             | 
             | I don't get it.
             | 
             | Great UI, though. But I still don't get it.
        
               | cuttysnark wrote:
               | That the frontend is hosted on someone else's server is a
               | convenience, but I see your point and agree. Technically
               | nothing is uploaded anywhere, nor does it call any APIs
               | to do the de/encryption. Instead, it uses the
               | cryptography mechanisms built into your browser. Local
               | file access and creation are via FileSystem api[0]. Said
               | differently, you could save the page to your desktop--
               | ensure all the includes are to local files, and still run
               | it. In fact, thats's what I did with Portable Secret[1]
               | which others noted was previously posted here. I can
               | confirm this works and nothing "calls home".
               | 
               | [0] https://developer.mozilla.org/en-
               | US/docs/Web/API/FileSystem [1]
               | https://mprimi.github.io/portable-secret
        
       ___________________________________________________________________
       (page generated 2023-02-18 23:00 UTC)