
Show HN: Password-protect a static HTML page - yoble
https://robinmoisson.github.io/staticrypt
======
roywiggins
In highschool I realized that my school's grading system was using a
javascript scheme to control access to grades online:

1\. Concatenate the username and password, hash the combination

2\. Name the HTML file with the grades using that hash

3\. When the user logs in, calculate the hash in Javascript and redirect to
that HTML page.

In theory, you can only work out the URL of the page if you have the username
and password in hand. I'm sure it was pretty trivially bruteforcable, but
aside from that it seemed sort of okay.

Until I realized that directory listings were turned on, and the directory
that had all the HTML files sometimes had no index.html, thereby rendering the
entire obfuscation scheme moot.

(n.b. I was too ethical to use this to peek at anyone's grades! I did try to
report it but it was never clear to whom to report it to, and since every
teacher generated these files using their own copy of the program, there was
no obvious central place to report this to. A couple of years later online
grades were centralized into a different system)

~~~
joekrill
From the way we've seen most schools respond to these types of reports from
students you have to wonder if you were lucky that you couldn't figure out how
to report it!

~~~
roywiggins
The time I accidentally took down the entire school website, I luckily did it
at school and immediately told my understanding math teacher, who told IT
directly, who came and asked me what I'd done, and fixed it within a couple
minutes.

In retrospect I dodged a huge bullet!

------
fredsted
Encrypted page includes javascript from 2 CDNs, one for jQuery and one for
"crypto-js". The jQuery one has an integrity hash, but "crypto-js" does not.
Granted, they both use HTTPS...

Doesn't seem very secure to include external JS on an encrypted page.

Why not include those things inline?

And why does it need jQuery for a simple 1-input form field that decrypts a
string?!

~~~
acdha
Using a CDN is only a problem if it's compromised, which is unlikely to be a
threat for most applications. You can avoid this entirely by using Subresource
Integrity:

[https://developer.mozilla.org/en-
US/docs/Web/Security/Subres...](https://developer.mozilla.org/en-
US/docs/Web/Security/Subresource_Integrity)

It looks like the developer for this page copied the CDNJS links at some point
but didn't do so consistently and later commented out the SRI portion of the
jQuery tag:

    
    
        <!--integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="-->

~~~
joshu
It is also a threat if your DNS is compromised.

~~~
a3_nm
Not when fetching over HTTPS.

~~~
snakeanus
The CA system is extremely broken, it won't protect you from a state actor.
Also TLS + DANE is useless if the DNS is compromised.

~~~
acdha
That's a bit too much hyperbole to be useful: yes, a state which runs a
trusted CA is a threat (at least for sites which don't use key-pinning) but
there are a ton of other things you're at risk for that way like SMS-based
auth and the police or black bag squad paying you a visit. Describing the CA
model as extremely broken because it doesn't handle an out-of-scope threat
doesn't help anyone change their behavior to avoid it.

------
jszymborski
I remember in ~2005-2009 while I was in high school, javascript password-
protection was my main interest, since I only had access to free hosts that
hosted static files.

Most of them just focused on obfuscating the password in the source (most by
encoding, the fancy ones through some opaque evals), but I came across one
during that time that claimed to use AES and even had a not-insignificant cash
prize for defeating it.

I really wish I could find that site... would be fun to give a shot at
cracking it given what I know now.

Anywho, in my search for that site, I found a pretty good tutorial considering
it's age (1997!) on implementing DES in javascript to achieve something
similar[0].

[0] [https://www.javacrypt.com/Course/](https://www.javacrypt.com/Course/)

------
devy
I remember 3-4 years ago when I was working with a major wall street financial
company to integrate with their credit card processing gateway, some of the
private and sensitive information (contracts, testing reports etc.) had
already been communicated with a similar but proprietary AES 256 based
encryption on a static HTML page via email attachments as a way of secure
communication. The intended recipients would get an invite to their site to
register/login to get the passphrase to unlock the encrypted static HTML doc.
This could have been the standard practices in many financial firms theses
days (when they are not using PGP/GPG encrypted emails)

Edit: redacted the name of company.

~~~
wyc
I believe SendSafely
([https://www.sendsafely.com/](https://www.sendsafely.com/)) claims to have a
somewhat secure/streamlined implementation of this. Browser non-plugin
JavaScript crypto is always sketchy, but possibly better than nothing if the
limitations are correctly communicated to the user.

~~~
devy
SendSafely's workflow is quite different[1] from what I described with the
encrypted static HTML email attachment. And I don't like the idea of sharing
the confidential data over 3rd part cloud storage even if it's encrypted.

[1]:
[https://www.sendsafely.com/howitworks/](https://www.sendsafely.com/howitworks/)

~~~
wyc
I agree there are differences, including transit route and format.

Here are the similarities I saw:

\- Payload is encrypted client-side by the sender

\- Encrypted payload is decrypted client-side by the receiver

\- 3rd party provides the unlock passphrase

I think I'd much prefer standard AES to AES sprinkled with a bit of
proprietary magic, as the latter is more likely to introduce new attack
vectors than not.

------
syphilis2
It does not seem to work for me on multiple machines. I just get an incomplete
HTML file that ends abruptly after the "border-top" CSS line. There is no
closing semicolon to the line, the file just ends in the middle of the style
element.

My input doesn't seem to matter, but I used:

<html><body>Hello</body></html>

Password: abcdefg

~~~
chicob
Same here.

<head> is truncated.

~~~
torrey_braman
Retry it without the html tags

~~~
mlok
Still not working.

~~~
yoble
Thank you for the reports, @thread.

Firefox was escaping the downloaded data (loaded in a href attribute)
differently than chrome, that problem should be solved now. Do let me know if
you still experience issues.

~~~
chicob
This is what I get:
[https://postimg.org/image/lhy1cdkad/](https://postimg.org/image/lhy1cdkad/)

------
viggity
I remember very distinctly about 15 years ago there was a site that had a
"members only" page that had some reports that I really wanted
(names/addresses/emails of the members of the org - I wanted a quick and easy
lead list for a product I wanted to sell to them). I could see through a
simple view source (remember, no chrome dev tools back then) that it wasn't
some server side check of the password (the members knew it, there was no
associated username).

They had found some library that would take a password and a desired output
and would generate some super crazy javascript looping/shifting/replacement
algorithm that would generate the name of the html page that had the desired
content. The report was available openly to the internet, but there were no
links to it, just through this algorithm.

I spent about 4-5 hours slowly but surely reverse engineering the algorithm so
I could figure out what the page name was. There was an immense sense of
satisfaction that came with being able to look at those reports.

~~~
pbhjpbhj
Unauthorised access and for financial gain - serious prison time awaits for
such things in USA and UK. Take care!

------
shams93
Back in the day we used to use Apache basic authentication for this, that was
before single page apps. Not you do have jwt that is explicitly designed to
handle things like offline progressive web app logins.

~~~
xaedes
As I read the title my first thought was "Huh? htaccess?"

------
StavrosK
Oooh, this is pretty cool. All that it needs is a cli utility so I can plug it
in my scripts, and I can just tell my static site generator to encrypt
specific pages while building.

~~~
perryprog
That would be cool! Maybe a gulp plugin or somthing, that would wrap your
pages with that, and then set a cookie or something.....

------
finchisko
Thank you for inspiration. I've created nodejs module to encrypt files. Now
wondering if we can make webpack bundle-loader that will load encrypted
chunks. How cool would be that? What u guys think?

------
renhoeknl
I did something like this some time ago, to send reports securely to people
who'd never heard of PGP.

What I like about my implementation is that it has a tamper proof clear text
message included with the encrypted payload. And everything (images and JS) is
inline, so nothing external needed.

[http://ivo.palli.nl/encryption/encryption2.html](http://ivo.palli.nl/encryption/encryption2.html)

------
bandrami
If only the web server software could do this for you...

~~~
thesmok
It should be quite easy to make an nginx plugin for that.

------
examancer
Simple and useful. The perfect "Show HN".

~~~
nroets
There are many caveats. For example, the server and the connection must be
trusted. Otherwise, an attacker can the javascript to send himself a copy of
your password.

And weak password are subject to bruteforcing.

If you trust the server, rather use htaccess. Or place the document at
example.com/mySecretPassword/index.html Just be careful about outgoing links.

------
112233
A feeling of saying "what is this familiar thing":

[http://www.acme.com/software/securepage/](http://www.acme.com/software/securepage/)

(2010 or earlier, basically does similar trick, from the authors of thttpd,
mini_httpd and micro_httpd!)

~~~
yoble
I didn't find that one when I looked for this kind of tool so I rolled out my
own, I would have definitely given it a go !

------
calebm
I wrote a little web app very similar to this last year:
[https://hypervault.github.io/](https://hypervault.github.io/). The difference
is mine was mostly focused on file encryption.

~~~
perryprog
That is cool :D

------
jopsen
That's a fun toy.. and a great example of how easy it is to get crypto wrong.
I'm just guessing here, but you are probably missing some key derivation like
PBKDF2.

Edit: For this something like tweetnacl is probably more foolproof, checkout:
[https://github.com/dchest/tweetnacl-js](https://github.com/dchest/tweetnacl-
js)

Or libsodium which can also be compiled to pure js:
[https://github.com/jedisct1/libsodium.js](https://github.com/jedisct1/libsodium.js)

~~~
lwhsiao
crypto-js has PBKDF2 functionality. What part of it this did you find wrong?
Preferably not a guess, but something more concrete that can be informative
for other readers. For example, could you provide some insight on why the two
libraries that you link to better for this use case?

~~~
cryptoishard
You've somewhat rolled your own crypto. For instance, you've manually HMACed
separately and appended it to the message, and you've chosen which encryption
primitives to use. In this case, I don't see anything wrong (you've used
encrypt-then-mac, which is the recommended way of doing it).

Another easy to make error would've been to use the same key for the MAC and
the encryption. In this case, the library probably uses a unique salt
everytime it generate a key from the passphrase, so you're fine there too.

In principle though, using a library like NaCL or Libsodium offers a high
level "encrypt and sign" primitive and you should be using something like that
to avoid getting anything wrong. There are lots of mistakes to be made.

libsodium is unfortunately a bit broken because the pw_hash functions (argon +
scrypt) don't work in the browser.

------
johnhenry
Reminds me of this:
[https://news.ycombinator.com/item?id=10901745](https://news.ycombinator.com/item?id=10901745)

Similar, but uses files instead of HTML text.

------
tspike
Interesting. What is the use case for this versus HTTP basic auth?

~~~
jewbacca
You don't need to control the server

But you can still control access to the content, distributing the password by
other channels.

A plausible use case for this (... like basically any crypto thing) would be
clandestine organizing. _Significantly_ less sophistication required, and much
less of a trail left, to put a static site online.

Shit, you wouldn't even need to host it as a site: you could drop it somewhere
as text, eg on a pastebin or in a forum comment, with "save as .html and open"
instructions. And you could distribute the encryptor itself the same way.

The really great thing about this is that you could do practical human crypto,
without Alice or Bob needing any special knowledge or equipment besides a web
browser, using arbitrary uncontrolled public infrastructure.

... though if someone knows the password + controls the infrastructure you've
used, they could substitute their own content.

... also short password + direct access to ciphertext -> easy brute force.

... also everything here:
[https://news.ycombinator.com/item?id=14554187](https://news.ycombinator.com/item?id=14554187)

Wouldn't use it for anything state-level or life-or death. There are
mitigations, but that would increase the difficulty and necessary
sophistication for using it. Actually, this probably falls into the uncanny
valley where it seems just accessibly cyberpunk enough to be extremely
dangerous to anyone relying on it. But still, really cool IMO.

------
nealrs
Pretty pretty neat. I built [something pretty
similar]([https://devpost.com/software/cryptopostal](https://devpost.com/software/cryptopostal))
to give my address to family & friends during the holidays. Includes a node
generator to make your own. Enjoy :)

[video demo]([https://youtu.be/zevMEiR2CZY](https://youtu.be/zevMEiR2CZY))

------
bluetidepro
This would be neat if you could build a wrapper of this around GitHub pages.
Then you could finally use GitHub pages sites for private content!

Also, as a non-security person, just how secure is this? Like is it used more
for "eh, I don't really want something to see this, but it's not the end of
the world if they do" or more like "yeah, use this for extremely secure
content, it's safe."

~~~
dangom
Doesn't the GitHub pages content itself live in a repository visible to all?
One could just look up the password. Or is it possible to have pages for
private repos as well?

~~~
Darphe
The passphrase wouldn't be included in the repo; that's the purpose of using
client-side encryption.

------
minhajuddin
I had built something along these lines. Not really encrypting the page. But
allowing you to send each other Base64 data:
[http://cloak.websrvr.in/](http://cloak.websrvr.in/) . I had built it to
circumvent enterprise email servers which don't allow sending binaries. Which
is kind of ironic because email sends attachments as Base64.

------
speps
And no one mentions TiddlyWiki[0]...

[0] [http://tiddlywiki.com/](http://tiddlywiki.com/)

------
alexbecker
I did something similar to this for redacting HTML pages a while back,
although I never fully polished it: [https://github.com/alexbecker/redact-
js](https://github.com/alexbecker/redact-js)

It's not something I'd use for serious security applications, but fun for
interactive fiction.

------
anilgulecha
This is cool! To really make the overhead tiny, include an inplace
implementation of XTEA (under 1KB decryption).

XTEA is not a military grade algo (but there's only been a partial attack on
reduced rounds). All in all the overhead can come in under 2KB in all.

------
chiefalchemist
Not sure, but this might be useful and/or interesting to some HN'ers

[https://github.com/ezWebDevTools/ezCryptoJS](https://github.com/ezWebDevTools/ezCryptoJS)

------
conmarap
It's pretty cool. I entertain the idea of doing this and hadn't thought of it
ever, but how do you see it being used if I can't use it with a python/node.js
API to deploy pages on the fly?

------
sleepychu
Rubber hose encryption would be a neat add here!

~~~
zyx321
Do you mean plausible deniability? That would be hard to accomplish on a
static file, since there's no logical reason it would include 'empty space' in
the way an encrypted hard disk does.

~~~
ColanR
I don't think so. There was an encryption scheme thought up and partially
implemented about a decade (or two?) ago that allowed for an arbitrary number
of partitions to exist in a single encrypted drive. It was called 'rubber
hose' because the scheme was designed such that it was impossible to determine
how many partitions existed inside the encrypted drive.

I don't think it's a scheme that's even relevant to this context, though.

Edit: source.
[https://en.wikipedia.org/wiki/Rubberhose_(file_system)](https://en.wikipedia.org/wiki/Rubberhose_\(file_system\))

~~~
zyx321
That is exactly what I was referring to. An HTML file has no empty space to
hide something in.

For those not familiar with the terminology, "rubber hose" in a cryptography
context is a euphemism for torture. I know of two approaches to counter it.

Plausible deniability, where you can give out a password that unlocks some of
the data, but your adversary has no way of knowing whether that's all of it.
Useful if you can expect that you'll be let go if you're 'innocent'.

A self-destruct function, e.g. you give out the wrong code 3 times and your
device wipes the data. Useful for military use cases where the data is worth
more than the life of the person holding it.

~~~
examancer
If the tool always makes a large blob of noise to hide the HTML in, and
accepts an arbitrary number of key/html pairs it seems like this could work in
the browser. Would seem to just cost disk space to be viable.

------
ConfucianNardin
This is essentially what encrypted pastebins do (but they usually put the
key/password in the URL hash).

------
Steeeve
That is awesome!

I would love to see it worked out in a way that it would output different
content depending on password.

------
amenghra
In 2017, one ought to use browsers' native crypto API instead of doing crypto
in js...

~~~
colejohnson66
Browsers have a native crypto API? Last I heard, websites requiring client
side crypto used libraries written by other people. There's even a Node.js
module for crypto.[0]

[0]: [https://www.npmjs.com/package/crypto-
js](https://www.npmjs.com/package/crypto-js)

~~~
kaoD
[https://www.google.com/search?q=web+crypto+api](https://www.google.com/search?q=web+crypto+api)

------
skdotdan
Seems very cool, but I don't see the use-case. Anyone can help me?

~~~
akeck
Static site on CloudFront?

------
romanovcode
For some reason it doesn't work with password 123

~~~
yoble
The password "123" is working for me, if you find steps to reproduce do let me
know !

------
ezekg
Now make a WP plugin and you're set!

~~~
ComputerGuru
WordPress has access to server-side scripting, why would you use js encryption
there?

~~~
unknownid
\- Allows transferring encrypted data over an insecure network \- Page can be
loaded online and decrypted/read offline later \- Server cannot track who
successfully decrypted the information \- If server is compromised by a third
party, they cannot retrieve the encryption key from users viewing the document
\- Among other things

~~~
ComputerGuru
We use JS encryption heavily in a number of our webapps, so I'm not unfamiliar
with its advantages. But relying on JS encryption to provide "security" over
unencrypted HTTP is just asking for trouble. It's the "secure on paper, broken
in practice" kind of thing that ends up being a huge liability.

~~~
pdx
Why do you speak of unencrypted HTTP? Who cares? Only AES-256 encrypted data
is sent and it's decoded locally. You could publish it on the front page of
the New York Times (if anybody reads that anymore) and be secure, because you
are publishing encrypted content.

It's really unclear what your point is here.

~~~
iancarroll
Your unencrypted (or just unauthenticated) HTML page might suddenly start
sending the password you enter elsewhere...

~~~
pdx
Really, how? Because somebody compromised the server? So what? If they did
that, all bets are off.

~~~
dpark
No, because someone MITMs your insecure channel and serves you a malicious
page that steals your password and the unencrypted data.

------
Animats
There's basic authentication for protecting static web pages. It's no better
or worse than any other password scheme.

------
cdevs
I could see some other nifty concept coming alive because of this.

------
snakeanus
From the source code I was unable to deduce what KDF and Block mode is used
with it. Does anybody know what does it use? crypto-js seems to support
multiple different KDFs and Block modes.

~~~
cryptoishard
doc says it defaults to cbc, not sure about the kdf

