Page 1 of 2 12 Last
  • Jump to page:
    #1
  1. Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Dec 2007
    Posts
    592
    Rep Power
    79

    Securing Files, Make them Accessible WHEN LOGGED IN?


    Hi there!

    I am designing a website for a client in which my client is able to upload PDF, TXT, and DOC files for HIS clients to see. The PDF and TXT are embedded in-site, while the DOC files are merely downloaded.

    Now, the problem: these files are extremely confidential, as they contain billing information, credit data, and content of the sort. How would I go about securing these files? On top of that, I need them to be accessible while the client is logged in, but only THAT CLIENT's files. I don't want the others to be able to be accessed via random URL guessing, etc.

    Am I making sense? Thank you!
  2. #2
  3. No Profile Picture
    Lost in code
    Devshed Supreme Being (6500+ posts)

    Join Date
    Dec 2004
    Posts
    8,316
    Rep Power
    7171
    1. Get a dedicated server
    2. Store the files outside of the web root
    3. Use a database table to keep track of who has access to which files
    4. Use header() and readfile() to deliver the files to the appropriate client when requested

    You could encrypt the files as well, although it would be of limited benefit if you stored the decryption keys on the same server as the files.
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2009
    Posts
    6
    Rep Power
    0
    You can use CMS software to manage permissions. In this way you can manage files online.
  6. #4
  7. Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Dec 2007
    Posts
    592
    Rep Power
    79
    My server allows me to upload files outside of the /www file. Is that what you meant?

    How would I upload to, and retrieve from, their location outside of the root? I've never done it before.


    EDIT - Also, how secure would .htaccess be?
    Last edited by Dekudude; March 7th, 2009 at 11:02 AM.
  8. #5
  9. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2008
    Posts
    496
    Rep Power
    89
    Outside of web root means one level up from your www.example.com/ directory. It might be the "www" folder you've mentioned or something else. Anyway, if you're using a shared hosting - get a dedicated one as someone already suggested, because shared hostings are not safe for projects like yours.
    .htaccess won't help you here. Especially if your hosting provider one day decides to disable .htaccess or do something like that.

    > How would I upload to, and retrieve from, their location outside of the root? I've never done it before.

    That has already been answered. Use header() to pass a file header and one of the available functions to pass the data itself. Uploading is the same as to any directory, however, downloading requires you to make a download script that uses the above functions to read the file and pass it to the user (because the user cannot read files outside www root).
  10. #6
  11. Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Dec 2007
    Posts
    592
    Rep Power
    79
    Gah. I highly doubt my clients wants to pay $200 a month for file hosting. Is there truly no other way? If not, what are some cheap dedicated hosts, if any?
  12. #7
  13. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2008
    Posts
    496
    Rep Power
    89
    If they do not want to pay $200 a month - they do not want their "highly confidential" data to be confidential at all You might try VPS plans, though i'm not sure of their security issues, you may check some providers that offer VPS. Also, i've seen simple dedicated servers for $99 / month in hostway.
  14. #8
  15. No Profile Picture
    Lost in code
    Devshed Supreme Being (6500+ posts)

    Join Date
    Dec 2004
    Posts
    8,316
    Rep Power
    7171
    Shared hosting is inherently insecure because hundreds of people have access to the server. You also have no control over the server or the security methods it uses. The server itself is also more likely to be attacked because of the large number of sites it hosts. Although certainly against the TOS of the shared host, it is sometimes possible for any of the other people with accounts on the server to access your files.

    A virtual private server is sort of a compromise and can be had for about $15/mo. A VPS is still technically shared hosting, in that multiple sites are hosted on the same physical server, but the level of separation between hosts in a VPS is hundreds of times stronger in a VPS than in a normal shared hosting environment. In a VPS environment it is not possible for someone else with a VPS on the same physical server to access your files unless the VPS host node is compromised.

    The disadvantage of using a VPS or dedicated server is that you either have to hire someone to manage the server or you have to manage it yourself. If you don't know how to manage a server and try to do so anyway you'll probably end up with an insecure server anyway, which kind of defeats the point. The advantage of a properly set up VPS or dedicated server is that you have complete control over security and random people can't read your files.

    You could also encrypt the files as I hinted at earlier. This wouldn't stop people from getting your files, but it would prevent them from reading them as long as the decryption keys are not stored on the server. That would work like this:

    For each client, generate a public/private key pair using an asymmetric encryption algorithm like RSA. Store the public key on the server, send the private key to the client (and don't store the private key on the server). When a private document is uploaded, generate a random string to act as a secret key for that document. Use the secret key to encrypt the document using a symmetric cipher like RC4, then encrypt the secret key using the client's public key and store the encrypted private key in the database along with the other file meta-data (location, which client it belongs to, etc.). Make sure you throw away the plaintext private key and original unencrypted document at this point.

    Now, when the client logs on and wants to access a document they enter their private key. The private key decrypts the secret key, the secret key decrypts the document, and the decrypted document is sent to the client. Make sure you throw away the private key they uploaded and the decrypted document and the plaintext private key at this point.

    The advantage is the documents will be relatively safe, even on a shared host and even if the server is compromised and someone steals the documents. The disadvantage is the clients have to remember the private key and upload it every time they want to access a document. Also, if the private key is ever lost, the document is gone forever. There is absolutely no way to recover it without the private key.

    EDIT:
    As murklys said, the simple fact of the matter is that more security costs more money.

    Comments on this post

    • requinix agrees
  16. #9
  17. Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Dec 2007
    Posts
    592
    Rep Power
    79
    A key sounds like it would be the best way for me to go. However, I don't know how to do it, haha. :P Do you know of any simple tutorials? I'll look in to it myself later today, but a nudge in the right direction never hurts.

    Would I be able to make it so that each key is generated based on a hash of the client's password, or something of the sort? That way, the only way to decrypt it would be to know the client's login password, which only the client should know.

    Thanks!
  18. #10
  19. No Profile Picture
    Lost in code
    Devshed Supreme Being (6500+ posts)

    Join Date
    Dec 2004
    Posts
    8,316
    Rep Power
    7171
    PHP's OpenSSL and MCrypt extensions provide all the functions you need. (OpenSSL for asymmetric encryption, MCrypt for symmetric encryption)

    Would I be able to make it so that each key is generated based on a hash of the client's password, or something of the sort? That way, the only way to decrypt it would be to know the client's login password, which only the client should know.
    No not really.

    If you generated a key based on the password hash then the encryption would be pretty much worthless because if an attacker gets at your files they can probably get at wherever you store the password hashes as well, and once they have the hashes it's trivial for them to decrypt the data by generating the keys themselves.

    If you set it up such that the password were used directly for generating the key (or use a different hash than the one used to store the password in the database) then you run into a different problem - you can't encrypt the document without knowing the client's password.

    One other thing to keep in mind is that a password is considerably shorter in length and weaker in content than a normal encryption key. A 10 character password is 80 bits long. An RSA encryption key should be at the very least 1024 bits, and 2048 bits is the recommended minimum length. You can take a 10 character password and create a 1024 bit key using it, but your key space still only has the security of an 80 bit key space. For RC4 the minimum encryption key should be 128 bits, which is considerably greater than 80 (consider, that each bit doubles the number of possible keys - so an 81 bit key space has twice as many possible keys as an 80 bit key space, and an 82 bit key space has four times as many possible keys as an 80 bit key space) and 256 bits is recommended.

    ---

    Here's an idea for you, although I don't recommend it for confidential information due to the key space issue I mentioned above:

    1. When a user creates an account, generate a random public/private key pair for an asymmetric cipher for that client. Store the public key in the database.
    2. Use the client's plaintext password to encrypt the private key using a symmetric cipher. Store the encrypted private key in the database.
    3. Generate a unique salt for the user and store that in the database.
    4. Use sha1 or greater to hash the password with the unique salt and store that in the database (you will use this for authenticating the user when they log in) as well.
    5. Discard the client's unencrypted private key and plaintext password.

    When a document is uploaded, generate a random secret key for it and encrypt it using a symmetric cipher and the secret key. Then, use the client's public key and encrypt the secret key. Store the encrypted secret key in the database, discard the unencrypted secret key. (Use a unique secret key for each document).

    When a client wants to download a document, prompt them for their password (do not store the plaintext password in session, prompt them each time). Use the plaintext password to decrypt the private key, use the private key to decrypt the document secret key, use the secret key to decrypt the document. Discard the user's plaintext password, decrypted private key, decrypted secret key and decrypted document.

    The Good:
    * The documents are encrypted, even if someone gains root access to the server they cannot read them
    * The client only has to remember a single password
    * Documents can be encrypted without knowing the client's password

    The Bad:
    * The key strength is weak, meaning if someone gained access to the files, was determined enough and had enough processing power they probably could crack some of the encryption, even using present day technology.
    * If the client forgets their password the documents are completely gone. A new public/private key pair would need to be generated and all documents re-uploaded from their original unencrypted versions and re-encrypted using the new keys.

    ---

    And, and in case it isn't obvious, this all MUST be running over HTTPS. If you run any of this process over HTTP then doing any of it is entirely worthless because of that hole.

    Also, when the client changes their password you need to prompt them for their old password so you can decrypt the private key, then re-encrypted it using the new password.
  20. #11
  21. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2008
    Posts
    496
    Rep Power
    89
    What if the password changes? You'll have to monitor password changes and possibly do a re-encryption of lots of files. And what's the point of doing this relatively secure thing? I think the first thing every hacker would check is if the files are not encrypted with user's password or its hash. It's almost the same as storing the encryption password on the server with a little added security. But if someone can access your files and retrieve the password for encryption - they can also find out the algorithm if you used to encrypt the files. So, as E-Oreo said, the safer way for this is to give the keys to clients. Because, really, if you plan on using a shared server (then i hope no hacker has interest in your company , you should at least not store the decryption keys on it.

    You see, on a shared server, if a hacker can't hack your website - he can simply crack some looser's buggy script (and there's probably lots of them on a shared hosting) and, possibly, even access your files. That is why you don't want to store sensitive data on shared servers and if you do insist on this solution, then encrypt the files and let the clients have decryption keys. Because if you don't - then there's almost no point in encrypting those files at all.
  22. #12
  23. Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Dec 2007
    Posts
    592
    Rep Power
    79
    Alright guys, thanks for all of the help thus far! I really appreciate it.

    PHP Code:
    <?php
    $fp
    =fopen ("/path/to/key.pem","r");
    $priv_key=fread ($fp,8192);
    fclose($fp);
    openssl_get_privatekey ($priv_key);
    openssl_private_encrypt($source,$finaltext,$priv_key);
    echo 
    "String crypted: $finaltext";
    ?>
    I found this on the openSSL functions page. Is this basically all I need? I encrypt $source (which I assume would be a file after being read and stored in a variable) and then decrypt it using openssl_private_decrypt? Would that provide a decent level of security, or would I have to take it a couple steps further? (salting it, etc)


    I really appreciate all of your help. As you can see, I am a bit new to the more sophisticated levels of security. I know how to prevent SQL injection, hash passwords, and all of that, but I am new to the more complex stuff.

    Thank you!
  24. #13
  25. No Profile Picture
    Lost in code
    Devshed Supreme Being (6500+ posts)

    Join Date
    Dec 2004
    Posts
    8,316
    Rep Power
    7171
    Originally Posted by murklys
    you should at least not store the decryption keys on it.
    Indeed, this is above all else the most important thing. If the decryption keys are stored on the server than the encryption is meaningless.

    As murklys mentioned, a shared hosting account has a high probability of being hacked (through the stupidity of other people, not through your own stupidity) so assuming that a hacker has access to all your data is a must. That is why the keys cannot be stored on the server.

    Originally Posted by murklys
    What if the password changes? You'll have to monitor password changes and possibly do a re-encryption of lots of files.
    You only need to re-encrypt the private key, since the private key doesn't change it isn't necessary to re-encrypt the files themselves.

    Originally Posted by murklys
    I think the first thing every hacker would check is if the files are not encrypted with user's password or its hash.
    The hacker won't know the user's password because it isn't stored on the server, and the hash isn't used to encrypt the file so it does them no good. The hacker can choose to attack the hashed password and try to recover the original plaintext password, but if a salt is used and a good hashing algorithm is used then attacking the hash of the password won't necessarily be any easier than attacking the encrypted files directly.

    Originally Posted by murklys
    they can also find out the algorithm if you used to encrypt the files
    The algorithms are publically available, wikipedia is a good place to read about them. Having the algorithm won't help the attacker if they don't have the key though.


    I found this on the openSSL functions page. Is this basically all I need? I encrypt $source (which I assume would be a file after being read and stored in a variable) and then decrypt it using openssl_private_decrypt? Would that provide a decent level of security, or would I have to take it a couple steps further? (salting it, etc)
    Read over the steps I outlined carefully, you can't use the openssl functions to encrypt the files directly because asymmetric encryption can't handle large chunks of data.

    When encrypting a new file you:
    1. Generate a random string of 256 bits (32 "characters" - but they don't have to be visible ascii characters)

    ex:
    PHP Code:
    $document_key '';
    for(
    $i 0$i 32$i++){
      
    $document_key .= chr(mt_rand(1,254));

    This is your document secret key.

    2. Encrypt the document secret key using the openssl functions. You actually want to use the public key to encrypt it, not the private key:

    PHP Code:
    $public_key_text // retrieve from database, each client has their own public key
    $pk openssl_get_publickey($public_key_text);
    $encrypted_doc_key '';
    openssl_public_encrypt($document_key,$encrypted_doc_key,$pk);
    // store $encrypted_doc_key in the database record for this document 
    3. Encrypt the file contents using the (unencrypted) document key:
    PHP Code:
    // $unencrypted_data should contain the contents of the file you want to encrypt
    $td mcrypt_module_open("rijndael-192",'','ecb','');
    $iv mcrypt_create_iv(mcrypt_enc_get_iv_size($td),MCRYPT_RAND);
    $key $document_key;
    if(
    strlen($key) > mcrypt_enc_get_key_size($td))
        
    $key substr($key,0,mcrypt_enc_get_key_size($td));
    mcrypt_generic_init($td,$key,$iv);
    $encrypted_data mcrypt_generic($td,$unencrypted_data);
    mcrypt_generic_deinit($td);
    mcrypt_module_close($td);
    // store $encrypted_data somewhere, either in the database or on the filesystem 
    Make sure you don't save $unencrypted_data or $document_key anywhere after the script finishes running.

    When you finish, all you'll have is an encrypted key for decrypting an encrypted document. In order to decrypt the document, you first have to decrypt the key. The key can only be decrypted using the client's private key (which is also encrypted). The client's private key can be decrypted using the client's plaintext password, and once you have that you can unravel the process.

    To decrypt a document, you:
    1. Use the client's password to decrypt the private key
    2. Use the private key to decrypt the document key
    3. Use the document key to decrypt the document

    The last thing to note: When you create a public/private key pair for a client you have to encrypt the private key. To encrypt the private key you use the same code that I posted above for step 3 of encrypting a document, except that the content to be encrypted is the private key and the encryption key is the user's password. This step only has to be done once though when the client's account is created (actually it also has to be done when they change their password).

    ===

    The "triple layer" thing is probably confusing, but it is necessary.

    You can't use a single symmetric cipher using the client's password as a key because then you need to know the password to encrypt documents.

    You can't use a single asymmetric cipher because you can't generate an asymmetric cipher key using such a value as small as the client's password (remember, 80 bits vs 2048 bits) and you can't encrypt a document using an asymmetric cipher (unless the document is like 1 sentence long max).

    A two layer approach would require that at least one of the keys be stored on the server, so you're stuck with a three layer approach.

    Comments on this post

    • Xyteran agrees : Wow, haha. Thanks. This looks complicated, and I will probably have more questions, but I will do my best to get it working. Thank you very much!
    • Winters agrees : No points left to give.
    • simshaun agrees : Good explanations
  26. #14
  27. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2008
    Posts
    496
    Rep Power
    89
    You only need to re-encrypt the private key, since the private key doesn't change it isn't necessary to re-encrypt the files themselves.
    We both replied at the same time so my post was addressed to the encryption with the password's hash and not your post
  28. #15
  29. Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Dec 2007
    Posts
    592
    Rep Power
    79
    Alrighty, I have a question. How do I come up with a public key for the client? Should it just be a random string of text, or what?

    Thanks!
Page 1 of 2 12 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo