So I have no code at the current time but I haven't quite started because of the following issue.
I want to have a website (written in PHP) that allows users to upload files but I'd also like to have a C# app that runs on a Windows desktop and can automatically upload the files. My question has to do with security.
Firstly, from the PHP perspective is simply hashing and salting with MD5 or something similar really safe for accounts on a website?
Furthermore, how can I safely STORE and preserve the credentials of the user LOCALLY within my C# application? Almost like cookies except I'd be managing it myself. I'm looking for a high level answer as well as what specific tools I should use (or what I should read about before fully pursuing this).
Thank you in advance for your time. :)
To answer both questions...
Firstly, hashing and salting with MD5 is no longer 100% secure as people can use a rainbow table to quickly hack the hashing. You might want to look into something that generates a longer hash to prevent rainbow tables attack.
If you want to safely store a authentication token on the client end (like a "remember me" check box), you can have a table in your server that stores a random string every time the user accesses the php page. To make it more secure, you can hash in a unique value of that PC, like the network card's MAC address.
What this does is...
1) When the user first logs in from the c# app, you will create a record that stores the user id, the MAC address, and a long random string in that table. You then return this random string to the c# app to store in the local file.
2) When the c# app access the web page again, it will pass to your PHP app, the MAC address and the random string stored there. If it matches a record, then we know the user id of the c# app.
3) The php side should then re-generate another random string and send it back to the c# app to overwrite the existing locally stored authentication token. This will ensure the token changes a lot and people cannot simply make a copy of the file storing the token, and be able to access the server.
Hope this is clear enough.
A salted sha256 hash will be fine. Salt it with something that isn't stored in the database. Having the data come from two different sources will make it even harder to brute force.
It depends on the C# app. If it's only going to have one user then transfer the files over SSH using your public key. If something goes awry you can always revoke the key.
Related
Let's say I have a MySQL database into which users can enter some personal data like postal addresses via a php website. The users can NOT log into this site to later verify what they have entered. The enterprise they have entered their data for (voluntarily of course) then can use this data to maybe send the users actual mail (you know, postal services and such) or emails (of course the users agreed beforehand that they want to receive emails). The database serves merely as a store for the data and I want it to be a bit safe. If anyone breaks into the database, retrieving the email address and the actual first and last name (many email addresses contain both anyway) might not do much harm, but knowing where people live could be too much of a giveaway.
The enterprise is accessing the database via a C# front-end that targets stored procedures within the database to do stuff, including searching for users based on their email address.
From what I have gathered through searching I could think of the following procedure to handle the personal data in a more secure way (than saving them as plain text in the database)
before submitting the sensitive information to the stored procedures the plain text gets encrypted with a key while still in php, so all the MySQL server logs see is encrypted data
the front-end uses the same key to make the data humanly readable again when it is displayed to the enterprise's users (They need to access this private information and the user is comfortable with the enterprise doing so, that's the whole point of this scheme)
My line of thinking is: These are not passwords that are stored so I don't need all the password hashing trickery (As I understand it, when securely saving a password in a database, you use a one way algorithm, so you can never reverse engineer the password straight from the database but have to hash every password you want to try and test that against the desired database entry to see if you chose the right password) but can instead go for a simple encrypt/decrypt, because I don't want to brute force every address out of the database.
There are a few rough edges that raise concerns for me:
I need to somehow provide the key I want to encrypt by to php. Usually this is done via a library or external php document, like you provide the database connection information in a separate php file which resides in a folder on the server which is not accessible from the web (The server will say access denied if you try to access it) Is this a good practice and can I be sure that this key-file is really safe?
I need to provide the key to the front-end as well. This should be done separately in a (maybe encrypted?) config file for the front-end. Is it wise to have the key in two places, albeit for two different systems? The key must never change or else part of the data will be lost!
Somehow I have the feeling that if someone knows how to access the database he/she probably figured out where the connection data was and how that was to be accessed. Oh look, here is an encryption key, I wonder what that does. How likely is it that if the database access is breached the encryption key is in the open as well rendering all efforts to give a little extra of privacy to the users void?
If I wanted to add another bit of "extra security" and encrypted the email address as well I would have to encrypt every email address I want to search for from the php or the front-end, right?
Having searching procedures using ´RLIKE´ will break on encrypted fields, won't they? So to retain searching for parts of an email address I cannot encrypt the email entry, right?
I will have to change my database fields to binary to accommodate encrypted data or make them bigger and base64-encode them, won't I?
Is there an encryption/decryption algorithm ready to use in PHP 7.0.7 and C#? (I don't worry that much about C#) One that is reasonably secure while not bloating my tiny texts to massive chunks of binary? I don't know if that is of any consequence, but if I use for example a 256 bit key, that's 32 bytes. If the street part of the address is shorter that 32 characters, will the encryption work? Will there be cumbersome padding involved?
All in all I feel that the security gain is minute compared to the measures I have to take in my php files as well as in the code for the front-end. The perceived security gain might be bigger ("Woha! They are saving our data encrypted! They sure know what they are doing!"). Having strict and restrictive privileges for certain types of users (for example revoke ´SELECT´ commands) should in all be more helpful, shouldn't it?
Edit for #Luke Joshua Park:
Thank you for your detailed answer.
I suppose by API server you mean the webserver my php's reside on? This indeed should be separate from the database server. Both servers are hosted within a university's network but can be accessed from the internet.
I can follow the authentication path to the point where every user from within the enterprise (small-ish project at said university, maybe a bad choice of wording) has a database user with sensibly set grants. But users from outside using the php only send data to be stored in the database (ideally with a common but seperate database-user with grants set accordingly), and never retreive (their own) data. Using authentication would mean they first had to create an account (which is not needed) and how do they authenticate themselves for creating the unwanted account?
It is good that you're asking these questions before implementing a solution, cryptography is difficult to get right and a sound understanding is required before you start.
I'll answer your questions quickly first, but the more important part is what follows.
Not really. See below.
Yes, in most cases, keys should be kept on the device they are created on, wherever possible.
Provided your API server(s) doesn't also have the database on it, relatively unlikely.
Yes.
Yes.
Yes. But don't base64 them. Wasted space and processing power for no benefit.
You're asking the wrong questions. An algorithm isn't "for" a language. You just need to pick the right algorithm/block mode/padding depending on your needs.
For the most part the questions you are asking are irrelevant. Believe it or not, your issue is more to do with authentication than it is to do with encryption.
The first thing you need to understand is that a server breach is a server breach. Bad stuff is going to happen regardless of how much cryptography you throw at it. But we can minimize damage where possible.
Your database software should be running on a separate server/instance/whatever from your API server. Encryption/decryption should only take place on your API server. This has the benefit that both your API server and database server would have to be breached in order to decrypt the data (to access the keys). How you store the keys on your API server isn't all that important provided they aren't in your webroot or something silly like that.
Everything past this is authentication. You need a strong authentication system to determine who can send you information and who can retrieve information from you. Communication to and from your API server should obviously be encrypted with TLS at all times. You might consider TLS client authentication as a way to ensure the entity requesting data from you is who they say they are. Usually client authentication can't really be used on the web, but if you're interacting with "enterprises" in a more private way, then client authentication is an excellent choice.
In summary:
Separate your API server from your database server. Encryption keys should only ever be on the API server. See this repository for a collection of encryption examples from PHP to just about any other language.
Use TLS for all ingoing and outgoing communication.
Focus on authentication. TLS Client authentication is a good option.
I'm working on a couple of projects that need to store user credentials for third-party applications, such as Paypal, Facebook developer creds etc. I've read a few books about different kinds of coding, including ASP.NET, WPF, jQuery, and all have nice examples on how to access the preceding services with own secrets, and also all of them use the exact phrase "in a real project you would store these in an encrypted file". None, however, give an example how to do so.
I have little (read: none) experience in encryption, but based on my understanding, I would need to encrypt a username and a password using some sort of key (salt?) and save them in a file. I would also want to be able to use these credentials on my apps so I would need to store the key (salt?) in my code.
Now my question is: How is it safer to store the decryption key, which is still plain text, in the program code, than the actual credentials?
Wouldn't the malicious user be able to decrypt my password-file as soon as he gets the key?
--EDIT--
I really mean my own credentials I need to store to log in to third party applications, not credentials of my users. For example I need to identify my self and/or my app to Google, so that users can log in to my app using their own Google account.
--EDIT 2--
To clarify, this is what I'm talking about. This screenshot is from asp.net PayPal tutorial:
Any quick pointers on good practises here?
You misunderstood the part about storing encrypted password* + salt: this is done when your system needs to validate someone else's credentials. In this situation storing password hash and the salt is more secure than storing the credentials, encrypted or not, because an attacker would have no way of getting the password back, even if he manages to get his hands on both the hash and the salt.
Storing decryption key in plain text is never a good option, because an attacker would get your users' passwords as soon as he gets access to the key.
There is no good solution to persisting your own credentials, encrypted or not. Your component that talks to 3-rd party services should use developer APIs from these providers. For example, PayPal provides two sets of APIs which you can use to access your account without having to store your password.
If you need to store a small amount of secret information in an encrypted form, use registry APIs to store the data in a key known to your application, and accessible from the user running your server-side component. This secret would be safe, as long as hackers do not hack the password for the account under which your service is running.
* Technically, password is not encrypted, it's hashed, i.e. there is no reliable way to turn the result of conversion back to the original value.
Your suspicions are correct. If the user has access to the key they can just go and decrypt the username and passwords themselves.
The two options you have are
Make it difficult enough to get the password that the reword of getting the password is not worth the effort to find it. This approach is done via things like Code Obfuscateors, I would not recommend this to someone starting out. Its not easy to get it right and it only takes one person who things it is "worth the effort" for it to break.
Don't give the user the information ever. Instead of storing the usernames and passwords in the program have your program call out to a server you own, then that server is what makes the request using the credentials. This approach is the more reliable one and is "unbreakable" (as long as your server is secure) but costs more because you now need to keep a server up and running that can handle the load of your entire userbase.
If I have a stored key file used to decrypt the encrypted input coming into my application, and I store that key file as an embedded resource so that it is embedded in the assembly when deploying, how difficult would it be for someone to reverse engineer the application and retrieve the key file?
Also, the application is deployed through ClickOnce "Online only" mode which I imagine would also make it more difficult to reverse engineer? (I'm not exactly sure of the workings of ClickOnce but I wasn't able to find the dll's/assemblies on my local machine after running the application in online only mode...).
Update:
As Ralf essentially answered the main question below in his comment (answer: it's not really safe at all), here's some more information so that you knowledgeable people can possibly suggest a better security model.
The encryption will be used to encrypt the login password for my application, to be used in a SSO setup (the user will first sign on to a different system and then by clicking a link will be able to directly open my application without having to enter in their login details).
The encrypted data will be sent as a base-64 string URL parameter in the link that will launch the my click-once application.
I will also be developing the application that will create the encrypted data for the URL parameter (clarification: not the first application the user will sign in to for the SSO, I will only be creating a small tool to convert the plain text password into an encrypted base64 string).
It's only an internal application so bullet proof security isn't essential and ease of deployment is more important, but it'd be nice to know what the best practices and different options that are available.
Whether in clear text or encrypted, you don't want to store the password. When you get a password, all you should do is pass it to your server app where you compare it against the salted hash of the password you have in the DB. Even if you don't think security is that important, you need to take care with the password because people frequently reuse passwords across different systems. I know they shouldn't but they do.
If you want to implement a single sign on (SSO), create a sign on token on the server side and pass it back to the client, either encrypted or signed (HMAC is a good choice for signing). This is an unforgeable token because you need to know the encryption key or shared secret for the HMAC and that data is only known on your servers. So you have your SSO and all data involving the SSO is managed on servers so there's no data leakage or chance of spoofing.
As long as the aplication can be launched, the files have to be somewhere on the computer. You just have to know where to look. The reverse-engineering may be ugly but it is always possible. The computer has to be able to understand what he is supposed to do so you only have to extraxt the information one is looking for. Therefore the security of your application should never depend on the difficulty of reverse-engineering! I believe that a secure application should be open-source anyways.
You propably need a diffent security model. The important thing here is that you know against what you want to protect the data. If you simply want that you know the data is sent by the server and not somebody else (man in the middle attack) you could use digital signatures instead.
If you do not want anybody to read any data sent between server and client you should use some sort of ssl implementation to create an encrypted channel. Then you only need to watch out that the public key of the server is not altered on the client. This may be done by an certificate of an official CA but unfortunately those are usualy not for free.
Here is what I am trying to do. I have an asp .net website in C#. I also have a game server and game both written in C++. The game server is hosted where the web site is.
What I want is for users to be able to automatically login to the website when they click a button in the game. That is, the game makes a request to the game server, and some how a token is generated that can be used to log into the website.
So the server might sendback something like:
www.contoso.com/tokenlogin?userid=67456353&token=576434324431fgdsastr
I'm aware that an easy solution to this is to just create a token in the database that the web site can read. If I cannot find a better solution, I'll do that, but ideally I would like to generate a token whereby for the next 5 minutes, passing this token with this userid will login that user as if they had passed their password.
A simple idea I had for this was to hash their password hash and username which would work, but this does not have a timestamp.
Does anyone have any suggestions for this? Can MySQL generate tokens that can be validated? I'm using MySQL. I don't mind a solution that uses the database, I just don't want a solution that writes to the database.
Thanks
Generating a random token and saving it to the database (with a timestamp) is definitely the easiest solution. Failing that (or another way of communicating between processes), what you can do is generate signed tokens in your server which can be validated by your web app. So your server would create a token like:
{userid: XXX, issueTime: YYY}
Then, you encrypt this data with an authenticated encryption method like GCM, base-64 encode it, and append it to the URL. Your web app decrypts and validates the data, and if the timestamp is ok logs the user in. This requires a shared key between the processes, which you must not lose.
Suppose someone gets access all of my hard disk, I guess the weak spot would be my windows password. Without knowing/being able to retrieve that, the data should be pretty much safe, shouldn't it?
I'm asking specifically because of the EFS entry in wikipedia which states that
In Windows 2000, the local administrator is the default Data Recovery Agent, capable of decrypting all files encrypted with EFS by any local user.
and EFS happens to use DPAPI. So does the same apply to my own data protected using this:
ProtectedData.Protect(plain, null, DataProtectionScope.CurrentUser);
And if that is indeed the case, how could I prevent it?
[Edit] N.B. I'm trying to store credentials for a winforms app so that the user does not have to enter their password every time they login. In other words, if someone is able to login as that user (i.e. know the user password), then they might as well be able read the encrypted data.
Which - not coming from a windows background - now makes me wonder - can't the local admin login as any local user anyway? In that case I shouldn't be concerned about the admin being able to retrieve passwords anyway...
[Edit2] As google reveals, it looks like an Administrator cannot just login as any user without resetting/changing their password first. So my question still seems relevant...
EFS uses DPAPI, not the other way around. And Administrator can't read your key just like that.
Before forgetting about DPAPI, I would consider the alternatives. If you encrypt the file yourself,
You must select a strong algorithm and implement it well.
You will need a key. Where will it be ?
You will store the key in a file somewhere on your drive.
That key is sensitive, obviously, you will want to encrypt it
Goto 1
DPAPI does 1 to 3 well. 4 and 5 are moot. If a Windows password is not enough to protect data, ask yourself why it is enough to CRUD that data in the first place.
For better security, you can consider not saving the data but a (salted) hash of it, if possible. It makes your data write only, though. For example, if you want to verify a customer license number :
Save a salted hash value of it
Run the same hash on the salted license number you want to verify,
Compare the two. It they match, the license is valid.
If you must read back encrypted data and a locally encrypted key is not enough, consider encrypting your application key (step 2 above) with a private key stored on a smart card.
Either way, remember that things happens. You always need a backup key somewhere.
See this article on DPAPI Security. Basically, it is as secure as your Windows password -- if your password is reset by an administrator, the decryption key will be lost. The major attack vectors you'll need to look at are:
Password disclosure: "shoulder surfing", sticky notes, etc.
Capture of the computer's accounts database and the use of a password cracker
Online attack by "drive-by download", removable media AutoPlay, etc.
Capture of a password reset disk, if you've made one
Physical installation of a key-logging device or other "bug"
DPAPI can be used both with and without optional entropy. There are only two ways DPAPI blobs without optional entropy can be compromised:
A domain admin can directly retrieve anyone's history of DPAPI master keys at any time. Nothing else is required. These can be used to decrypt all blobs. Local administrators cannot do this.
The user's Windows credentials are compromised.
If you use optional entropy then the data cannot be decrypted by anyone who doesnt know the value. The entropy may be derived from a password required to launch the application etc. Without the value, the data is lost forever.
EFS works differently. The user's key is protected using DPAPI for his profile, but the decryption key for the file itself is additionally directly encrypted with the administrator's public key as well. Therefore a domain admin can access the files.