1st off: thanks for the awesome Plugin!
I am using the Plugin with my portable KeePass on a USB drive which is attached to my keychain.
I am not too familiar with how the Google (Drive) API / OAuth credentials / scopes work. But it seems to lack a functionality to view precisely what scopes have been grated.
I also have not found the source code to this plugin and thus cannot verify what the Plugin requests.
I am a little worried now that the credentials that are visible in the KeePass config on my USB drive might give an attacker full access to my Google Drive when I lose my keychain or do not notice someone snooping around when I leave my drive out of sight.
Anyone have a little more insight into this issue?
Last edit: Uranium235 2014-10-21
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Found the source code. Thought I'd share my newly found "insight":
It seems that the Plugin does request full access to the Drive API.
Google says: best practice would be to only request the scopes really necessary and incrementally.
Then again, the Plugin does have access to the Google Account password anyway...
What was worrying me was that even though I have configured the Plugin to show the Authentication Form, it only did so once when I had to enter the TOTP from Google Authenticator.
But it seems that the Plugin still has to authenticate with the password every time (the Plugin is loaded) though, just not with the TOPT anymore. I did not know that. (The refresh token is not persistent afaict)
I initially tried using an App-Specific password, btw. But that did not work.
Since I see no Cookie or the like authorizing the App / Plugin to not be asked about the TOTP, I thought the OATH credential alone would suffice to access the Drive API after initial authorization without the need for the password.
Google does not disclose what "Other registered computers" I have... but I suspect this plugin would not be listed there anyway.
Could it be that the login process is so quick that I do not see the Form?
If that is the case, losing my OATH credentials would not be such a big deal after all, since there is still the password needed that is (hopefully) still protected.
Anyway, interesting to know that the 2nd factor is only ever needed once with OATH. I have not read anything about that at Google so far.
Sad to see that I have no control / oversight in my Google Account to see what Apps are authorized to login into my account without the 2nd factor...
Last edit: Uranium235 2014-10-17
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
There is indeed a considerable security risk involved with using this Plugin. (If you use KeePass with this plugin on untrusted / public computers)
After some tests, I found out that it is NOT the case that the "login process is so quick that I do not see the Form" nor that "The refresh token is not persistent afaict".
What actually happens is, that once you authenticate the Plugin with OAuth and possibly your OTP (2nd Factor), the returned refresh token together with the easily accessible OAuth info in the KeePass main config (GoogleSyncClientID and GoogleSyncClientSecret) is enough to gain full access to the Google Drive without the Google Account Password or OTP.
This refresh token is then saved in the Plugin's own configuration file by KeePass. Took me a while to figure out where exactly KeePass stores those:
The token is obfuscated with the memory protection scheme from KeePass, but that is just a simple XOR with a fixed, hard coded key that can easily be reversed.
So if you use this Plugin in portable mode on an untrusted machine, that refresh token is compromised regardless of whether KeePass is using a global config or not.
But this problem is not limited to untrusted machines, I guess. The same applies to your local installation if an attacker - online or offline - has access to it.
To quote the Google docs: "Note: Save refresh tokens in secure long-term storage and continue to use them as long as they remain valid."
I guess the way the refresh token is saved now, that does not qualify as secure long-term storage.
So, in essence, if you use this Plugin, anyone with access to the machine where it was used can (together with your KeePass config file) gain full access (not just the encrypted KeePass database) to your Google Drive without your password.
Thus using this Plugin in portable mode is NOT a good idea at all. I would even go as far as saying it is a considerable risk to use this Plugin with your local KeePass installation if multiple people have access to it - and that is more often the case than not, I would argue.
Since it would be a hassle to have to enter a OTP every time the Plugin is loaded, using an App-Specific Password is not possible and disabling 2-Factor authentication for the Google account not ideal either, I guess the only options are to either save the token in the database itself (e.g. as a String field with the associated Google Account entry) or encrypt it with a (random) secret stored inside the database.
And while we're at it, the GoogleSyncClientID and GoogleSyncClientSecret should better also move inside the database or be encrypted.
Since KeePass is not all that friendly to using it in portable mode configuration wise (esp. when the local user also uses his own KeePass), I would opt for storing inside the database.
The only drawback I see would be that the db needs to be altered and saved (and synced) when a new refresh token gets issued. And that should only happen once or if the user intentionally revokes the access granted.
tl;dr - here is what I would recommend:
Move the GoogleSyncClientID and GoogleSyncClientSecret inside the database as a protected String field to the entry associated with GoogleSyncKeePassUID (The Google Account Password entry).
(Have the Plugin ask for those on first use when not present.)
Instead save the obtained refresh token in that same db entry (as a protected String field "GoogleSyncRefreshToken") and only update when in fact different after initial / new / forced authentication to not unnecessarily alter the database.
Remove the setting GoogleSyncShowAuthenticationForm as it is obsolete and should always be true since it only shows once on initial authorization anyway and in fact should be visible then imho (auto filling in of the username and password should remain though).
Rename the setting "EnableAutoSync" to "GoogleSyncEnableAutoSync". ;)
Last edit: Uranium235 2014-10-26
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks for posting your detailed findings as well as solution :) Really appreciate your help!
However, for a normal user, your post from few days ago can be quite frightening unless they read the whole thing. If you can, I would ask to add under your bold line
There is indeed a considerable security risk involved with using this Plugin. (If you use Portable KeePass with this plugin on untrusted / public computers)
You do point out this somewhere down if the computer is being used by multiple people :)
However, I would like to understand a little further how it's not a security risk if user was to install KeePass on an untrusted / public computer. The underlying issue seems to be the token being stored under AppData - whether it's portable or installed wouldn't matter - I think.
An alternate solution could have been to simply delete that user.config file either on KeePass exit or informing the user to delete it themselves when they are done using an unsecure computer.
But I like your solution a lot better of keeping everything inside KeePass database.
I have uploaded the source code and added you as a developer. I would really appreciate if you could upload the changes there as well as updating the readme.txt and Sample-KeePass.config.xml file.
Please let me know if you can do it. If not, I will try to merge your changes - hopefully in the next few days.
Once again, thank you for contributing!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Once an application has been granted access to the Google Drive API by the user, all the application needs thereafter to access the API is three things:
The OAuth Client ID
The OAuth Client Secret
The OAuth Refresh Token (obtained after successful user consent)
No further need for the password or user consent dialogue.
Anyone that knows these three things has the same access rights to the Google Drive as the original application. In this case the Plugin has full Google Drive access.
The old Plugin stored all three things unprotected. The Refresh Token was obfuscated, but as I pointed out above, that is in effect the same as storing it plain text.
Here are possible ways an attack might work:
I use the KeePass on my USB drive at work where other people also have access to the computer
I close the database and KeePass after I have used it but leave the USB Drive in the computer because I think the database is locked anyway and nothing can happen
I leave the computer to have lunch and forget to take my USB drive with me
My evil co-worker finds that USB drive and copies himself my keepass.config.xml as well as the user.config for the Plugin
He now has full access to my Google Drive without me knowing (not via the Webinterface, but via the API - which is pretty much the same thing with a little know-how)
In that same scenario I could have just installed KeePass locally - no need for the USB Drive. Same thing at home with e.g. evil flat mates. Or, if my system is infected with a Virus / Malware / Bot, the attacker can simply copy those files and be anywhere on this planet. Of course you have a much bigger problem in that last case, but the old way makes it really easy. And there are already Bots out there that routinely copy those interesting files (like unprotected Browser / Mail client password databases).
Deleting that user.config file would mean that the Plugin itself has no more access to the Google Drive and needs user authentication again. That might be done (semi-) automatic as the Plugin has access to the password, but it is not the way Google intended this process to work. User consent should always be done by the user in person. Once you get a Refresh Token, Google says you should keep it safe and re-use it as long as possible.
I think I can get around to updating the code, sample and readme tomorrow.
Last edit: Uranium235 2014-10-26
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Select KeePasPlugin (might be misspelled as KeyPassPlugin) and then click on Revoke Access
In KeePass, click menu Help > About KeePass to find the KeePass version.
Exit and close KeePass
Copy and backup folder C:\Users[User]\AppData\Local\Dominik_Reichl somewhere safe
Browse to C:\Users[User]\AppData\Local\Dominik_Reichl\KeePass.exe_StrongName_[*][KeePass-version]
Open user.config
Look for a tag called sectionGroup
Do you only have one section inside, named section name="GoogleSyncPlugin.Properties.Settings"
Yes, I only have one section
Close user.config
Delete user.config
No, I have other sections in there as well
Delete the entire section with name = GoogleSyncPlugin.Properties.Settings. See example below.
Delete the entire setting GoogleSyncPlugin.Properties.Settings under userSettings. See example below.
Save
Restart KeePass and do a sync again using the plugin. This should prompt you with a consent popup from Google. The sync will start working again once you accept the consent.
This will also recreate the KeePass folder under C:\Users[User]\AppData\Local\Dominik_Reichl, giving you a fresh new token from Google.
It should be noted that the problem is not fixed in release version 1.6 yet.
A version 2.0, which will not be compatible with the old version in terms of the configuration, will probably be released very soon.
A similar process as above - to be on the safe side - will be needed too. There will be separate instructions for upgrading though.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi,
1st off: thanks for the awesome Plugin!
I am using the Plugin with my portable KeePass on a USB drive which is attached to my keychain.
I am not too familiar with how the Google (Drive) API / OAuth credentials / scopes work. But it seems to lack a functionality to view precisely what scopes have been grated.
I also have not found the source code to this plugin and thus cannot verify what the Plugin requests.
I am a little worried now that the credentials that are visible in the KeePass config on my USB drive might give an attacker full access to my Google Drive when I lose my keychain or do not notice someone snooping around when I leave my drive out of sight.
Anyone have a little more insight into this issue?
Last edit: Uranium235 2014-10-21
Found the source code. Thought I'd share my newly found "insight":
It seems that the Plugin does request full access to the Drive API.
Google says: best practice would be to only request the scopes really necessary and incrementally.
Then again, the Plugin does have access to the Google Account password anyway...
What was worrying me was that even though I have configured the Plugin to show the Authentication Form, it only did so once when I had to enter the TOTP from Google Authenticator.
But it seems that the Plugin still has to authenticate with the password every time (the Plugin is loaded) though, just not with the TOPT anymore. I did not know that. (The refresh token is not persistent afaict)
I initially tried using an App-Specific password, btw. But that did not work.
Since I see no Cookie or the like authorizing the App / Plugin to not be asked about the TOTP, I thought the OATH credential alone would suffice to access the Drive API after initial authorization without the need for the password.
Google does not disclose what "Other registered computers" I have... but I suspect this plugin would not be listed there anyway.
Could it be that the login process is so quick that I do not see the Form?
If that is the case, losing my OATH credentials would not be such a big deal after all, since there is still the password needed that is (hopefully) still protected.
Anyway, interesting to know that the 2nd factor is only ever needed once with OATH. I have not read anything about that at Google so far.
Sad to see that I have no control / oversight in my Google Account to see what Apps are authorized to login into my account without the 2nd factor...
Last edit: Uranium235 2014-10-17
Well, I was wrong - or right in the first place.
There is indeed a considerable security risk involved with using this Plugin.
(If you use KeePass with this plugin on untrusted / public computers)
After some tests, I found out that it is NOT the case that the "login process is so quick that I do not see the Form" nor that "The refresh token is not persistent afaict".
What actually happens is, that once you authenticate the Plugin with OAuth and possibly your OTP (2nd Factor), the returned refresh token together with the easily accessible OAuth info in the KeePass main config (GoogleSyncClientID and GoogleSyncClientSecret) is enough to gain full access to the Google Drive without the Google Account Password or OTP.
This refresh token is then saved in the Plugin's own configuration file by KeePass. Took me a while to figure out where exactly KeePass stores those:
C:\Users\[User]\AppData\Local\Dominik_Reichl\KeePass.exe_StrongName_xzynbbjhsmtgnkfkag4h4gilrsbrudqj\2.28.0.29696\user.config
The token is obfuscated with the memory protection scheme from KeePass, but that is just a simple XOR with a fixed, hard coded key that can easily be reversed.
So if you use this Plugin in portable mode on an untrusted machine, that refresh token is compromised regardless of whether KeePass is using a global config or not.
But this problem is not limited to untrusted machines, I guess. The same applies to your local installation if an attacker - online or offline - has access to it.
To quote the Google docs:
"Note: Save refresh tokens in secure long-term storage and continue to use them as long as they remain valid."
I guess the way the refresh token is saved now, that does not qualify as secure long-term storage.
So, in essence, if you use this Plugin, anyone with access to the machine where it was used can (together with your KeePass config file) gain full access (not just the encrypted KeePass database) to your Google Drive without your password.
Thus using this Plugin in portable mode is NOT a good idea at all. I would even go as far as saying it is a considerable risk to use this Plugin with your local KeePass installation if multiple people have access to it - and that is more often the case than not, I would argue.
Since it would be a hassle to have to enter a OTP every time the Plugin is loaded, using an App-Specific Password is not possible and disabling 2-Factor authentication for the Google account not ideal either, I guess the only options are to either save the token in the database itself (e.g. as a String field with the associated Google Account entry) or encrypt it with a (random) secret stored inside the database.
And while we're at it, the GoogleSyncClientID and GoogleSyncClientSecret should better also move inside the database or be encrypted.
Since KeePass is not all that friendly to using it in portable mode configuration wise (esp. when the local user also uses his own KeePass), I would opt for storing inside the database.
The only drawback I see would be that the db needs to be altered and saved (and synced) when a new refresh token gets issued. And that should only happen once or if the user intentionally revokes the access granted.
tl;dr - here is what I would recommend:
Last edit: Uranium235 2014-10-26
I have fixed all of the bullet points above and contacted the author.
Hopefully we'll have a new version soon.
Thanks for posting your detailed findings as well as solution :) Really appreciate your help!
However, for a normal user, your post from few days ago can be quite frightening unless they read the whole thing. If you can, I would ask to add under your bold line
There is indeed a considerable security risk involved with using this Plugin.
(If you use Portable KeePass with this plugin on untrusted / public computers)
You do point out this somewhere down if the computer is being used by multiple people :)
However, I would like to understand a little further how it's not a security risk if user was to install KeePass on an untrusted / public computer. The underlying issue seems to be the token being stored under AppData - whether it's portable or installed wouldn't matter - I think.
An alternate solution could have been to simply delete that user.config file either on KeePass exit or informing the user to delete it themselves when they are done using an unsecure computer.
But I like your solution a lot better of keeping everything inside KeePass database.
I have uploaded the source code and added you as a developer. I would really appreciate if you could upload the changes there as well as updating the readme.txt and Sample-KeePass.config.xml file.
Please let me know if you can do it. If not, I will try to merge your changes - hopefully in the next few days.
Once again, thank you for contributing!
Once an application has been granted access to the Google Drive API by the user, all the application needs thereafter to access the API is three things:
No further need for the password or user consent dialogue.
Anyone that knows these three things has the same access rights to the Google Drive as the original application. In this case the Plugin has full Google Drive access.
The old Plugin stored all three things unprotected. The Refresh Token was obfuscated, but as I pointed out above, that is in effect the same as storing it plain text.
Here are possible ways an attack might work:
In that same scenario I could have just installed KeePass locally - no need for the USB Drive. Same thing at home with e.g. evil flat mates. Or, if my system is infected with a Virus / Malware / Bot, the attacker can simply copy those files and be anywhere on this planet. Of course you have a much bigger problem in that last case, but the old way makes it really easy. And there are already Bots out there that routinely copy those interesting files (like unprotected Browser / Mail client password databases).
Deleting that user.config file would mean that the Plugin itself has no more access to the Google Drive and needs user authentication again. That might be done (semi-) automatic as the Plugin has access to the password, but it is not the way Google intended this process to work. User consent should always be done by the user in person. Once you get a Refresh Token, Google says you should keep it safe and re-use it as long as possible.
I think I can get around to updating the code, sample and readme tomorrow.
Last edit: Uranium235 2014-10-26
That makes perfect sense.
So as a quick fix ...
TO ANYONE READING THIS POST - IF YOU HAVE USED THIS PLUGIN ON AN UNTRUSTED / PUBLIC / SHARED COMPUTER - PLEASE DO FOLLOWING IMMEDIATELY
This will also recreate the KeePass folder under C:\Users[User]\AppData\Local\Dominik_Reichl, giving you a fresh new token from Google.
Section Example
Setting example
Thanks Uranium for reporting and fixing this problem.
Last edit: Danyal 2014-10-26
It should be noted that the problem is not fixed in release version 1.6 yet.
A version 2.0, which will not be compatible with the old version in terms of the configuration, will probably be released very soon.
A similar process as above - to be on the safe side - will be needed too. There will be separate instructions for upgrading though.
Thanks for all your work on this. Much appreciated. Looking forward to 2.0!
Version 2.0 is already released