Securly Storing OpenID identifiers and OAuth tokens - database

I am creating a web app that will use OpenID logins and OAuth tokens with Youtube. I am currently storing the OpenID identity and OAuth token/token secret in plain text in the database.
Is it inappropriate to store these values as plain text? I could use a one-way encryption for the OpenID identifier but I don't know if that is necessary. For the OAuth tokens, I would need to use a two-way encryption as my app relies on getting the session token for some uses.
Is it necessary to encrypt the OpenID identity? Could someone use it to gain access to a user's account?

First, there is a registered application that has consumer_key and consumer_secret.
When users authenticate and "allow" your registered application, you get back:
an access_token that is considered the user's "password" and would allow JUST YOUR application to act on the user's behalf.
So, getting just the user's access_token from your database won't help much if they don't also have the consumer_key and consumer_secret for complete access.
The service provider compares all 4 parameters on request. It would be smart to encrypt these 4 parameters before storage and decrypt them before response.
This is just when you need to update or make changes to the user's resource owner on behalf of a user. To keep a user logged-in on your site, use sessions.

The OAuth Token and Secret should both obviously be kept safe in your database, but you can't store them using 1 way encryption the same way you would for a password. The reason being is that you need the token and secret to be able to sign the request.
This would also be the case if you are running an OAuth server, you still need the original token/secret to verify the request.
If you want to you could still encrypt them using a 2 way encryption algorithm such as AES to offer security in case your database or database backups get compromised.

There's two schools of thought here.
The first argument is that: you should treat OAuth tokens like passwords. If anyone were to access your database, obtain all the OpenID/OAuth pairs and run an man-in-the-middle attack, they could impersonate any user on your site.
The second argument is this: by the time someone has access to your database and sufficient access to your network to run an man-in-the-middle attack, you're hosed anyway.
I'd personally err on the side of caution and just encrypt them; it's a standard practice for passwords, so you might as well give yourself just that little extra peace of mind.
Meanwhile, Google has this advice:
"Tokens should be treated as securely as any other sensitive information stored on the server."
source: http://code.google.com/apis/accounts/docs/OAuth.html
And some random guy on the web has specific implementation advice:
If they’re on a regular disk file, protect them using filesystem
permissions, make sure that they’re
encrypted, and hide the password well
If they’re in a database, encrypt the fields, store the key
well, and protect access to the
database itself carefully. *
If they’re in LDAP, do the same.
archived post (original post URL, now a dead link)

OpenID URL shouldn't be encrypted because this is your "open id" literally, everyone should know the value. Besides, the URL needs to be an index in the database and it's always problematic to encrypt the index in the database.
OAuth token/secret should be secret and encryption may improve security if you have to store the token long term. In our OAuth consumer application, token/secret is only stored in session for a short while and we choose not to encrypt them. I think that's secure enough. If someone can peek into our session storage, they probably have our encryption key also.

Yes, these should be symmetrically encrypted (say, AES-256 in CBC mode) at rest in a database. A simple way to encrypt these tokens is using SecureDB's Encryption as a Service RESTful APIs.
Disclosure: I work at SecureDB.

Related

Is there a secure way to store data like login credentials on client-side?

I am using React JS, and I would like to store user's login credentials on client's browser so they don't have to enter email and password each time.
How can I securely store user's login credentials in the browser?
Define securely. If your definition is like "no one beside the user can use the credentials to access the application" then forget it. No technical or technological mean can make it happen. The definition is simply to broad, and if the attack models include the attacker having access to your user agent (browser) or physical access to your device, then the solution gets hopeless pretty quick.
Think encryption can help? You have encrypted the payload using some key. Now you have to protect the key. Encryption does not solve your problem. It just shifts it somewhere else. All security through obscurity solutions use stuff like this.
We usually define security of passing secrets as something that requires us to be protected from the remote attacker. Someone who has the access to the wire and can sniff the traffic, someone who may have access to some of the remote machines you are communicating with. This makes the problem solvable at least to some degree. It allows you to use either well configured cookies or local web storage to use it as cache.
Having said that - storing credentials is usually considered bad practice anyway. You may store your refresh tokens, you may store your session id, but you should not store your users credentials in anything else but a password manager. Refresh tokens and session ids will expire on its own and does not reveal anything about the user when they do.
To better understand what is allowed and disallowed when designing your solution please have a look into OWASP ASVS.
Even if there are many replies on the same subject for numerous queries, I wanted to share my ideas nonetheless.
It is impossible to completely safeguard data saved on local storage and it is a bad practice to save user credentials on localStorage , as #Marek pointed out in the prior response, but we can make it difficult for people to crack it.
Encryption is one of the solutions in this case, but it is still insufficient to secure local storage if you just encrypt the data and store it there using a shared or application-specific encryption key.
Here is why.
Consider the following scenario: you’ve encrypted the user’s login information and saved it locally. When you reload the platform, you’re decrypting the data that’s been written to local storage and marking the user as logged in or logged out. Your website and the platform use a single secure key to encrypt and decrypt, which means only your website knows how to decrypt.
If someone copies data from local storage and pastes it into a separate browser, then visits your site, your website will authenticate the user. Why?
because your website understands how to decode data!
then, what can we do?
It is preferable to generate a special encryption key that is only known by each browser and use that key to encrypt the data.
One method is to utilise the react-secure-storage package, which generates a special encryption key known only to the browser being used.
Here is how to use it:
yarn add react-secure-storage
npm install react-secure-storage
Sample code
import { useEffect } from "react";
import secureLocalStorage from "react-secure-storage";
const App = () => {
useEffect(() => {
secureLocalStorage.setItem("object", {
message: "This is testing of local storage",
});
secureLocalStorage.setItem("number", 12);
secureLocalStorage.setItem("string", "12");
secureLocalStorage.setItem("boolean", true);
let value = secureLocalStorage.getItem("boolean");
}, []);
return (
<div>
This is a sample code
</div>
);
}
export default App;

How to Secure tokens when storing on the Client side?

We have a system that connects our user to 2-3 third party applications. So, we usually store the tokens to be used for these applications for the user in the client side. When we make an API call to our server (our server is maintained by us), we also send the tokens to the backend, where it will be used to make API calls to these applications. Now, We're not using a Database, so We cannot store these tokens on the server side and hold a session token.
What are the best possible ways to hold the token on the client side? Is it safe to hold them as they are in the Cookies?
Keeping them open did not look fairly safe to us, so we're planing to add AES encryption to them, and whenever they are sent to the server, they are decrypted and used for API calls.
Is this the best approach we can continue while keeping our tokens secure? Or is there another better way to approach this issue?
If the client does not need to use that token and is only expected to forward it to the server for authentication with the 3rd party I think it is definitely a good idea to encrypt it. This way, an eventually compromised encrypted token cannot be used to make requests to the 3rd party.
Cookies should be a safe place to store these tokens as long as you make sure you enable the Secure and HttpOnly attributes on them (more about restricting access to cookies). In a nutshell, you prevent cookies from traveling through unencrypted channels (reducing the risk to suffer man-in-the-middle attacks) and from being accessed from the Javascript (which prevents your cookie from being accessible by an XSS attack on your client).

How to sync user password between 3 different services when they are hashed in different point of time?

