How does python-keyring provide security on Windows?
In GNOME/KDE on Linux, the user is prompted to enter his password to authorize access to the keyring on a per-application basis.
In Windows there is no such prompt when an application accesses the keyring. What is stopping a random python application to retrieve a password from the keyring by running
import keyring
get_password(service, username)
How is user consent implemented? Is the whole concept, atleast in Windows, based on the assumption that all installed programs are 'trusted'?
Researching this a bit, it appears that the passwords are stored within a Windows Credential Vault, which is the equivalent of the Gnome or KDE keyrings. You can actually see the ones that you have stored by opening up the Windows Credential Manager. I get there by just typing in Credential Manager on Windows 8.1 from the start screen, but I think you can get to it from the User accounts page as well.
Anyway, as you can see from the attached image, the password that I added to the keyring as a test is displayed under Windows Credentials -> Generic Credentials -> keyring_demo. Opening this window up as another user on the PC does not show this password, so it seems secured from other Users. This screen also allows you to revoke or change passwords.
As to how consent is implemented, I believe keyring will operate as long as your Windows user account is logged in, but I don't know the specifics.
the cedential manager method works, but in my case add:
internet or network addess "myPassGroup"
username "pass1"
password "xxx"
then add another entry using the same network address
internet or netwokr address "myPassGroup"
username "pass2"
password "xxx"
the pass2 will OVERRIDE the frist entry pass1!
this is a major drewback, as the "internet or network address" is
served as a groupname in keyring, I need put mutiple password under
the same name
my solution is to use the python command direct
open CMD in windows
type Python
then type import keyring
then type keyring.set_password("groupName", "passKey" ,"password")
then type keyring.set_password("groupName", "passKey2" ,"password2")
you can validate the result by
keying.get_password("groupname", "passKey")
keying.get_password("groupname", "passKey2")
I konw this will work, but still struggle to find where the actual data
is saved
I used the following command try to find out
python -c "import keyring.util.platform_; print(keyring.util.platform_.config_root())"
python -c "import keyring.util.platform_; print(keyring.util.platform_.data_root())"
the data_root in my case is "C:\Users\JunchenLiu\AppData\Local\Python Keyring"
I checked the folder, it doesn't exists... it must been saved somewhere. maybe someone can figure it out.
but my solution should work prefectly on Windows
This is from the python-keyring github I imagine a similar concern exists for windows as does MacOS though the website says no analysis has been completed
Security Considerations
Each builtin backend may have security considerations to understand before using this library. Authors of tools or libraries utilizing keyring are encouraged to consider these concerns.
As with any list of known security concerns, this list is not exhaustive. Additional issues can be added as needed.
macOS Keychain
Any Python script or application can access secrets created by keyring from that same Python executable without the operating system prompting the user for a password. To cause any specific secret to prompt for a password every time it is accessed, locate the credential using the Keychain Access application, and in the Access Control settings, remove Python from the list of allowed applications.
from keyring.backend import KeyringBackend
class SimpleKeyring(KeyringBackend):
"""Simple Keyring is a keyring which can store only one
password in memory.
"""
def __init__(self):
self.password = ''
def supported(self):
return 0
def get_password(self, service, username):
return self.password
def set_password(self, service, username, password):
self.password = password
return 0
def delete_password(self, service, username):
self.password = None
Related
I am using pyVmomi for my automation. Now I am testing a VM, where the SSH is disabled by default, and I must change the password upon the first login:
You are required to change your password immediately (root enforced)
If I try connecting using pyVmomi's StartProgramInGuest, I get vim.fault.InvalidGuestLogin exception:
Failed to authenticate with the guest operating system using the supplied credentials
I am looking for a way to change the default password programmatically, (preferably) using pyVmomi
To start off, it seems like you failed to pass the correct credentials when calling the "StartProgramInGuest" function, you can specify and pass credentials to this function using Name-Password authentication, like below.
creds = vim.vm.guest.NamePasswordAuthentication(username='username', password='password)
Test this and make sure you successfully authenticated to the guest virtual machine. After you're able to successfully authenticate, you can use Process Manager, to create either a Linux process or Windows process to change your password. For example, here is a PowerShell process tested on a Windows 10 virtual machine, executed through StartProgramInGuest.
argument= vim.vm.guest.ProcessManager.ProgramSpec(programPath='powershell.exe -Command', arguments='"& {net user loginid newpassword;}"')
res = pm.StartProgramInGuest(vm, creds, argument)
Let me know if you need any clarification!
Up until now, whenever I have needed to store a "secret" for a simple python application, I have relied on environment variables. In Windows, I set the variables via the Computer Properties dialog and I access them in my Python code like this:
database_password = os.environ['DB_PASS']
The simplicity of this approach has served me well. Now I have a project that uses Oauth2 authentication and I have a need to store tokens to the environment that may change throughout program execution. I want them to persist the next time I execute the program. This is what I have come up with:
#fetch a new token
token = oauth.fetch_token('https://api.example.com/oauth/v2/token', code=secretcode)
access_token = token['access_token']
#make sure it persists in the current session
os.environ['TOKEN'] = access_token
#store to the system environment (Windows)
cmd = 'SETX /M TOKEN ' + access_token
os.system(cmd)
It gets the job done quickly for me today, but does not seem like the right approach to add to my toolbox. Does anyone have a more elegant way of doing what I am trying to do that does not add too many layers of complexity? If the solution worked across platforms that would be a bonus.
I have used the Python keyring module with great success. It's an interface to credential vaults provided by the operating system (e.g., Windows Credential Manager). I haven't used it on Linux, but it appears to be supported, as well.
Storing a password/token and then retrieving it can be as simple as:
import keyring
keyring.set_password("system", "username", "password")
keyring.get_password("system", "username")
I'm currently writing a script where I need to gain access to another computer on my LAN while using administrative credentials that differ from the account I am logged in as. I attempted to use the requests module.
Here is my code so far:
import requests
with requests.Session() as c:
location = ('file://computer/c$/')
USERNAME = 'notrealusername'
PASSWORD = 'notrealpassword'
c.get(location)
logindata = dict(username=USERNAME, password=PASSWORD, next='/')
c.post(location, data=logindata, headers{"Referer":"file://computer/c$/"})
Can someone tell me how I can edit my code to make it work properly according to the criteria specified above?
Impacket
This 3rd party library is pretty useful for Windows related networking tasks. In this situation i would use their wmiexec.py script:
wmiexec.py
A semi-interactive shell, used through Windows Management Instrumentation. It does not require to install any service/agent at the target server. Runs as Administrator. Highly stealthy.
If your not wanting any 3rd party dependencies, you could write your own solution. A wmi shell is mentioned in the BlackHat Python book.
I am using nose to test a Python class that requires a username and password. What is the best practice for providing that username and password pair to the test module? I'd like the testing process to be intuitive for another engineer to pick up, and I cannot store any sensitive information in cleartext. Any ideas?
Most common options is to provide data in env variables.
import os
password = os.environ['PASSWORD']
username = os.environ['USERNAME']
$ USERNAME=user PASSWORD=qwerty nose
Note: Environment variables can be read by root and process owner. Variables provided via command line appear in shell history with the command.
Manual tests
encourage (enforce) developers to obtain their own credentials,
encrypt credentials; among others I would take a look at git-secret. Tox could be used to automate this a bit.
Automated tests
Most CI systems offer option (internally or via plugin) to store and pass credentials to test/build plans, mask them in logs. For example Jenkins has numerous plugins Mask Password, Credentials Binding. Atlassian's Bamboo by default masks all plan variables if name has password word. Personally, I found the most useful are Travis' encrypted variables, credentials are tied to repo/commit, not to plan.
I'm developing a script with a co-worker that involves connecting to a database. We want to keep the code independent of which one of us uses it, while keeping our passwords private and not having to authenticate over and over during the workday. After some searching (we are both novices in Python) it seems that we can use keyring for this purpose, so I installed it from pip (most likely version 1.2.2 of the library, based on my memory of the installation date).
The problem is that when I try to access my stored passwords, I am prompted to set a master password to access the keyring, as shown here (from IDLE):
>>> import keyring
>>> keyring.set_password('Service', 'MyUsername', 'MyPassword')
Warning (from warnings module):
File "C:\Python27\lib\getpass.py", line 92
return fallback_getpass(prompt, stream)
GetPassWarning: Can not control echo on the terminal.
Warning: Password input may be echoed.
Please enter password for encrypted keyring:
After setting the password, I can get and set passwords easily, until I restart the shell. Now I have to enter the master password again:
>>> ================================ RESTART ================================
>>> import keyring
>>> print keyring.get_password('Service', 'MyUsername')
Warning (from warnings module):
File "C:\Python27\lib\getpass.py", line 92
return fallback_getpass(prompt, stream)
GetPassWarning: Can not control echo on the terminal.
Warning: Password input may be echoed.
Please enter password for encrypted keyring:
After entering the master password, this authentication persists only during the current session/between restarts. When running scripts from the command line, it's even worse - I have to authenticate every time the script is run. At this point, keyring is not saving me any time or effort, and I doubt it's making my password any more secure vs. memorization and manual entry.
After searching for solutions, it looks like keyring will automatically authenticate on Unix if the master password is the same as the password for the user account, but this didn't work for me on Windows.
Am I trying to get keyring to do something it's not meant to do, or is there just an error in my implementation?
My experience seems to conflict with that reported by another user who claims (s)he is not prompted for a password when an application tries to access the keyring in the related question, How does python-keyring work on Windows?
Which backend are you using? Check using:
>>> from keyring import get_keyring
>>> get_keyring()
[... what is output here?]
If it outputs this:
<keyring.backends.file.EncryptedKeyring object at 0x.....>
Then that's why it's requesting a password. The module failed to find any platform specific keyring to use, so it's instead just encrypting your passwords using a master password and placing them into an ordinary file.
Personally, it's more important to me that my scripts run unattended than that my passwords are secure, so I wrote this function:
def configureKeyring():
"""
EncryptedKeyring requires a master password to unlock it, which is not ideal
for our scripts since we want them to run unattended. So if we're using
EncryptedKeyring, automatically swap to a PlaintextKeyring instead.
If we're using something else, say WinVaultKeyring, then that's more secure
than PlaintextKeyring without being any less convenient, so we'll use it.
"""
from keyring import get_keyring, set_keyring
from keyring.backends.file import EncryptedKeyring, PlaintextKeyring
if isinstance(get_keyring(), EncryptedKeyring):
set_keyring(PlaintextKeyring())
Before you use keyring to set_password or get_password, run this function configureKeyring(), if you, like me, value not needing to insert a master password over keeping your passwords safe. Please understand the security implications that you are storing your passwords in plaintext before doing this.
A better long term solution is to probably investigate all the other available backends and install the proper pre-reqs so that a different one can be used, if one exists where you don't need to input a master password and simply being logged in is sufficient.
Note: from https://build.opensuse.org/package/view_file/openSUSE:Leap:42.2/python-keyring/python-keyring.changes?rev=a2e727a9e4a21a65c9496362d8cff27d
As these keyrings have moved, any keyrings indicated explicitly in
configuration will need to be updated to replace "keyring.backends."
with "keyrings.alt.". For example,
"keyring.backends.file.PlaintextKeyring" becomes
"keyrings.alt.file.PlaintextKeyring"
so depending on the version in the solution already provided, you might have to do
from keyrings.alt.file import EncryptedKeyring, PlaintextKeyring