Pythonスクリプトでパスワードを非表示にする(安全でない難読化のみ)


127

ODBC接続を作成するPythonスクリプトを取得しました。ODBC接続は、接続文字列を使用して生成されます。この接続文字列には、この接続のユーザー名とパスワードを含める必要があります。

このパスワードをファイル内で簡単に隠す方法はありますか(ファイルを編集しているときに誰もパスワードを読み取れないだけです)。


16
このファイルを実行しているユーザーは、少なくともファイルへの読み取りアクセス権を持ち、パスワードを簡単に取得できることを覚えておいてください。シンがあなただけが読み取ることができ、あなたがそれを肩越しに見ているのを心配しているのに心配しているのであれば、平均的な観察者がパスワードを取得するのに十分な速さで物事を覚えることができないときに警告されます。少しの技術的なノウハウと少しの野心があなたのパスワードをつかむことができます。セキュリティは常に慎重に検討してください。それは重要です。
Youarefunny 2011

回答:


117

Base64エンコーディングは標準ライブラリにあり、肩のサーファーを停止するために行います:

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

5
同意する。base64でエンコードされたパスワードは、はるかに不思議に見えます。
Ed Haber、

4
ただし、スクリプトを実行するユーザーがスクリプトを読み取れる必要があり、パスワードが読み取れないようにする必要があるという事実には役立ちません。
マーティンベケット

79
これbase64rot13、この文脈よりも難読化する方が良いとは思いません。逆に、base64はその典型的な特性(等号など)を備えているため、他のアプローチよりも簡単に検出できます。ただし、難読化には実用的なメリットはありません。この答えがこの高評価であることは本当に悪い。それは誤った安心感を与えるだけです...
シュラマー

12
スクリプトで使用できるようにパスワードを記録している場合、スクリプトにアクセスできるユーザーは、使用する暗号化方法に関係なく、パスワードを取得できます。ここでの要件は、スクリプトが開いているときにスクリプトを見ている人にパスワードを隠すことだけでした。この場合、Python標準ライブラリの場合よりbase64も望ましいrot13です。
Dave Webb

17
base64は暗号化ではありません。せいぜい難読化です。
csgeek 2015年

52

Douglas F Shearerは、リモートログインのパスワードを指定する必要がある場合に、Unixで一般に承認されているソリューションです。
あなたは追加--password-からファイルのパスを指定し、ファイルから平文を読み込むためのオプションを選択します。
このファイルは、オペレーティングシステムによって保護されているユーザー自身の領域に置くことができます。また、さまざまなユーザーが自分のファイルを自動的に取得することもできます。

スクリプトのユーザーが知ることを許可されていないパスワードの場合-特権を付与してスクリプトを実行し、そのroot / adminユーザーがパスワードファイルを所有することができます。


1
rootまたはadminのパスワードを指定せずに、昇格したアクセス許可でスクリプトをどのように正確に実行しますか?UIDビットの設定に関連していますか?
Youarefunny 2011

4
私がそれを考え出したことを気にしないでください。気にする他の人のために:スクリプトにsetuidビットが設定されている場合、OSはsetuidビットをインタープリターに「渡します」。残念ながら、大きなセキュリティホールが存在するため、最近のほとんどのディストリビューションでは、スクリプトのsetuidをオフにしています。
Youarefunny 2011

--password-from-fileオプションに関する情報が見つかりません。例はありますか?ありがとう!
pyramidface

@pyramidface-このような機能をコーディングし、ファイルからパスワードを読み取る機能を追加することを意味しました
Martin Beckett

@MartinBeckettですが、Youarefunnyが言ったように、スクリプトにパスワードファイルへのルートアクセスを与えるには、Pythonでsetuidを発生させる必要がありますか。
pyramidface '12

51

ここに簡単な方法があります:

  1. Pythonモジュールを作成します-それをpeekaboo.pyと呼びましょう。
  2. peekaboo.pyに、パスワードとそのパスワードを必要とするコードの両方を含めます
  3. このモジュールを(pythonコマンドラインなどを介して)インポートして、コンパイル済みバージョン-peekaboo.pycを作成します。
  4. 次に、peekaboo.pyを削除します。
  5. peekaboo.pycのみに依存してpeekabooを楽しくインポートできるようになりました。peekaboo.pycはバイトコンパイルされているため、カジュアルなユーザーには読み取れません。

これは、base64デコードよりも少し安全です-py_to_pyc逆コンパイラに対して脆弱です。


2
これにはまだいくつかの欠点がありますが、実際には私が望むものに非常に近いです。画面上にパスワードを表示したり、コマンドプロンプトにパスワードを入力したりすることなく、user / passwd接続を含むpythonスクリプトをデモできます。import peekabopeekaboo.passwordpassword='secret'
peekabooを

8
このアイデアをさらに一歩進めたい場合は、Cythonを使用し .pyファイルをCにコンパイルし、プラットフォーム固有のバイナリ(例:.pyd for windows、.so for macOSなど)を生成できます... cythonizingスクリプトによる生成されたバイナリを共有すると、この回答の利点が得られます+難読化の別のレイヤーが追加されます。これで、パスワードを取得するためのCコードを逆コンパイルすることができます。これは100%安全ではありませんが、非表示にしたい機密データを入手するには多くの労力がかかります。
Fnord 2016年

cythonizing、perfect
アルノ

29

Unixシステムで作業している場合は、標準Pythonライブラリのnetrcモジュールを利用してください。ここで説明する形式の別のテキストファイル(.netrc)からパスワードを読み取ります

これは小さな使用例です:

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

19

ユーザーが実行時にユーザー名とパスワードを指定できない場合の最善の解決策は、メインコードにインポートされるユーザー名とパスワードの変数初期化のみを含む別のソースファイルであると考えられます。このファイルは、資格情報が変更されたときにのみ編集する必要があります。それ以外の場合、平均的な記憶力を持つショルダーサーファーだけが心配な場合は、Base 64エンコーディングがおそらく最も簡単なソリューションです。ROT13は手動でデコードするのが簡単すぎて、大文字と小文字を区別せず、暗号化された状態で意味を保持しすぎます。Pythonスクリプトの外でパスワードとユーザーIDをエンコードします。実行時にスクリプトをデコードして使用します。

自動化されたタスクにスクリプトの資格情報を与えることは常に危険な提案です。スクリプトには独自の資格情報が必要です。また、スクリプトが使用するアカウントには、必要なもの以外はアクセスできないようにする必要があります。少なくともパスワードは長くランダムである必要があります。


とても良い答え-ありがとう。私が書いている小さなスクリプト(とにかくメンテナンススクリプトです-BASE64エンコーディングで十分です)
bernhardrusch

2
これは良さそうですが、実装例を挙げていただけますか?現在のところ、これは一般的な慣行の説明にすぎず、これまでにこれを行ったことのない人にとってはあまり役に立ちません。
ダニード2014年

18

スクリプトの外部のファイルからユーザー名とパスワードをインポートするのはどうですか?そうすれば、誰かがスクリプトを手に入れても、自動的にパスワードを取得することはありません。


15

base64は、単純なニーズに対応する方法です。何もインポートする必要はありません:

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

2
愚かなことは正確には何ですか?返信全体、または重要ではない部分?
tzot 2008年

18
Base64は、セキュリティの幻想を追加するだけです。
FlySwat、2008年

13
ジョナサン、質問を読んでいないようです。それはセキュリティではなく、あいまいさ(および非常に一時的なもの)に関するものであるため、私の回答が役に立たないと見なす理由がわかりません。
tzot

1
base64モジュールを使用する代わりに、これを実行できることを知りませんでした。そして、zlibのようなエンコーディングもたくさんあります... fun :)
Kiv

1
@Dennis現在、base64モジュールを使用する方法が推奨されています。後者は、新しいバージョンのPythonでは機能しません。
ジェイコモン

5

以下のためのpython3の難読使用してbase64別々に行われます。

import base64
base64.b64encode(b'PasswordStringAsStreamOfBytes')

その結果

b'UGFzc3dvcmRTdHJpbmdBc1N0cmVhbU9mQnl0ZXM='

非公式の文字列表現に注意してください。実際の文字列は引用符で囲まれています

元の文字列にデコードして戻します

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

文字列オブジェクトが必要な場合にこの結果を使用するには、バイトオブジェクトを変換できます

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

python3がバイト(およびそれに応じて文字列)を処理する方法の詳細については、公式ドキュメントを参照してください。


4

これはかなり一般的な問題です。通常、実行できる最善の方法は次のいずれかです。

A)エンコード/デコードするためのある種のシーザー暗号関数を作成する(rot13ではない)または

B)推奨される方法は、プログラムの範囲内で暗号化キーを使用し、パスワードをエンコード/デコードすることです。ファイル保護を使用して、キーへのアクセスを保護できます。

これらの線に沿って、アプリがサービス/デーモン(ウェブサーバーなど)として実行されている場合、サービスの起動の一部としてパスワードを入力し、パスワードで保護されたキーストアにキーを配置できます。アプリを再起動するには管理者が必要ですが、設定パスワードは非常に適切に保護されます。


2

