• 5
name

A PHP Error was encountered

Severity: Notice

Message: Undefined index: userid

Filename: views/question.php

Line Number: 191

Backtrace:

File: /home/prodcxja/public_html/questions/application/views/question.php
Line: 191
Function: _error_handler

File: /home/prodcxja/public_html/questions/application/controllers/Questions.php
Line: 433
Function: view

File: /home/prodcxja/public_html/questions/index.php
Line: 315
Function: require_once

I have got a python script which is creating an ODBC connection. The ODBC connection is generated with a connection string. In this connection string I have to include the username and password for this connection.

Is there an easy way to obscure this password in the file (just that nobody can read the password when I'm editing the file) ?

      • 2
    • Just remember that the users running this file will have at least read access to it and can easily grab the passwords. If thins can only be read by you and you are worried about people seeing it over your shoulder go for it, but be warned while the average observer can't memorize things fast enough to grab a password, anyone with access to the script and a small bit of technical know-how and a small amount of ambition will be able to grab your passwords. Always think security through very carefully, it's important.

Base64 encoding is in the standard library and will do to stop shoulder surfers:

>>> import base64
>>>  print(base64.b64encode("password".encode("utf-8")))
cGFzc3dvcmQ=
>>> print(base64.b64decode("cGFzc3dvcmQ=").decode("utf-8"))
password
  • 117
Reply Report
    • But doesn't help the fact that the script must be readable by the user running it and the password must not.
    • I don't think that base64 is better obfuscating than rot13 in this context. On the contrary, base64 has its typical characteristics (equal sign, ...) and is thus easier detectable than other approaches. Any obfuscation has no practical benefit, though. Really bad that this answer is this highly rated. It just gives a false feeling of security...
      • 2
    • If you're recording the password so that it can be used by the script, anyone with access to the script will be able to able to get the password, not matter which encryption method you use. The requirement here was just to hide the password from someone just looking at the script while it was open. In this case base64 is preferable to rot13 as it is in the Python standard library.

Douglas F Shearer's is the generally approved solution in Unix when you need to specify a password for a remote login.
You add a --password-from-file option to specify the path and read plaintext from a file.
The file can then be in the user's own area protected by the operating system. It also allows different users to automatically pick up their own own file.

For passwords that the user of the script isn't allowed to know - you can run the script with elavated permission and have the password file owned by that root/admin user.

  • 52
Reply Report
    • How exactly do you run the script with elevated permissions without giving a root or admin password? Is it related to set UID bits?
      • 2
    • Never mind I figured it out. For anyone else who cares: If a script has a setuid bit set the OS will 'pass' the setuid bit to the interpreter. Unfortunately, there are massive gaping security holes so most modern distros turn off setuid for scripts.
      • 1
    • @pyramidface - I meant that you would code a feature like this and add the ability to read a passwd from a file
      • 1
    • @MartinBeckett but like Youarefunny said, you would have to raise setuid on python in order to give the script root access to the password file?

Here is a simple method:

  1. Create a python module - let's call it peekaboo.py.
  2. In peekaboo.py, include both the password and any code needing that password
  3. Create a compiled version - peekaboo.pyc - by importing this module (via python commandline, etc...).
  4. Now, delete peekaboo.py.
  5. You can now happily import peekaboo relying only on peekaboo.pyc. Since peekaboo.pyc is byte compiled it is not readable to the casual user.

This should be a bit more secure than base64 decoding - although it is vulnerable to a py_to_pyc decompiler.

  • 51
Reply Report
      • 1
    • This still has some shortcomings, but it's actually very close to what I want. It will allow me to demo python scripts that include user/passwd connections without revealing the password onscreen, or having to type it into the command prompt. After importing peekaboo import peekabo the password is available as peekaboo.password (if peekaboo.py contained password='secret')
    • If you want to take this idea one step further, you can use Cython to compile any .py file into C and generate a platform specific binary (ex: .pyd for windows, .so for macOS, etc)... By cythonizing your script and sharing the generated binary you'll get the benefit of this answer + add another layer of obfuscation, because now you have decompile C code to get to password. This is not 100% secure, but it'll take a lot of labor to get to the sensitive data you want to hide.

If you are working on a Unix system, take advantage of the netrc module in the standard Python library. It reads passwords from a separate text file (.netrc), which has the format decribed here.

Here is a small usage example:

import netrc

# Define which host in the .netrc file to use
HOST = 'mailcluster.loopia.se'

# Read from the .netrc file in your home directory
secrets = netrc.netrc()
username, account, password = secrets.authenticators( HOST )

print username, password
  • 29
Reply Report

The best solution, assuming the username and password can't be given at runtime by the user, is probably a separate source file containing only variable initialization for the username and password that is imported into your main code. This file would only need editing when the credentials change. Otherwise, if you're only worried about shoulder surfers with average memories, base 64 encoding is probably the easiest solution. ROT13 is just too easy to decode manually, isn't case sensitive and retains too much meaning in it's encrypted state. Encode your password and user id outside the python script. Have he script decode at runtime for use.

Giving scripts credentials for automated tasks is always a risky proposal. Your script should have its own credentials and the account it uses should have no access other than exactly what is necessary. At least the password should be long and rather random.

  • 19
Reply Report
      • 1
    • Very nice answer - thank you. For the small scripts I'm writing (which are maintenance scripts anyway - the BASE64 encoding will suffice)
    • This sounds good, but can you give an example implementation? Right now it's just a description of a general practice, and not as useful to someone hasn't done this before.

How about importing the username and password from a file external to the script? That way even if someone got hold of the script, they wouldn't automatically get the password.

  • 18
Reply Report

base64 is the way to go for your simple needs. There is no need to import anything:

>>> 'your string'.encode('base64')
'eW91ciBzdHJpbmc=\n'
>>> _.decode('base64')
'your string'
  • 15
Reply Report
    • Jonathan, it seems as if you didn't read the question. It's about obscurity (and a very temporary one), not security, so I don't understand why you consider my answer not helpful.
    • I didn't know you could do this instead of having to use the base64 module. And there are a lot of encodings too like zlib too... fun :)
    • @Dennis Using the base64 module is the preferred way nowadays. The latter doesn't work anymore in newer versions of Python.

for python3 obfuscation using base64 is done differently:

import base64
base64.b64encode(b'PasswordStringAsStreamOfBytes')

which results in

b'UGFzc3dvcmRTdHJpbmdBc1N0cmVhbU9mQnl0ZXM='

note the informal string representation, the actual string is in quotes

and decoding back to the original string

base64.b64decode(b'UGFzc3dvcmRTdHJpbmdBc1N0cmVhbU9mQnl0ZXM=')
b'PasswordStringAsStreamOfBytes'

to use this result where string objects are required the bytes object can be translated

repr = base64.b64decode(b'UGFzc3dvcmRTdHJpbmdBc1N0cmVhbU9mQnl0ZXM=')
secret = repr.decode('utf-8')
print(secret)

for more information on how python3 handles bytes (and strings accordingly) please see the official documentation.

  • 5
Reply Report

This is a pretty common problem. Typically the best you can do is to either

A) create some kind of ceasar cipher function to encode/decode (just not rot13) or

B) the preferred method is to use an encryption key, within reach of your program, encode/decode the password. In which you can use file protection to protect access the key.

Along those lines if your app runs as a service/daemon (like a webserver) you can put your key into a password protected keystore with the password input as part of the service startup. It'll take an admin to restart your app, but you will have really good pretection for your configuration passwords.

  • 4
Reply Report

Your operating system probably provides facilities for encrypting data securely. For instance, on Windows there is DPAPI (data protection API). Why not ask the user for their credentials the first time you run then squirrel them away encrypted for subsequent runs?

  • 2
Reply Report

More homegrown appraoch rather than converting authentication / passwords / username to encrytpted details. FTPLIB is just the example. "pass.csv" is the csv file name

Save password in CSV like below :

user_name

user_password

(With no column heading)

Reading the CSV and saving it to a list.

Using List elelments as authetntication details.

Full code.

import os
import ftplib
import csv 
cred_detail = []
os.chdir("Folder where the csv file is stored")
for row in csv.reader(open("pass.csv","rb")):       
        cred_detail.append(row)
ftp = ftplib.FTP('server_name',cred_detail[0][0],cred_detail[1][0])
  • 2
Reply Report

Here is my snippet for such thing. You basically import or copy the function to your code. getCredentials will create the encrypted file if it does not exist and return a dictionaty, and updateCredential will update.

import os

def getCredentials():
    import base64

    splitter='<PC+,DFS/-SHQ.R'
    directory='C:\\PCT'

    if not os.path.exists(directory):
        os.makedirs(directory)

    try:
        with open(directory+'\\Credentials.txt', 'r') as file:
            cred = file.read()
            file.close()
    except:
        print('I could not file the credentials file. \nSo I dont keep asking you for your email and password everytime you run me, I will be saving an encrypted file at {}.\n'.format(directory))

        lanid = base64.b64encode(bytes(input('   LanID: '), encoding='utf-8')).decode('utf-8')  
        email = base64.b64encode(bytes(input('   eMail: '), encoding='utf-8')).decode('utf-8')
        password = base64.b64encode(bytes(input('   PassW: '), encoding='utf-8')).decode('utf-8')
        cred = lanid+splitter+email+splitter+password
        with open(directory+'\\Credentials.txt','w+') as file:
            file.write(cred)
            file.close()

    return {'lanid':base64.b64decode(bytes(cred.split(splitter)[0], encoding='utf-8')).decode('utf-8'),
            'email':base64.b64decode(bytes(cred.split(splitter)[1], encoding='utf-8')).decode('utf-8'),
            'password':base64.b64decode(bytes(cred.split(splitter)[2], encoding='utf-8')).decode('utf-8')}

def updateCredentials():
    import base64

    splitter='<PC+,DFS/-SHQ.R'
    directory='C:\\PCT'

    if not os.path.exists(directory):
        os.makedirs(directory)

    print('I will be saving an encrypted file at {}.\n'.format(directory))

    lanid = base64.b64encode(bytes(input('   LanID: '), encoding='utf-8')).decode('utf-8')  
    email = base64.b64encode(bytes(input('   eMail: '), encoding='utf-8')).decode('utf-8')
    password = base64.b64encode(bytes(input('   PassW: '), encoding='utf-8')).decode('utf-8')
    cred = lanid+splitter+email+splitter+password
    with open(directory+'\\Credentials.txt','w+') as file:
        file.write(cred)
        file.close()

cred = getCredentials()

updateCredentials()
  • 2
Reply Report

Do you know pit?

https://pypi.python.org/pypi/pit (py2 only (version 0.3))

https://github.com/yoshiori/pit (it will work on py3 (current version 0.4))

test.py

from pit import Pit

config = Pit.get('section-name', {'require': {
    'username': 'DEFAULT STRING',
    'password': 'DEFAULT STRING',
    }})
print(config)

Run:

$ python test.py
{'password': 'my-password', 'username': 'my-name'}

~/.pit/default.yml:

section-name:
  password: my-password
  username: my-name
  • 1
Reply Report
      • 1
    • As @successhawk has noted - I don't see ANY documentation in those github/pypi links for "pit" - but the above description is clear - and overall I like this solution for "hiding" credentials from easy view...
      • 1
    • I am reluctant to use a module that is not maintained, and I get errors when I try to use it as instructed: /usr/lib/python3.7/site-packages/pit.py:93: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details. return yaml.load(open(Pit._config))

If running on Windows, you could consider using win32crypt library. It allows storage and retrieval of protected data (keys, passwords) by the user that is running the script, thus passwords are never stored in clear text or obfuscated format in your code. I am not sure if there is an equivalent implementation for other platforms, so with the strict use of win32crypt your code is not portable.

I believe the module can be obtained here: http://timgolden.me.uk/pywin32-docs/win32crypt.html

  • 1
Reply Report

Trending Tags