9

Requirement:

Users fill out a form which includes sensitive personal data and need to be able to download the content of this form for a limited time.

Question:

How useful / secure is it to create a hash from

  • the data the user entered
  • plus a salt
  • plus the timestamp

and use this hash as the filename of the file with the stored sensitive data, then returning its URL to the user that just filled out the form, deleting the files after e specified time, e.g. 30 days.

Notes:

I know the situation is not ideal, but how would this 'hash filename' compare security wise to a user / password account situation.

But it should not be possible to guess the URL because of the hash and it would not be feasible to try random URLs to get a set of user data, or am i missing something here?

I have seen this being used when i ask for receipts, google docs, or something from online purchases with links being invalidated after a set amount of time.

Can anyone give me some idea of the effectiveness of such an approach?

4
  • Does the user create an account? Is there a session? Is the user supposed to be able to download the file from a different computer/browser than the one they just used to submit the data? Why not use session authentication?
    – jcaron
    May 13 at 13:18
  • If the file contains sensitive data it is a good idea to use a filename that does not reveal any details about the content. For the end-user it might be better to have a clear description in the filename.
    – Cie6ohpa
    May 14 at 5:36
  • @jcaron there is no user account, it was basically a bad design that is now under review and i needed to get an idea on 'how bad' it really was...
    – Larzan
    May 14 at 9:29
  • 2
    It doesn't protect the data. It protects the filename. Obscurity is not security, If you want to protect the data, encrypt it.
    – user207421
    May 14 at 10:14

5 Answers 5

19

I don't really see what problem hashing the filename is trying to solve.

If the filename is provided by the user, then it's unlikely to be unique, and the user is unlikely to remember exactly what they called it - so having them enter the filename to download their data isn't going to be secure or practical.

But if the filename is generated by the server, the user won't know what it is - so the only way they can access it is if you provide the link to them when they complete the form or via email or something. And if you're doing that, then you should just be sending them cryptographically secure (and probably single-use, as it could end up stored in the browser history/proxies caches/etc) random token, like you would for a password reset email.


Edits based on further discussion in the comments:

If you were generating secure random 256 bit tokens (or even 128bit) then the chance of someone guessing or brute-forcing a token are effectively zero. But the tokens are getting emailed round, stored in browsers, logged on proxies, etc, and you have no idea how secure those systems are. So it's not ideal, but depends on your exact use cases and threat models.

With hashed tokens it's impossible to say how easy they would be for an attacker to brute-force without knowing exactly how they're generated, and how predictable the data is - but it's almost certainly weaker than just generating a random token, and I don't really see any upside to it.

8
  • The filename is the hash of > the data the user entered into the form + timestamp + salt. The link will be displayed / sent via email (i know, insecure), so i basically use the token as filename. Does that count as at least a bit secure?
    – Larzan
    May 12 at 11:10
  • 5
    @Larzan you're reducing the entropy of the token compared to just securely generating a random one - but what benefit are you obtaining from using a hash instead?
    – Gh0stFish
    May 12 at 11:13
  • 3
    @Larzan if you were generating secure random 256 bit tokens (or even 128bit) then the chance of someone guessing or brute-forcing a token are effectively zero. But the tokens are getting emailed round, stored in browsers, logged on proxies, etc, and you have no idea how secure those systems are. With hashed tokens it's impossible to say how easy they would be for an attacker to brute-force without knowing exactly how they're generated, and how predictable the data is.
    – Gh0stFish
    May 12 at 11:22
  • 5
    See security.stackexchange.com/questions/29449/… for some interesting reading on using long randomly generated URL's to protect sensitive information.
    – mti2935
    May 12 at 11:41
  • 1
    @Larzan I've edit the answer to include these comments.
    – Gh0stFish
    May 12 at 12:14
18

The approach has several major issues.

  • If anybody ever accidentally enables directory listing in the webserver configuration, all sensitive files immediately become public. That alone is sufficient to avoid this scheme at all costs.
  • It's impossible to revoke access to a file without deleting it (and possibly creating it under a different name).
  • An attacker who knows the salt (which generally isn't considered secret information) and has managed to guess the timestamp (which isn't difficult) can check whether somebody has posted specific content. This again can be a serious problem in the case of sensitive data.

The solution is to set up a basic authentication system and store the files outside of the document root, not allowing any direct links. Access should only be granted to the actual owner of the file after they've authenticated (e.g., with a password). The implementation doesn't have to be complex. This can be done with a single short script and a database (a plaintext file is sufficient).

1
  • 4
    I agree with you and that is exactly what happened (the hoster effed up the server configuration and activated the directory listing, worst case). The whole thing was only supposed to be used in development for tests, but because of delays and a premature go-live without that part being finished, it ended up on the live site.
    – Larzan
    May 12 at 20:39
5

I would probably not use a hash to generate the file name, as these are deterministic, and someone might be able to guess the filename if they knew some or all of the data that went into the hash. Perhaps if you are hashing a lot of the file content to ensure that it was impossible to guess you might be ok, but what if the only data I put into my file was 'ok'? Counting on user behavior as a feature of security seems risky.

Also consider the problem of immutability: If I change the content in a file, does that change the hash? It's a classic no-no to use hash key values that can change over time.

Docusign use GUIDs for their documents. Upload a document, they generate a GUID, and it's basically unguessable. No real chance of collisions, and edge cases will never burn you with hashing. Give GUIDs a try.

ADDENDUM

Just realized this: Make sure that your language / platform / whatever has a way of generating crypographically secure guids if you go this route. Don't hack it with some psudo random rand() call as assume that is good enough if there isn't a native implimentation you can use.

ADDENDUM ADDENDUM

This solution you have cooked up didn't really sit right with me, and after thinking about it, I feel like can now properly articulate why.

You titled this article, 'Hash as filename to protect data'. The fact that you are using the hash itself as a form of security is the problem I think. Renaming files with GUIDs, Random strings, or hashes is done all the time, but it is not for security purposes. Its only to prevent file name collisions.

Even Docusign, which I cited as an example for GUIDs doesn't really rely on the unguessability of a GUID for their security. They have a whole layer double checking that you have been granted access to a file before letting you download it.

So, I would encourage you to adjust your thinking slightly. Hash the filename if you will, but don't tie the file name directly to the security model you are employing. It is basically turning the filename into a shared password.

1
  • all the content was being used for the hash generation and it was a minimum of ~60char or so. Basically, to recreate the hash you'd need to know all the sensitive data already, so the only new information you could get from the file would be that that specific person did fill out that form, everything else would have been know already
    – Larzan
    May 14 at 9:35
2

There are two and a half questions here (including your comments):

  • Is it reasonable to use a content hash?
  • Is it reasonable to mail the token around in standard (insecure) mails?
  • Is it reasonable to have a bunch of files with cryptic file names lying around on the server, which will be deleted after 30 days.

To answer these separately:

  • Content hashes are often used, but not for cryptographic reasons. They are appropriate for areas like source repositories (e.g., git storage blobs), file system data structures(e.g., ZFS deduplication and so on). Basically, when you want to very easily and quickly find content based on a hash, you would use this. Cryptographically, nothing beats a random token (true randomness, not pseudo-RNG-based). Also, I do not see a reason why using a content hash + timestamp + salt would be easier to implement than a cryptographically strong token. Every reasonable programming language these days should have a library for that.
  • It is what it is. If mail is your only medium, and a separate user account/trust cannot be created in some manner, then using an URL with the token included as a GET parameter is what you will need. Any cryptographically strong random token will by definition be safe against guessing or brute force, and you can easily adapt to future developments by making the length configurable or even automatically increasing it over time. You cannot do anything about the inherent problems with mail (i.e., the distributed and uncontrollable nature of SMTP server chains).
  • This would be sensible provided that your server is generally safe. Nothing special about it. You can safely assume that nobody will be able to exhaustively number through your token space if it's cryptographic randomness. And if someone manages to break into your server and downloads all those unencrypted files, then that is a different issue. Obviously, do not do this if you are running a simple PHP website on some server hosted by someone you do not trust, but in this case there is nothing you can do anyways.
4
  • 2
    This fails to address the fact that the whole scheme breaks down with a single configuration mishap (turning directory listing on). As the OP already confirmed, this is exactly what happened. "Provided that your server is generally safe" -- that's a fairly big (and vague) assumption.
    – Ja1024
    May 13 at 12:41
  • 2
    I do not see what I should change in my answer, @ja1024. "Provided that your server is generally safe" is meant as a delimitation for exactly this kind of issue. The question is not a general "what all do I have to do to make a safe web server" question, but focuses on a very specific detail. The answer answers the detail question, with some (explicitly mentioned) assumptions for the surrounding constraints that I clearly state.
    – AnoE
    May 13 at 14:07
  • You wrote that there's nothing special to consider with regards to the server, and that the server just has to be "generally safe" (whatever that means), but this is clearly not the case. The entire security of the approach depends on whether or not directory listing is enabled, which is a very special requirement. Like I said, according the OP, the system has already failed catastrophically because of this, so it seems pretty important to point this out -- and possibly advise against the approach altogether.
    – Ja1024
    May 13 at 14:43
  • 1
    The topic of tokens vs. hashes and insecure e-mail has already been brought up by Gh0stFish, so this part of the answer doesn't add anything new.
    – Ja1024
    May 13 at 14:45
0

I don't see the approach much different from using a randomly generated hash for filename. The randomness can also be added with all the points you have mentioned (like user input, timestamp, etc...) to add a bit of difficulties for an attacker to guess.

As other people have pointed out, if the attacker has any means of listing your directory, the random filename solution is cracked. This would be better if you put user input in a database but that's also not sufficient, database can also be dumped.


I would suggest another layer of protection be added, just like Bitwarden's "sending" function (and lots of other sharing services):

in your URL returned to user, there should be a "hash" property (not the cryptographic hash discussed above, but part of a URL, see this description), which is a symmetric key used to encrypt the user data before uploaded to server. This is done at client side, and from server side no one knows the content.

The URL looks like: https://example.org/<some random filename>/#48nJ5QjLoccM6rD9jmO2

The random symmetric key after # is not sent to server from browser, and is a good place to keep the secret at user's side.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .