1
$\begingroup$

What would be the best approach for storing a list of hardcoded email addresses in plain sight (in a public JS file or such)?

The site is pretty low-key, for a small community of friends. Starting out, I'd like to just hardcode some email addresses as hashes, which would then be checked against a users input to check that they are an invited member of the site.

Rather than creating an api with authentication etc, I'd prefer to keep it all in the front end. The 'account' would only be used for tracking user and guiding them to the right resources. Nothing financial, or sensitive.

I understand I could use an MD5 hash, though I hear this would be easily cracked?

$\endgroup$
3
  • 2
    $\begingroup$ Would love to know why this was downvoted so I can improve my question(s)? $\endgroup$
    – shennan
    Commented Nov 4, 2019 at 18:11
  • $\begingroup$ This almost seems off topic for the site, to me. Security through obscurity is not cryptography. $\endgroup$ Commented Nov 6, 2019 at 20:33
  • 1
    $\begingroup$ But I think it's clear I'm asking for a cryptographic hash function of some sort? Granted, my use-case sounds a bit lame but I still feel like it's relevant to cryptography. $\endgroup$
    – shennan
    Commented Nov 6, 2019 at 21:09

2 Answers 2

1
$\begingroup$

It sounds like you have a public store for some data, and you want to use it to store a set of secret elements, with the following operations:

  1. Add a new element to the set.
  2. Query whether an existing element is in the set.

(I'll assume that this is where the story ends—if you're actually trying to do some kind of authentication, there may be substantially more to it. I'll also assume that you already have a mechanism for authenticating changes to the set, and your main concern is to prevent disclosure of the elements of the set.)

If the party that needs to perform these operations can additionally keep secrets, say a 256-bit secret key $k$, then instead of storing an element $e$, you could store a secret pseudorandom function of $e$, such as $\operatorname{HMAC-SHA256}_k(e)$. Computing $\operatorname{HMAC-SHA256}_k$ requires knowledge of $k$; nobody without $k$ can tell the difference between your set of hashes and a set of independent uniform random 256-bit strings.

However, compromise of $k$ would enable anyone to verify elements of the set, enabling dictionary searches and batch speedups like rainbow tables. If you're concerned with compromise of $k$ in addition to disclosure of the list of hashes, you could:

  1. Use a password hash like Argon2id instead of HMAC-SHA256 to raise the cost of testing guesses.
  2. Use a Bloom filter rather than a list of hashes. This raises the false positive rate for membership tests from totally negligible (at most $n/2^{256}$ when there are $n$ elements) to something you have to worry about based on the Bloom filter parameters, but it also gives an adversary less to work with by not even exposing individual hashes to attack—raising the probability of false successes for the adversary.
$\endgroup$
6
  • $\begingroup$ This is an interesting option as there is a single authentication passphrase for entrance to the site (came free out-of-the-box with the framework I'm using). So all users will have to keep a single secret anyway. I could use this secret as 𝑘 in your example. Looking at CryptoJS it appears there is HMAC-SHA256. I presume this would be suitable for my needs? The result of a test encryption on one email results in an object with an array of integers and sigBytes: 20. I presume I will need to match these to whatever was generated by the user? $\endgroup$
    – shennan
    Commented Nov 5, 2019 at 11:15
  • $\begingroup$ @shennan Who makes the decision of whether a user is allowed in? Is it the user themself, by checking whether they're on the guest list and politely leaving if not, or is it some kind of application server? If it's some kind of application server, I meant storing that secret key as part of the application server. $\endgroup$ Commented Nov 5, 2019 at 16:19
  • $\begingroup$ The first one. Every user has the same passphrase to get through to the site. This is done through backend authentication and session. I'm unable to hook into that authentication and add emails as the framework is just offering a simple password protected site. I would like to add email as an added check that they are who they say they are, without doing any more backend work. So I figured I could use a combination of the passphrase they all have, and their individual emails, which I will hardcode on the front end. $\endgroup$
    – shennan
    Commented Nov 5, 2019 at 16:24
  • $\begingroup$ An enemy could potentially still authenticate without the email so long as they have the passphrase, but my users won't be of this nature and so this method would work for purposes of tracking users and tailoring their experience. The key thing is to make it hard for an enemy to guess the emails. $\endgroup$
    – shennan
    Commented Nov 5, 2019 at 16:25
  • $\begingroup$ @shennan OK, then I guess you can use the passphrase as an HMAC-SHA256 key (or, if the user can afford some computation when checking the guest list, an Argon2id key), and it might be worthwhile to use a Bloom filter to limit the ability of an adversary to enumerate the email addresses even if the passphrase is leaked. $\endgroup$ Commented Nov 5, 2019 at 16:47
1
$\begingroup$

If you have or just want to have just the email address for authentication then you could store a password hash as value in the public JS file. You could for instance use PBKDF2 with salt and relatively high iteration value. Basically, if you do that, you treat the email address as a passphrase.

However, please keep in mind that an email address is really easy to guess, and therefore an adversary could just try email addresses and try to get to the same hash in an offline attack. It's unlikely that the iteration count / work factor will be a prohibitive measure. However, your friends could use a complex mail address if they would wish (e.g. Google allows to use [email protected] as alias for [email protected]) and be more secure.

MD5 - or any other cryptographically secure hash - is not secure for password hashing by itself.


Another issue is that adversary can change the code in the client and skip any verification that takes place in there. So your security should at least be partially implemented at a different place than the page anyway. Generally you'd try and secure your system starting at the server. For that however you do need code execution on the server. If the server can e.g. store the hash, and limit the amount of tries, then you're already much more secure.

If the system is for sending messages then you could also put some verification / security at the receiver of the messages if the server is unavailable to you.

$\endgroup$
1
  • $\begingroup$ Thanks for the info. Yes, aware that this wouldn't be the most secure and that real verification would be best done by a server. It's really more of a quick measure for being able to track the user and give them a more tailored experience. None of the resources are sensitive, so if someone was to gain access it wouldn't matter. There would only be around 100 emails and they wouldn't have any other information attached to them like names etc, so I'm guessing that running a dictionary against it would take quite a while before anything was found. $\endgroup$
    – shennan
    Commented Nov 4, 2019 at 18:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.