web-dev-qa-db-fra.com

Masquage d'un mot de passe dans un script python (obfuscation non sécurisée uniquement)

J'ai un script python qui crée une connexion ODBC. La connexion ODBC est générée avec une chaîne de connexion. Dans cette chaîne de connexion, je dois inclure le nom d'utilisateur et le mot de passe pour cette connexion. 

Existe-t-il un moyen simple de masquer ce mot de passe dans le fichier (juste que personne ne puisse le lire lorsque je modifie le fichier)? 

109
bernhardrusch

Le codage Base64 est dans la bibliothèque standard et fera pour arrêter les surfeurs à l'épaule:

>>> import base64
>>> print base64.b64encode("password")
cGFzc3dvcmQ=
>>> print base64.b64decode("cGFzc3dvcmQ=")
password
99
Dave Webb

Douglas F Shearer's est la solution généralement approuvée sous Unix lorsque vous devez spécifier un mot de passe pour une connexion à distance.
Vous ajoutez une option --password-from-file pour spécifier le chemin et lire le texte en clair dans un fichier.
Le fichier peut alors se trouver dans la zone protégée par le système d'exploitation de l'utilisateur . Il permet également à différents utilisateurs de sélectionner automatiquement leur propre fichier.

Pour les mots de passe que l'utilisateur du script n'est pas autorisé à connaître, vous pouvez exécuter le script avec une autorisation spécifique et attribuer le fichier de mot de passe à cet utilisateur root/admin.

48
Martin Beckett

Voici une méthode simple:

  1. Créez un module python - appelons-le peekaboo.py. 
  2. Dans peekaboo.py, incluez à la fois le mot de passe et tout code nécessitant ce mot de passe
  3. Créez une version compilée - peekaboo.pyc - en important ce module (via la ligne de commande python, etc ...).
  4. Maintenant, supprimez peekaboo.py. 
  5. Vous pouvez maintenant importer avec plaisir peekaboo en vous fiant uniquement à peekaboo.pyc. Depuis que peekaboo.pyc est compilé en octets, il est illisible pour l'utilisateur occasionnel.

Cela devrait être un peu plus sécurisé que le décodage en base64 - bien qu'il soit vulnérable à un décompilateur py_to_pyc.

37

Si vous travaillez sur un système Unix, utilisez le module netrc de la bibliothèque Python standard. Il lit les mots de passe dans un fichier texte séparé (.netrc), dont le format est décrit here .

Voici un petit exemple d'utilisation:

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
25
jonasberg

La meilleure solution, en supposant que le nom d'utilisateur et le mot de passe ne puissent pas être fournis au moment de l'exécution par l'utilisateur, est probablement un fichier source séparé contenant uniquement l'initialisation de variable pour le nom d'utilisateur et le mot de passe importés dans votre code principal. Ce fichier n'aurait besoin d'être édité que lorsque les informations d'identification changent. Sinon, si vous ne vous inquiétez que des surfeurs à l'épaule avec des mémoires moyennes, l'encodage en base 64 est probablement la solution la plus simple. ROT13 est trop facile à décoder manuellement, n’est pas sensible à la casse et conserve trop de signification dans son état crypté. Encodez votre mot de passe et votre identifiant utilisateur en dehors du script python. Avoir le script décoder au moment de l'exécution pour une utilisation.

Donner des identifiants de scripts pour des tâches automatisées est toujours une proposition risquée. Votre script doit avoir ses propres informations d'identification et le compte qu'il utilise ne doit avoir d'autre accès que celui qui est nécessaire. Au moins, le mot de passe devrait être long et plutôt aléatoire.

18
tduehr

Que diriez-vous d'importer le nom d'utilisateur et le mot de passe depuis un fichier externe au script? De cette façon, même si quelqu'un se procurait le script, le mot de passe ne serait pas automatiquement obtenu.

16

base64 est la solution idéale pour vos besoins simples. Il n'est pas nécessaire d'importer quoi que ce soit:

>>> 'your string'.encode('base64')
'eW91ciBzdHJpbmc=\n'
>>> _.decode('base64')
'your string'
15
tzot

C'est un problème assez commun. En règle générale, le mieux que vous puissiez faire est de 

A) créez une sorte de fonction de chiffrement Ceasar pour encoder/décoder (mais pas pour autant rot13) Ou B) la méthode recommandée consiste à utiliser une clé de cryptage, à la portée de votre programme, pour encoder/décoder le mot de passe. Dans lequel vous pouvez utiliser la protection de fichier pour protéger l'accès à la clé . Sur ces lignes, si votre application fonctionne en tant que service/démon (comme un serveur Web), vous pouvez placer votre clé dans un magasin de clés protégé par mot de passe avec la saisie du mot de passe lors du démarrage du service. Il faudra un administrateur pour redémarrer votre application, mais vous aurez une très bonne protection pour vos mots de passe de configuration.

4
Patrick

Une approche plus locale plutôt que de convertir les authentifications/mots de passe/noms d'utilisateur en détails chiffrés.FTPLIBest juste l'exemple . " pass.csv " est le nom du fichier csv

Enregistrez le mot de passe au format CSV comme ci-dessous: 

nom d'utilisateur

mot de passe de l'utilisateur

(Sans en-tête de colonne)

Lecture du fichier CSV et enregistrement dans une liste. 

Utilisation de List elelments en tant que détails d'authentification.

Code complet.

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
LonelySoul

pour python3 obfuscation à l'aide de base64 se fait différemment:

import base64
base64.b64encode(b'PasswordStringAsStreamOfBytes')

qui se traduit par

b'UGFzc3dvcmRTdHJpbmdBc1N0cmVhbU9mQnl0ZXM='

notez la représentation informelle de la chaîne, la chaîne réelle est entre guillemets

et décodage à la chaîne d'origine

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

pour utiliser ce résultat lorsque des objets chaîne sont requis, l'objet bytes peut être traduit

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

pour plus d'informations sur la manière dont python3 gère les octets (et les chaînes en conséquence), veuillez consulter le documentation officielle .

2
jitter

Votre système d'exploitation fournit probablement des installations pour chiffrer les données en toute sécurité. Par exemple, sous Windows, il y a DPAPI (API de protection des données). Pourquoi ne pas demander à l'utilisateur ses identifiants la première fois que vous exécutez, puis les chiffrer à l'écart pour les exécutions suivantes?

2
Jamie Eisenhart

Placez les informations de configuration dans un fichier de configuration chiffré. Interrogez cette information dans votre code à l'aide d'une clé. Placez cette clé dans un fichier séparé par environnement et ne la stockez pas avec votre code.

1
FlySwat

Si vous utilisez Windows, vous pouvez utiliser la bibliothèque win32crypt. Il permet le stockage et la récupération des données protégées (clés, mots de passe) par l'utilisateur qui exécute le script. Ainsi, les mots de passe ne sont jamais stockés en texte clair ou au format obscur dans votre code. Je ne sais pas s'il existe une implémentation équivalente pour les autres plates-formes. Par conséquent, avec l'utilisation stricte de win32crypt, votre code n'est pas portable.

Je crois que le module peut être obtenu ici: http://timgolden.me.uk/pywin32-docs/win32crypt.html

1
VilleLipponen

Il existe plusieurs utilitaires ROT13 écrits en Python sur le Net - il suffit de les rechercher sur Google. ROT13 encoder la chaîne hors ligne, la copier dans la source, la décoder au moment de la transmission.

Mais c’est vraiment une faible protection ...

0
Kevin Little

Connaissez-vous la fosse?

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

https://github.com/yoshiori/pit (cela fonctionnera sous py3 (version actuelle 0.4))

test.py

from pit import Pit

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

Courir:

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

~/.pit/default.yml:

section-name:
  password: my-password
  username: my-name
0
TakesxiSximada

Cela ne répond pas précisément à votre question, mais c'est lié. J'allais ajouter un commentaire, mais je n'étais pas autorisé… .. Je suis confronté au même problème et nous avons décidé d'exposer le script aux utilisateurs de Jenkins. Cela nous permet de stocker les informations d'identification de la base de données dans un fichier séparé, crypté et sécurisé sur un serveur, non accessible aux non-administrateurs. Cela nous permet également de créer une interface utilisateur et de limiter l’exécution.

0
Joe Hayes

Vous pouvez également envisager la possibilité de stocker le mot de passe en dehors du script et de le fournir au moment de l'exécution.

par exemple. fred.py

import os
username = 'fred'
password = os.environ.get('PASSWORD', '')
print(username, password)

qui peut être exécuté comme

$ PASSWORD=password123 python fred.py
fred password123

Des couches supplémentaires de "sécurité à travers l'obscurité" peuvent être obtenues en utilisant base64 (comme suggéré ci-dessus), en utilisant des noms moins évidents dans le code et en éloignant davantage le mot de passe réel du code.

Si le code est dans un référentiel, il est souvent utile de stocker les secrets en dehors de celui-ci , afin de pouvoir l'ajouter à ~/.bashrc (ou à un coffre-fort, ou à un script de lancement, ... )

export SURNAME=cGFzc3dvcmQxMjM=

et remplacez fred.py par

import os
import base64
name = 'fred'
surname = base64.b64decode(os.environ.get('SURNAME', '')).decode('utf-8')
print(name, surname)

puis vous reconnecter et

$ python fred.py
fred password123
0
jalanb