I have 3 microservices that hold particular user information including their sign-in credentials (email + password). If the services are A, B, and C then the user "John" will have his info stored separately in all three of these services' database.
Now, the user info in service A is updated at an earlier point of time, and at that moment it is not predictable whether services B or C will definitely be activated to be used by that particular user. So, there is no point in creating an entry in B and C for "John". But, as "John" activates B or C at a later point of time, the system can only have access to the hashed password.
It is to be noted that the service C requires the password to be stored in encrypted form so that it can be decrypted later. So, merely storing the hashed value in all 3 services is not feasible, neither do we want all 3 of them to have encrypted password.
What is a feasible solution to sync the password between the services by maintaining the requirements?
Your approach implies a lot of problems in addition to the one you already described yourself. I recommend to look into Federated Identity (using OAuth2 and OpenID Connect) which fits for Microservices architectures.
Basically, this means that authentication and credentials handling is performed by a separate highly available and scalable service (usually referred to as identity provider or authorization server) that only does that - handling user credentials, identity and access control - and does it well.
It handles login and issues access tokens which are then sent to your Microservices along with the requests. As each Microservice will trust this identity provider it will be able to verify that the token is valid and was issued by this identity provider (this happens by validating the token with a public key). And the token contains information like user id and information about what actions are allowed with this token.
The identity provider can be a cloud service like Okta, Auth0, Azure AD B2C, etc. (see https://openid.net/developers/certified/#OPServices) or host an identity provider on your own, if you are not able to access cloud services, by using ready-to-use libraries available for your technology stack (https://openid.net/developers/certified/#OPLibs).
So there is no need to store user credentials in each Microservice and sync this information between them. I would consider such an approach as an anti-pattern.
The federated authentication approach also allows to solve other problems such as single-sign-on.
If you are new to that topic it can be a little overwhelming at first but it's something you can't get around if you really want to have all the advantages a Microservices architecture can provide.
This article might help you get started:
https://nordicapis.com/how-to-control-user-identity-within-microservices/

Where to Store sensitive data/information

I have a Two Factor Authentication system where I need to store the Auto generated Code and the requested time in some form storage for retrieving it later purpose. I need to know what is the best way to store these sensitive information.
I was planning to use Session to store those sensitive information. When I googled, In some places people are telling its not recommended to use session to store sensitive information. Can any body explain why so.
Any suggestion to this will be highly appreciated.
Thanks
In your user database is fine, it's a web app so the database should be completely hidden from end users (if properly managed).
The rest is just making sure your actual application is secure -- ie no SQL injections, no buffer overflows, proper workflows that all pass through your server side authentication engine etc.
If you are worried about your information they should be encrypted before store them in database, for more secure propose you can use HSM (Hardware security module) to do encryption and decryption for you or even you can rely on OTP (one-time password) for two factor authentication.

Google apps applications talk to each other

I am looking for a way for two Google Apps applications to talk to each other and share data between each other. I have the following scenario:
Application A logs user in using Google Apps login
Application B logs user in using Google Apps login
then these applications need to communicate directly to each other (server-to-server) using some APIs
The question is: how do these applications verify that the other one is logged in with the same user to Google? I would imagine something like:
- Application A gets some 'token' from Google and sends it to Application B
- Application B verifies that this token is valid for the same Google account as it is logged in with
Is there a way to accomplish that via Google Federated Login? I am talking about Hybrid protocol here.
Here's a simple way to do it:
You keep everything keyed to the user's Google userid on both applications.
You share the data using HTTP requests that contain the userid.
To prevent leaking of the userids (forbidden by the account API) and to verify the messages really come from the other application, you encrypt the requests with a symmetric cipher such as AES or Blowfish or whatever you like. Both applications have the same key embedded.
You could public key cryptography. With just two applications, it's not worth it in my opinion. If you start having more apps, public key makes sense.
The fine print: encryption does not guarantee integrity or origin without additional measures. You need to take precautions against playback, for example by incorporating a time-stamp or sequence number. You need to take precautions against tampering, e.g. with a checksum. Make sure to use CBC and good initialization vectors. Keep the key secret.
user.user_id() is always the same across all the apps for the same user. So you can simply compare values returned by user.user_id(). Is this what you are looking for?
Note: Every user has the same user ID
for all App Engine applications. If
your app uses the user ID in public
data, such as by including it in a URL
parameter, you should use a hash
algorithm with a "salt" value added to
obscure the ID. Exposing raw IDs could
allow someone to associate a user's
activity in one app with that in
another, or get the user's email
address by coercing the user to sign
in to another app.
From docs

Resources