I would like to use PouchDB in a web app desktop client. I work in an environment where the computer user is generic and different persons use the same computer account. However, using my app they must log in with individual user names granting them their corresponding privileges. The system works offline, with period replication to the server.
Browsing through the documentation of PouchDB and searching the Internet I come to understand that there is no access restriction to a local PouchDB. Anyone who has access to the client/browser has in principle access to the cached data. Also implementing any sort of user access control in my web app seems to be kind of pointless. The code could simply be altered to allow access.
I came to the following possible solution and would like to know if that could work:
First contact with the central server
App sends user credentials to the server. The server encrypts a special databaseKey with the user credentials and sends this encryptedDatabaseKey back to the client app. The client app stores this encryptedDatabaseKey in localStorage, decrypts the contained databaseKey, creates and encrypts the local PouchDB using this databaseKey (e. g. crypto-pouch).
Offline usage
User logs into the app, his credentials are used to decrypt the encryptedDatabaseKey in localStorage, only then has he access to the stored data. If someone alters the code of the app he still cannot gain access to the encrypted PouchDB.
I see the following advantages:
- Without correct credentials there is no access to the local data
- Multiple users can have access to same local PouchDB since the databaseKey is identical.
- The databaseKey could even be changed regularly (app compares during a connection to the server the local encryptedDatabaseKey and the one received from the server, if they differ the app decrypts the database using the old key and encrypts it with the new)
Does this seem like a viable solution? Are there any other/better methods of securing a local PouchDB?
crypto-pouch is indeed the best method to encrypt a local PouchDB. However, I think where you say
Offline usage User logs into the app, his credentials are used to decrypt the encryptedDatabaseKey in localStorage, only then has he access to the stored data
I think it's pointless to decrypt the key and use that to decrypt the database; you might as well just as the user to create and memorize a password? Then you can use that as the key to the crypto-pouch.
Related
Context: I have a client app (a compiled NodeJS app that can run on Windows, Mac, Linux), in which I authenticate the user via the browser, and then store the authentication token (JWT, typically valid for a few hours) in a file ~/.myapp/auth-token. This is to avoid having to log the user in each time they launch the app. When the app launches, it checks this file and if the JWT is still good, it uses it (and refreshes it) without prompting the user to sign in again.
Question: How can I secure this file, such that only my app can read from it and write to it? Or, more broadly, how I can store my app secrets (in file or any other OS provided mechanism) and prevent them from being scooped up by other applications?
Generally, how do client apps store secrets, securely?
Chrome, for example, stores cookies, passwords, credit cards, and other sensitive information. What stops another application running on my Windows or Mac machine from reading the file where this data is stored?
If the data is encrypted, where's the cert or key for it stored, and how is it enforced that only the owning application, i.e. Chrome, can access the key? Are there OS-level utilities across Windows, Mac, Linux, that somehow authenticate apps and facilitate secure storage of secrets, keys, cert per app?
Background
I've been out of the web app development realm for a few years and I've recently come back into it. There are a few questions I have about best security practices for performing the following tasks.
I'm developing an electron (node.js) application that will authenticate user credentials using my remote application server. On my server I have a MySQL database which will store the usual assortment of user account and application data. Additionally, the electron application will have a local sqlite database that I will periodically be updated to keep things in sync with the remote MySQL server. The Sqlite database is there to allow the application to continue to function should the electron app be used in an offline environment or in case the remote server goes down. I intend the application to be online first with an offline fallback.
Once the user authenticates in the electron app, the application will allow the user to do their work, and when the user is done, their work will be submitted to a 3rd party by posting that work to the 3rd party's API. The first time a user logs in, they will be asked to authenticate with the 3rd party API using OAuth2 and an api access token will be given by the 3rd party upon successful completion of this authentication procedure. This token will be stored in the remote MySQL database as well as the local sqlite database.
Here's the kicker. There will be multiple machines running this electron application so keeping everything in sync between all of these installations is a necessity as the same user may be using any one of these machines on a given day.
The Questions
With the background information out of the way, here are my questions:
If I hash and salt user passwords prior to storing them in the database: is SHA-512 still a secure hash, or is there another algorithm that is better?
The 3rd party API token is essentially the user's password to accessing the 3rd party API. I intend to treat it as such and give it the same treatment as I would a password. Since hashing is one-way and therefore not an option, how could I best encrypt the API token for storage in the database? My current thought is to use AES with a long randomly generated string that is stored in my server application's configuration file as the secret key. In this case, if the database is breached, the secret key would not be included with the data. To acquire the secret key the server itself would have to be broken into. Is this the best way of going about this?
Upon application startup or when manually triggered, the local electron app will query my remote server to determine if there has been any changes to the database since the local sqlite database was last updated. If there are changes and a local update is needed, the remote server will send back a response with all the things that have changed (probably in a JSON format) since the last update. The connection between the local application and the remote server will be encrypted using TLS (https). Is this sufficient to protect the data exchange (which contains password hashes and the like) between the local application and the remote server or should the JSON object be further encrypted? Is this even a good way to go about syncing data?
I appreciate any and all help. I'm a bit out of touch with some of the current best practices, and this is my first actual production application in a long while, so I want to make sure things are done properly.
I've read several Stack Overflow threads, I still can't decide what is the best option for my case. And the most secure one.
Here is the story. My webapp is to help users automatically get an overview of some of their data available in some third-party website. I need to store for each user some third-party credentials. Each night or so, my server will connect to the third-party services on the users' behalf and retrieve the required data.
Most of those third-party sites do not implement any API or OAuth mechanism, so I was thinking to do some web scraping.
I've read in many places that storing the credentials in the DB is not a good idea - especially because my app needs access to the password (so it has to be encrypted in such a way I can easily reuse it).
So, I have two options left:
Whenever I access (via webscraping) the third-party service, I store on the server the cookies issued by that service, for future reuse. I encrypt them and keep them encrypted in a DB, and decrypt them only when I need them. The problem is that the cookie can be denied or expired after a while, and so the automatic process wouldn't work any more.
I store the credentials in the environment variables. I will be on Node.js and Heroku. That's an idea I found in another SO thread. But I'm wondering about the security of this idea. Is it really safe? No one can access them but me? And what about if I reach many users. Like 1000 users, with 10 services. That's 10000 credentials to store in the env variables. That doesn't seem like a good idea.
I found two interesting questions on Stack Overflow but they don't fit 100% with my use case.
Security model: log in to third-party site with user's credentials (that gave me the idea in point 1)
Rails storing third party credentials.. Anyone know best practice? (gave me the idea in point 2).
I add another answer because maybe this one will do the trick for you.
You said the main goal of your website is to have an overview of third party applications. But what if instead of updating this overview every night, you update it when the user logs in ? It changes everything, because you could use the user's password (of your website) as master password to encrypt (using AES) all the others.
If you do that, the communications between your server and the clients have to be encrypted with SSL pinning, because an attacker could perform a MITM, get the master password and all the others stored in the DB... (Even if in practice it's very hard because you need to hack the client AND the server)
Storing a lot of data that changes and grows in environment variables will never be practical, no matter if it's secure or not so this is pretty much out of the question, unless if you have a small fixed number of users.
Not storing credentials in the database is a very good advice, but the cookies are credentials and even if you store them encrypted, your app needs to be able to encrypt it to use it. (This is unlike the situation with verifying passwords of your users when you don't need to ever encrypt them, you only need to see if the provided passwords hash to the same values that you have stored).
This is a hard problem because to make it work you need to have some form of credentials (whether those are passwords or cookies) stored and ready to be used unencrypted (even if they are stored encrypted, you need to store the keys to encrypt it as well).
Also, what you are trying to do can be illegal. Mayke sure that you follow the TOC of every service that you're using or otherwise you may face legal trouble.
Plan for the attacker gaining admin access to the server. Your site will be very attractive to attackers, kind of a one-stop-shop for user credentials so you will need very good security of the login credentials.
There are more than two options for storing the credentials:
Use an HSM for the storage or individual credential encryption keys.
Keep the credentials on another dedicated server with no Internet access, 2-factor authentication and limit admin personal. Rate limit the access to this server and add rate alarms. Access this server on a per user credential basis over a non-Internet connection. The credentials will only be available to the Internet connected server in memory as used, not at-rest in a file.
Storing users credentials in a reversible way looks like a terrible idea anyway. But if you really want to store them, I suggest you to use the environment variables solution. But you can improve it. To limit the amount of data you store and don't have 1000000 variables as you said, you can just store an AES encryption key, store all credentials in a DB encrypted with this key, and you just have to get this key (which is in memory) and decrypt the DB. But there is another problem with this solution. As I said, this is stored in RAM memory, so it's not persistent, imagine your server has to reboot for X or Y reason... You will lose the AES key and also the credentials of your users... Moreover, if the attacker performs a memory dump, he will have access to the AES key...
I think the better idea is to store the cookies (in an encrypted way) and when this one expires, you alert the user (by mail, phone, notifications, ...) and ask him to fill his credentials again. But it's not a perfect solution ! Indeed the cookies are a type of credentials and shouldn't be stored either...
I want do develop simple web app using Node.js (MEAN.io Fullstack). I am using Passport as authentication middleware. I especially want that on my app users can login with Twitter account.
Are my API key and API secret that i define in config/production.js file "secure". Can someone see their value and misuse them ?
They are as secure as your server is. If someone breaks into your server, then it has full access to the source code and also the API keys.
If you trust your code to store passwords for databases, salts (e.g. for session cookies), etc, then you can trust it also for your API keys.
Please note that it's pretty standard to store API keys inside source/config files (in a non-publicly accessible folder - as would "public/" be, for example).
I have a Silverlight 3 app which connects to a server to perform various actions. My users log in using Forms Authentication but the actions they request are run on the server using the AppPool account so when they go in the audit logs they're recorded against the AppPool account. PCI DSS regulations now require that the user's own ID is in the audit logs which means the action must be taken using the user's creds. Now, I can save the user's creds when they log on and submit them with each request and the actions being taken by the server can use those creds. But the PCI regs say that if creds are saved they must be encrypted (to avoid someone taking a memory dump of the PC and getting the password).
The only way I can see of doing this is to get a public key from the server and encrypt the password with it, then submit the encrypted password and decrypt it on the server using the private key. But Silverlight doesn't have asymmetric cryptography.
I guess I'm too close to the problem and there must be another solution but I can't see what it is. Can anyone help?
CLARIFICATIONS
It's an internal application. Up until now, I've been using IIS Forms AuthN over SSL to Active Directory - I'm not worried about protecting the password in transit, just whilst it's held in memory on the client. As I understand it, because I'm using Forms Authentication, impersonation is not possible on the server unless I use LogonUser, which means I need the password on the server, so I need to transmit it each time, so I need to hold it in the client, in memory, until the app closes.
Are you saying you need to store the password for re-use in the silverlight app? If you are concerned about the password appearing in memory un-encrypted then Silverlight then I think you're in trouble.
The .NET framework does have a SecureString class for exact purpose you outline.
Unfortunately the Silverlight version of the framework does not have this class. Hence even if you were to keep the logical storage of the password encrypted at some point your code would need to decrypt it before using it. At the point there is memory allocated containing the string in unencrypted form.
I don't know much about Forms authentication but if you can map the User principle to a domain user (which you seem to indicate you need) then you will want to use impersonation when running your code on the server.
Alternatively stop using Forms authentication and use Windows integrated authentication where you definitely can use impersonation server-side.
Encryption should never be used for passwords. When you encrypt something then it follows there should be a way to decrypt it. One way hashes should always be used for passwords. md5 and sha1 have been proven to be far too weak for any secuirty system.
Sha256 should be used, and in silverlight this library will take care of it:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.sha256%28VS.95%29.aspx
In fact storing passwords using "encryption" is recognized by the vulnerability family CWE-257. The use of a message digest is the ONLY way to safely store passwords. I didn't just make this up, this is coming from NIST. There are many other vulnerabilities that come up when storing passwords. Here is THE LIST that NIST has put together: