Een wachtwoord verbergen in een python-script (alleen onveilige verduistering)

Ik heb een python-script dat een ODBC-verbinding maakt. De ODBC-verbinding wordt gegenereerd met een verbindingsreeks. In deze verbindingsreeks moet ik de gebruikersnaam en het wachtwoord voor deze verbinding opnemen.

Is er een gemakkelijke manier om dit wachtwoord in het bestand te verbergen (alleen dat niemand het wachtwoord kan lezen wanneer ik het bestand aan het bewerken ben)?


Antwoord 1, autoriteit 100%

Base64-coderingzit in de standaardbibliotheek en is voldoende om schoudersurfers te stoppen :

>>> import base64
>>>  print(base64.b64encode("password".encode("utf-8")))
cGFzc3dvcmQ=
>>> print(base64.b64decode("cGFzc3dvcmQ=").decode("utf-8"))
password

Antwoord 2, autoriteit 48%

Hier is een eenvoudige methode:

  1. Maak een python-module – laten we het kiekeboe.py noemen.
  2. Vermeld in kiekeboe.py zowel het wachtwoord als de code waarvoor dat wachtwoord nodig is
  3. Maak een gecompileerde versie – peekaboo.pyc – door deze module te importeren (via de python-opdrachtregel, enz…).
  4. Verwijder nu peekaboo.py.
  5. Je kunt nu met plezier kiekeboe importeren door alleen te vertrouwen op kiekeboe.pyc. Aangezien kiekeboe.pyc byte gecompileerd is, is het niet leesbaar voor de gewone gebruiker.

Dit zou een beetje veiliger moeten zijn dan base64-decodering – hoewel het kwetsbaar is voor een py_to_pyc-decompiler.


Antwoord 3, autoriteit 41%

Douglas F Shearer’s is de algemeen goedgekeurde oplossing in Unix wanneer u een wachtwoord moet opgeven voor inloggen op afstand.
U voegt een optie –password-from-filetoe om het pad op te geven en leesbare tekst uit een bestand te lezen.
Het bestand kan zich dan in het eigen gebied van de gebruiker bevinden dat wordt beschermd door het besturingssysteem.
Het stelt verschillende gebruikers ook in staat om automatisch hun eigen bestand op te halen.

Voor wachtwoorden die de gebruiker van het script niet mag weten, kun je het script uitvoeren met uitgebreide toestemming en het wachtwoordbestand in bezit hebben van die root-/admin-gebruiker.


Antwoord 4, autoriteit 23%

Als je op een Unix-systeem werkt, maak dan gebruik van de netrc-module in de standaard Python-bibliotheek. Het leest wachtwoorden uit een apart tekstbestand (.netrc), dat het formaat heeft dat hierwordt beschreven .

Hier is een klein gebruiksvoorbeeld:

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

Antwoord 5, autoriteit 14%

Hoe zit het met het importeren van de gebruikersnaam en het wachtwoord uit een bestand buiten het script? Op die manier zouden, zelfs als iemand het script te pakken zou krijgen, ze niet automatisch het wachtwoord krijgen.


Antwoord 6, autoriteit 14%

De beste oplossing, ervan uitgaande dat de gebruikersnaam en het wachtwoord niet door de gebruiker kunnen worden gegeven tijdens runtime, is waarschijnlijk een afzonderlijk bronbestand met alleen variabele initialisatie voor de gebruikersnaam en het wachtwoord dat in uw hoofdcode wordt geïmporteerd. Dit bestand hoeft alleen te worden bewerkt als de inloggegevens veranderen. Anders, als je je alleen zorgen maakt over schoudersurfers met gemiddeld geheugen, is base 64-codering waarschijnlijk de gemakkelijkste oplossing. ROT13 is gewoon te gemakkelijk om handmatig te decoderen, is niet hoofdlettergevoelig en behoudt te veel betekenis in zijn versleutelde staat. Codeer uw wachtwoord en gebruikers-ID buiten het python-script. Laat het script tijdens runtime decoderen voor gebruik.

Het geven van inloggegevens voor scripts voor geautomatiseerde taken is altijd een riskant voorstel. Uw script moet zijn eigen inloggegevens hebben en het account dat het gebruikt, mag geen andere toegang hebben dan wat nodig is. Het wachtwoord moet in ieder geval lang en nogal willekeurig zijn.


Antwoord 7, autoriteit 13%

base64 is de juiste keuze voor uw eenvoudige behoeften. U hoeft niets te importeren:

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

Antwoord 8, autoriteit 4%

voor python3wordt verduistering met base64anders gedaan:

import base64
base64.b64encode(b'PasswordStringAsStreamOfBytes')

wat resulteert in

b'UGFzc3dvcmRTdHJpbmdBc1N0cmVhbU9mQnl0ZXM='

let op de informele tekenreeksrepresentatie, de daadwerkelijke tekenreeks staat tussen aanhalingstekens

en decoderen terug naar de originele string

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

om dit resultaat te gebruiken waar string-objecten vereist zijn, kan het object bytes worden vertaald

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

raadpleeg de voor meer informatie over hoe python3 omgaat met bytes (en tekenreeksen dienovereenkomstig) officiële documentatie.


Antwoord 9, autoriteit 4%

Een manier waarop ik dit heb gedaan is als volgt:

Bij de python-schaal:

>>> from cryptography.fernet import Fernet
>>> key = Fernet.generate_key()
>>> print(key)
b'B8XBLJDiroM3N2nCBuUlzPL06AmfV4XkPJ5OKsPZbC4='
>>> cipher = Fernet(key)
>>> password = "thepassword".encode('utf-8')
>>> token = cipher.encrypt(password)
>>> print(token)
b'gAAAAABe_TUP82q1zMR9SZw1LpawRLHjgNLdUOmW31RApwASzeo4qWSZ52ZBYpSrb1kUeXNFoX0tyhe7kWuudNs2Iy7vUwaY7Q=='

Maak vervolgens een module met de volgende code:

from cryptography.fernet import Fernet
# you store the key and the token
key = b'B8XBLJDiroM3N2nCBuUlzPL06AmfV4XkPJ5OKsPZbC4='
token = b'gAAAAABe_TUP82q1zMR9SZw1LpawRLHjgNLdUOmW31RApwASzeo4qWSZ52ZBYpSrb1kUeXNFoX0tyhe7kWuudNs2Iy7vUwaY7Q=='
# create a cipher and decrypt when you need your password
cipher = Fernet(key)
mypassword = cipher.decrypt(token).decode('utf-8')

Zodra u dit heeft gedaan, kunt u mijn wachtwoord rechtstreeks importeren of u kunt het token en de versleuteling importeren om indien nodig te decoderen.

Het is duidelijk dat deze aanpak enkele tekortkomingen heeft. Als iemand zowel het token als de sleutel heeft (zoals ze zouden hebben als ze het script hebben), kunnen ze gemakkelijk ontsleutelen. Het vertroebelt echter wel, en als je de code compileert (met iets als Nuitka), verschijnt je wachtwoord in ieder geval niet als platte tekst in een hex-editor.


Antwoord 10, autoriteit 3%

Dit is een vrij algemeen probleem. Meestal kunt u het beste ofwel

A) maak een soort ceasar-cijferfunctie om te coderen/decoderen (alleen niet rot13)
of

B) de voorkeursmethode is om een ​​coderingssleutel te gebruiken die binnen het bereik van uw programma ligt en het wachtwoord codeert/decodeert. Waarin u bestandsbeveiliging kunt gebruiken om de toegang tot de sleutel te beveiligen.

Als je app als een service/daemon (zoals een webserver) draait, kun je je sleutel in een wachtwoordbeveiligde keystore plaatsen met de wachtwoordinvoer als onderdeel van het opstarten van de service. Er is een beheerder voor nodig om je app opnieuw te starten, maar je hebt echt goede bescherming voor je configuratiewachtwoorden.


Antwoord 11, autoriteit 2%

Hier is mijn fragment voor zoiets. U importeert of kopieert de functie in feite naar uw code. getCredentials maakt het versleutelde bestand als het niet bestaat en retourneert een woordenboek, en updateCredential wordt bijgewerkt.

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()

Antwoord 12, Autoriteit 2%

Uw besturingssysteem biedt waarschijnlijk faciliteiten voor het veilig versleutelen van gegevens. Bijvoorbeeld, op Windows is er DPAPI (gegevensbescherming API). Waarom vraagt ​​u de gebruiker niet om hun inloggegevens de eerste keer dat u rent, dan eekhoorn ze weg gecodeerd voor latere runs?


Antwoord 13, Autoriteit 2%

Plaats de configuratie-informatie in een gecodeerd configuratiebestand. Vraag deze informatie in uw code met een toets. Plaats deze sleutel in een apart bestand per omgeving en sla deze niet op met uw code.


Antwoord 14, Autoriteit 2%

meer homegraal Apprach in plaats van verificatie / wachtwoorden / gebruikersnaam te converteren naar gecodeerde details. FTPLIB is gewoon het voorbeeld.
Pass.CSV ” is de CSV-bestandsnaam

Wachtwoord opslaan in CSV zoals hieronder:

user_name

user_password

(zonder kolomkop)

het lezen van de CSV en opslaan in een lijst.

Lijstlulds gebruiken als authetnticatiedetails.

volledige 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])

Antwoord 15

Weet jij pit?

https://pypi.python.org/pypi/pit (alleen PY2 (versie 0.3))

https://github.com/yoshiori/pit (het werkt op PY3 (huidige versie 0,4))

test.py

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

Uitvoeren:

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

~ / .pit / standaard.yml:

section-name:
  password: my-password
  username: my-name

Antwoord 16

Als u op Windows draait, kunt u overwegen de win32crypt-bibliotheek te gebruiken. Het maakt opslag en ophalen van beschermde gegevens (sleutels, wachtwoorden) mogelijk door de gebruiker die het script uitvoert, dus wachtwoorden worden nooit in leesbare tekst of verduisterd formaat in uw code opgeslagen. Ik weet niet zeker of er een equivalente implementatie is voor andere platforms, dus met het strikte gebruik van win32crypt is je code niet overdraagbaar.

Ik geloof dat de module hier kan worden verkregen: http://timgolden.me. nl/pywin32-docs/win32crypt.html


Antwoord 17

Je zou ook de mogelijkheid kunnen overwegen om het wachtwoord buiten het script op te slaan en het tijdens runtime aan te leveren

bijv. fred.py

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

die kan worden uitgevoerd als

$ PASSWORD=password123 python fred.py
fred password123

Extra lagen van “beveiliging door onduidelijkheid” kunnen worden bereikt door base64te gebruiken (zoals hierboven gesuggereerd), minder voor de hand liggende namen in de code te gebruiken en het daadwerkelijke wachtwoord verder van de code te verwijderen.

Als de code zich in een repository bevindt, is het vaak handig om geheimen daarbuiten op te slaan, dus je zou dit kunnen toevoegen aan ~/.bashrc(of aan een kluis, of een opstartscript, …)

export SURNAME=cGFzc3dvcmQxMjM=

en verander fred.pyin

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

log dan opnieuw in en

$ python fred.py
fred password123

Antwoord 18

Waarom geen simpele xor?

Voordelen:

  • ziet eruit als binaire gegevens
  • niemand kan het lezen zonder de sleutel te kennen (zelfs als het een enkele teken is)

Ik kom op het punt dat ik eenvoudige b64-strings herken voor gewone woorden en ook voor rot13. Xor zou het veel moeilijker maken.


Antwoord 19

Er zijn verschillende ROT13-hulpprogramma’s geschreven in Python op het internet — google er maar op. ROT13 codeert de string offline, kopieert deze naar de bron, decodeert op het punt van verzending.

Maar dit is echtzwakke bescherming…


Antwoord 20

Dit is niet precies het antwoord op je vraag, maar het is gerelateerd. Ik was van plan om als opmerking toe te voegen, maar dat mocht niet.
Ik heb met hetzelfde probleem te maken gehad en we hebben besloten om het script beschikbaar te stellen aan de gebruikers die Jenkins gebruiken. Hierdoor kunnen we de db-referenties opslaan in een apart bestand dat versleuteld en beveiligd is op een server en niet toegankelijk is voor niet-beheerders.
Het biedt ons ook een kortere weg naar het maken van een gebruikersinterface en het beperken van de uitvoering.


Antwoord 21

import base64
print(base64.b64encode("password".encode("utf-8")))
print(base64.b64decode(b'cGFzc3dvcmQ='.decode("utf-8")))

Other episodes