お使いのオペレーティングシステムは、データを安全に暗号化する機能を備えている可能性があります。たとえば、WindowsにはDPAPI(データ保護API)があります。初めて実行するときにユーザーに資格情報を要求し、その後の実行のために暗号化して暗号化して削除しませんか?


2

認証/パスワード/ユーザー名を暗号化された詳細に変換するのではなく、より自作の手法。FTPLIBは単なる例です。" pass.csv "はcsvファイル名です

以下のようにパスワードをCSVに保存します。

user_name

ユーザーパスワード

(列見出しなし)

CSVを読み取り、リストに保存します。

認証の詳細としてリスト要素を使用します。

完全なコード。

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

これがそのようなものの私の抜粋です。基本的には、関数をコードにインポートまたはコピーします。getCredentialsは、存在しない場合は暗号化されたファイルを作成して辞書を返し、updateCredentialは更新されます。

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

1

構成情報を暗号化された構成ファイルに配置します。キーを使用してコードでこの情報をクエリします。このキーは環境ごとに別のファイルに配置し、コードと一緒に保存しないでください。


1

あなたはピットを知っていますか?

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

https://github.com/yoshiori/pit(py3(現在のバージョン0.4)で動作します)

test.py

from pit import Pit

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

実行:

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

〜/ .pit / default.yml:

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

3
ピットにはドキュメントがありません
successhawk '25 / 07/25

@successhawkが指摘したように、これらのgithub / pypiリンクに「pit」のドキュメントはありません-しかし、上記の説明は明確です-全体的に、簡単なビューから資格情報を「

私は維持されていないモジュールを使用するには消極的だ、と私は指示通りにそれを使用しようとすると、私はエラーを取得:/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))
netdesignate

1

Windowsで実行している場合は、win32cryptライブラリの使用を検討できます。スクリプトを実行しているユーザーが保護されたデータ(キー、パスワード)を保存および取得できるため、パスワードがコード内にクリアテキストまたは難読化形式で保存されることはありません。他のプラットフォームに同等の実装があるかどうかは不明なので、win32cryptを厳密に使用すると、コードを移植できなくなります。

モジュールはここで入手できると思います:http : //timgolden.me.uk/pywin32-docs/win32crypt.html


1

私がこれを行った方法は次のとおりです:

Pythonシェルで:

>>> 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=='

次に、次のコードでモジュールを作成します。

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

これを実行したら、mypasswordを直接インポートするか、必要に応じてトークンと暗号をインポートして復号化できます。

明らかに、このアプローチにはいくつかの欠点があります。誰かが(スクリプトを持っている場合と同様に)トークンとキーの両方を持っている場合、簡単に復号化できます。しかし、それは難読化し、コードを(Nuitkaのようなもので)コンパイルすると、少なくともパスワードは16進エディタでプレーンテキストとして表示されません。


0

これはあなたの質問に正確に答えるものではありませんが、関連しています。コメントとして追加するつもりでしたが、許可されませんでした。私はこれと同じ問題を扱ってきましたが、Jenkinsを使用するユーザーにスクリプトを公開することにしました。これにより、サーバー上で暗号化および保護され、管理者以外はアクセスできない個別のファイルにdb資格情報を保存できます。また、UIを作成し、実行を抑制するための簡単なショートカットも提供します。


0

スクリプトの外部でパスワードを保存し、実行時にパスワードを提供する可能性を検討することもできます

例:fred.py

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

のように実行できます

$ PASSWORD=password123 python fred.py
fred password123

「あいまいさによるセキュリティ」の追加レイヤーは、 base64(上記で提案したように)を使用して、コードであまり明確でない名前を使用し、実際のパスワードをコードから遠ざけるます。

コードがリポジトリにある場合、シークレットをその外部保存すると便利なことがよくあります。そのため、これを~/.bashrc(またはボールトや起動スクリプトなどに)追加できます。

export SURNAME=cGFzc3dvcmQxMjM=

そして、変更fred.py

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

その後、再ログインして

$ python fred.py
fred password123

0

単純なxorがないのはなぜですか?

利点:

  • バイナリデータのように見える
  • キーを知らなくても誰もそれを読むことができません(たとえそれが単一の文字であっても)

一般的な単語やrot13についても単純なb64文字列を認識するようになりました。Xorはそれをはるかに難しくします。



-1

'ネット上のPythonで書かれたいくつかのROT13ユーティリティがあります-それらのためのグーグル。ROT13は文字列をオフラインでエンコードし、それをソースにコピーし、送信ポイントでデコードします。

しかし、これは本当に弱い保護です...


この回答をより役立つものにするには、リンクまたはサンプルコードを含めてください
Micah Stubbs
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.