How to avoid plain text passwords in a python script? - python

I am going to start a new python project with web scraping, data analysis and etc... This implies making some logins in emails and data websites. I would like to know how can I avoid putting plain text password in my python scripts? Because I understand this is not very secure to have your password readable somewhere.
I have found a method using cryptography library that encrypts your password and generates a secret key that can decrypt it but I think it is not a good idea because as soon as a put the secret key in the script, someone can decrypt my password.
https://www.linkedin.com/pulse/encrypt-passwords-python-scripts-lee-rock/
Also, some people say to create a file named secret.py and stores there all passwords I need. When I have to use it, I can import this file and get the password. Consequently, this is not good too because there is a file full of readables passwords.
None of all these results were not satisfying.
In my case, I would like to share my code without leaking my passwords.

Related

Storing and using encryption key without user input in python

I am writing a script that is going to be ran as a scheduled task every morning. The program pulls encrypted usernames and passwords from a SQL Database and will need to decrypt them. My question is, is there any way for me to store the encryption/decryption key for the script to use without expecting a user input such as a password? Ideally the script should run completely autonomously.
The most flexible idea as stated by #EugeneProut would be to use env variable. I would like to extend that it also provides the best security. Then You can simply access the variable by using the code as below:
import os
print(os.environ['ENCRYPTION_KEY'])
This solution is the most production-like, since gives the best possibility to provide the key securely for example as secret.

securing of passwords in python

I am learning python so I figured I would try to make a script that automatically sends gmail emails for me.
It needs to send a login and password to my gmail account to automatically send some emails for me.
I read some of the guides here and it seems passlib is a good choice. But I am still a bit confused about how to set it up.
I use passlib to encrypt my password
The result will be stored in a hidden file in my linux vm.
When script runs, it needs to parse that hidden file on my vm for the hased password.
Here is where I am confused, I think I need to decrypt it and before sending it out? Isn't that rather insecure? Or can I send it without decryption and hopefully gmail can decrypt it?
I am using the SMTP library.
server = smtplib.SMTP('smtp.gmail.com', 587)
server.ehlo()
server.starttls()
server.login(gmail_sender, gmail_passwd)
Thanks
Passlib probably isn't actually the right choice here. It's primarily concerned with one-way hashing of passwords. You'd be able to use the resulting hash to verify if a user-provided password matches your hash, but not decrypt the hash. (Older Passlib releases did have an incorrectly named .encrypt() method, but Passlib 1.7 renamed that to .hash()).
You probably want one of two things, depending on your use case:
keyring is a python interface for saving & storing passwords in an OS-controlled "wallet". It works cross-platform on windows, linux, etc.
However, it may prove awkward to use if the password is needing to be run from a script that's triggered outside of a logged-in desktop session.
In that case, you may want to encrypt the credentials you're using for storage, and pick a single password (provided at call time to your script, e.g. from command line prompt or env var) to decrypt those credentials.
cryptography is a good choice for doing something like that; it provides a number of high-level functions that don't require (too much) crypto experience, such as their fernet encryption helpers.
The starttls() call sets up an encrypted SSL/TLS connection, so the password is not being sent in cleartext. Yes you will need decrypt the password before sending it to server.login(). Alternatively you could store the password in an environment variable and read it into python, which is not as secure, but much easier to implement.

How to encrypt and decrypt passwords for selenium testing?

The context is testing of a web app with selenium while using a number of virtual user accounts we created for this very purpose. And so the testing process needs to access our sites and log-on with the virtual user's id and password.
None of these accounts are critical and they are flagged as testing accounts so no damage can be done. Still, it would probably be a good idea to encrypt the passwords and decrypt them prior to use.
If it matter, our test app is written in Python, Django and uses PostgreSQL for the database. It runs on a small Linode instance.
What might best practices be for something like this?
EDIT 1
The other thought I had was to store the credentials on a second machine and access them through and API while only allowing that access to happen from a known server's non-public IP. In other words, get two instances at Linode and create a private machine-to-machine connection within the data center.
In this scenario, access to the first machine would allow someone to potentially make requests to the second machine if they are able to de-obfuscate the API code. If someone really wants the data they can certainly get it.
We could add two factor authentication as a way to gate the tests. In other words, even if you had our unencrypted test_users table you couldn't do anything with them because of the 2FA mechanism in place just for these users.
Being that this is for testing purposes only I am starting to think the best solution might very well be to populate the test_users table with valid passwords only while running a test. We could keep the data safe elsewhere and have a script that uploads the data to the test server when we want to run a test suite. Someone with access to this table could not do thing with it because all the passwords would be invalid. In fact, we could probably use this fact to detect such a breach.
I just hate the idea of storing unencrypted passwords even if it is for test users that can't really do any damage to the actual app (their transactions being virtual).
EDIT 2
An improvement to that would be to go ahead and encrypt the data and keep it in the test server. However, every time the tests are run the system would reach out to us for the crypto key. And, perhaps, after the test is run the data is re-encrypted with a new key. A little convoluted but it would allow for encrypted passwords (and even user id's, just to make it harder) on the test server. The all-important key would be nowhere near the server and it would self-destruct after each use.
What is generally done in a case like this is to put the password through a cryptographic hash function, and store the hashed password.
To verify a login, hash the provided password and compare the calculated hash to the stored version.
The idea behind this is that it is considered impossible to reverse a good cryptographic hash function. So it doesn't matter if an attacker could read the hashed passwords.
Example in Python3:
In [1]: import hashlib
In [2]: hashlib.sha256('This is a test'.encode('utf8')).hexdigest()
Out[2]: 'c7be1ed902fb8dd4d48997c6452f5d7e509fbcdbe2808b16bcf4edce4c07d14e'
In [3]: hashlib.sha256('This is a tist'.encode('utf8')).hexdigest()
Out[3]: 'f80b4162fc28f1f67d1a566da60c6c5c165838a209e89f590986333d62162cba'
In [4]: hashlib.sha256('This is a tst.'.encode('utf8')).hexdigest()
Out[4]: '1133d07c24ef5f46196ff70026b68c4fa703d25a9f12405ff5384044db4e2adf'
(for Python2, just leave out the encode.)
As you can see, even one-letter changes lead to a big change in the hash value.

Python hashed password to use in different script?

OK, i was unable to find this same question anywhere.. So i apologize in advance if this has been asked before.
My need is to have a script ssh into other devices at different times, to do this I need to store a password. I don't want to use plain text or base64, but I would be OK with hashing the password and I have no issue doing that. The issue is I don't know how to get the hash to be sent to the devices as a password. It just sends the hash and the login gets denied.
This is the hash script that writes to a file:
import getpass, hashlib, os
pwf = open('hashes.txt', 'w')
password = getpass.getpass()
hashpass = hashlib.sha256(password).hexdigest()
pfw.write(hashpass)
This is the 2nd script that I can pull the hash out of the file, but its still a hash.
hashes = open('hashes.txt', 'r')
for pw in hashes:
passwrd = pw.strip()
password = passwrd
Thats all fine and dandy, but the I cant login with the hash.. Im sure im doing something fundamentally wrong here. please let me know.
Also i left out the other ssh code as I didnt think it was relevent.
The entire point of a cryptographic hash is that it isn't feasible to reverse it into the original password. If you need to send the actual password, a hash will not work for you; you'd need to use an actual encryption algorithm - but then you run into a similar problem of how you store the encryption key you're using to store the password.
Either way you need a way of securely storing data on your local system that other unauthorized users can't access. Typically this is done by using key-based ssh authentication and storing the key with permissions that make it inaccessible to other users. This essentially skips the unnecessary step of encrypting/decrypting a password and instead just uses the encryption key as the authentication mechanism for ssh.
Note that there exist Python libraries that are designed for the kind of task you're doing (sshing to remote systems and running commands automatically) - fabric is one of them.

How to programmatically(python) authenticate username/password using OS users

I'm writing a python program which allow user to login to it. I don't want to implement my own authentication but would rather take advantage of the OS(linux) mechanism. That is, when the user is trying to sign in my app by inputing username/password pair(which should be a valid OS user), I need to authenticate the pair by the OS. How to do that ? It may need the subprocess module, yet I've tried with no luck.
Try using PAM via Python PAM or similar
That should be possible by having your script read the /etc/passwd and /etc/shadow files, which contain details about usernames and passwords on a Linux system. Do note that the script will have to have read access to the files, which depending on the situation may or may not be possible.
Here are two good articles explaining the format of those files, which should tell you everything you need to know in order to have your script read and understand them:
Understanding /etc/passwd File Format
Understanding /etc/shadow File Format
By the way, when it talks about encrypted password, it means that it has been encrypted using the DES algorithm. You'll probably need to use pyDes or another python implementation of the DES algorithm in order for your script to create an encrypted password that it can compare to the one in /etc/shadow.

Categories

Resources