파이썬 스크립트에서 비밀번호 숨기기 (안전하지 않은 난독 화만 해당)


127

ODBC 연결을 생성하는 Python 스크립트가 있습니다. ODBC 연결은 연결 문자열로 생성됩니다. 이 연결 문자열에이 연결의 사용자 이름과 비밀번호를 포함시켜야합니다.

파일 에서이 암호를 숨기는 쉬운 방법이 있습니까 (파일을 편집 할 때 아무도 암호를 읽을 수 없도록)?


16
이 파일을 실행하는 사용자는 최소한이 파일에 대한 읽기 권한이 있으며 암호를 쉽게 얻을 수 있습니다. 얇은 부분은 당신 만 읽을 수 있고 어깨 너머로 그것을 보는 사람들에 대해 걱정하고 있지만, 평범한 관찰자가 암호를 잡을만큼 빨리 물건을 암기 할 수는 없지만 스크립트에 액세스 할 수있는 사람은 약간의 기술적 노하우와 적은 양의 야심이 암호를 얻을 수 있습니다. 항상 보안을 매우 신중하게 생각하는 것이 중요합니다.
Youarefunny

답변:


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
그러나 스크립트를 실행하는 사용자가 스크립트를 읽을 수 있어야하고 암호는 사용하지 않아야한다는 사실에는 도움이되지 않습니다.
Martin Beckett

79
나는 이 맥락에서 base64보다 더 난독 화 한다고 생각하지 않습니다 rot13. 반대로, base64전형적인 특성 (등호, ...)을 가지므로 다른 접근 방식보다 쉽게 ​​감지 할 수 있습니다. 그러나 모든 난독 화에는 실질적인 이점이 없습니다. 이 답변이 높은 평가를 받았다는 것은 정말 나쁜 일입니다. 그것은 단지 잘못된
안전감을

12
스크립트에서 사용할 수 있도록 비밀번호를 기록하는 경우 스크립트에 액세스 할 수있는 모든 사용자는 사용하는 암호화 방법에 상관없이 비밀번호를 얻을 수 있습니다. 여기서 요구 사항은 암호가 열려있는 동안 스크립트를보고있는 누군가로부터 암호를 숨기는 것이 었습니다. 이 경우 base64에 바람직하다 rot13는 파이썬 표준 라이브러리에있다.
Dave Webb

17
base64는 암호화가 아닙니다. 가장 난독 화입니다.
csgeek

52

Douglas F Shearer는 원격 로그인 암호를 지정해야 할 때 Unix에서 일반적으로 승인 된 솔루션입니다. --password-from-file 옵션을
추가 하여 경로를 지정하고 파일에서 일반 텍스트를 읽습니다. 파일은 운영 체제에 의해 보호되는 사용자 자신의 영역에있을 수 있습니다. 또한 다른 사용자가 자신의 파일을 자동으로 선택할 수 있습니다.

스크립트 사용자가 알 수없는 비밀번호의 경우, 권한을 높이고 스크립트를 실행하고 해당 루트 / 관리자 사용자가 비밀번호 파일을 소유 할 수 있습니다.


1
루트 또는 관리자 암호를 제공하지 않고 상승 된 권한으로 스크립트를 정확히 어떻게 실행합니까? UID 비트 설정과 관련이 있습니까?
Youarefunny

4
내가 알아 냈어 상관 없어. 관심있는 다른 사람 : 스크립트에 setuid 비트가 설정되어 있으면 OS가 setuid 비트를 인터프리터에게 '전달' 합니다. 불행히도 방대한 보안 허점이있어 대부분의 최신 배포판은 스크립트의 setuid를 해제합니다.
Youarefunny

--password-from-file 옵션에 대한 정보를 찾을 수 없습니다. 예가 있습니까? 감사!
pyramidface

@pyramidface-나는 당신이 이와 같은 기능을 코딩하고 파일에서 암호를 읽는 기능을 추가한다는 것을 의미했습니다
Martin Beckett

@MartinBeckett하지만 Youarefunny와 마찬가지로 스크립트에서 비밀번호 파일에 루트 액세스 권한을 부여하려면 Python에서 setuid를 제기해야합니까?
pyramidface

51

간단한 방법은 다음과 같습니다.

  1. 파이썬 모듈 만들기-peekaboo.py라고하겠습니다.
  2. peekaboo.py에 비밀번호와 해당 비밀번호가 필요한 코드를 모두 포함하십시오.
  3. 이 모듈을 가져 와서 (python 명령 줄 등을 통해) 컴파일 된 버전 (peekaboo.pyc)을 만듭니다.
  4. 이제 peekaboo.py를 삭제하십시오.
  5. peekaboo.pyc에만 의존하여 peekaboo를 행복하게 가져올 수 있습니다. peekaboo.pyc는 바이트 컴파일되므로 일반 사용자는 읽을 수 없습니다.

이것은 py_to_pyc 디 컴파일러에 취약하지만 base64 디코딩보다 조금 더 안전해야합니다.


2
이것은 여전히 ​​몇 가지 단점이 있지만 실제로는 내가 원하는 것과 매우 가깝습니다. 암호를 화면에 표시하거나 명령 프롬프트에 입력하지 않고도 사용자 / 암호 연결이 포함 된 Python 스크립트를 시연 할 수 있습니다. import peekabopeekaboo.passwordpassword='secret'
peekaboo를

8
당신이 한 단계 더이 아이디어를 가지고 싶다면, 당신이 사용할 수있는 사이 썬를 함으로써 ... (등, 맥 OS에 대한 .so를 Windows 용으로 .pyd 전)가 C에 어떤 평 파일을 컴파일 및 플랫폼 특정 바이너리를 생성하는 cythonizing스크립트 생성 된 바이너리를 공유하면이 답변의 이점을 얻고 + 난독 화 계층을 추가 할 수 있습니다. 이제 암호를 얻기 위해 C 코드를 디 컴파일해야합니다. 100 % 안전하지는 않지만 숨기려는 민감한 데이터를 얻으려면 많은 노력이 필요합니다.
Fnord

cythonizing, perfect
Arno

29

유닉스 시스템에서 작업하는 경우 표준 Python 라이브러리에서 netrc 모듈을 활용하십시오. 별도의 텍스트 파일 (.netrc)에서 암호를 읽습니다 . 형식은 here 입니다.

다음은 작은 사용 예입니다.

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은 수동으로 해독하기가 너무 쉽고 대소 문자를 구분하지 않으며 암호화 된 상태에서 너무 많은 의미를 유지합니다. 파이썬 스크립트 외부에서 비밀번호와 사용자 ID를 인코딩하십시오. 런타임시 스크립트 디코딩을 사용하도록합니다.

자동화 된 작업에 대한 스크립트 자격 증명을 제공하는 것은 항상 위험한 제안입니다. 스크립트에는 자체 자격 증명이 있어야하며 사용하는 계정에는 필요한 것 이외의 액세스 권한이 없어야합니다. 최소한 암호는 길고 임의적이어야합니다.


아주 좋은 답변-감사합니다. 내가 쓰고있는 작은 스크립트의 경우 (어쨌든 유지 관리 스크립트-BASE64 인코딩이면 충분 함)
bernhardrusch

2
이것은 좋은 것처럼 들리지만 구현 예제를 줄 수 있습니까? 지금은 일반적인 관행에 대한 설명 일 뿐이며, 이전에는 다른 사람에게 유용하지 않았습니다.
Dannid

18

스크립트 외부의 파일에서 사용자 이름과 비밀번호를 가져 오는 것은 어떻습니까? 그렇게하면 누군가 스크립트를 가지고 있어도 자동으로 암호를 얻지 못할 것입니다.


15

base64는 간단한 요구를 충족시키는 방법입니다. 아무것도 가져올 필요가 없습니다 :

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

2
정확히 무엇입니까?! 전체 답장 또는 수입하지 않는 부분?
tzot

18
Base64는 보안의 환상만을 추가합니다.
FlySwat

13
조나단, 질문을 읽지 않은 것 같습니다. 그것은 관하여 무명 (아주 일시적 일),하지 보안 당신이 내 대답은 도움이되지 고려 왜 이해하지 않도록.
tzot

1
나는 base64 모듈을 사용하는 대신 이것을 할 수 있다는 것을 몰랐다. 그리고 zlib와 같은 인코딩도 많이 있습니다 ... fun :)
Kiv

1
@Dennis 오늘날 base64 모듈을 사용하는 것이 좋습니다. 후자는 더 최신 버전의 Python에서 더 이상 작동하지 않습니다.
Jeyekomon

5

대한 python3의 난독 사용 base64다르게 이루어집니다 :

import base64
base64.b64encode(b'PasswordStringAsStreamOfBytes')

결과

b'UGFzc3dvcmRTdHJpbmdBc1N0cmVhbU9mQnl0ZXM='

비공식 문자열 표현에 유의하십시오. 실제 문자열은 따옴표로 묶습니다.

원래 문자열로 다시 디코딩

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

문자열 객체가 필요한 경우이 결과를 사용하기 위해 bytes 객체를 번역 할 수 있습니다

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

python3이 바이트 (및 이에 따라 문자열)를 처리하는 방법에 대한 자세한 내용은 공식 설명서 를 참조하십시오 .


4

이것은 매우 일반적인 문제입니다. 일반적으로 할 수있는 최선의 방법은

A) rot13이 아닌 인코딩 / 디코딩을위한 일종의 ceasar cipher 함수를 생성하거나

B) 선호되는 방법은 프로그램이 접근 할 수있는 곳에 암호화 키를 사용하여 암호를 인코딩 / 디코딩하는 것입니다. 파일 보호를 사용하여 액세스 키를 보호 할 수 있습니다.

이러한 라인을 따라 앱이 서비스 / 데몬 (웹 서버와 같은)으로 실행되는 경우 서비스 시작의 일부로 비밀번호를 입력하여 키를 비밀번호로 보호 된 키 저장소에 넣을 수 있습니다. 앱을 다시 시작하려면 관리자가 필요하지만 구성 비밀번호에 대한 예측은 훌륭합니다.


2

운영 체제는 데이터를 안전하게 암호화하기위한 기능을 제공 할 수 있습니다. 예를 들어, Windows에는 DPAPI (데이터 보호 API)가 있습니다. 처음 실행할 때 사용자에게 자격 증명을 요청한 다음 후속 실행을 위해 암호화하여 다람쥐를 빼 내지 않겠습니까?


2

인증 / 암호 / 사용자 이름을 암호화 된 세부 정보로 변환하는 대신보다 자체 개발 한 접근 방식입니다. FTPLIB 는 단지 예일 뿐입니다. " pass.csv "는 csv 파일 이름입니다.

아래와 같이 CSV로 비밀번호를 저장하십시오.

사용자 이름

사용자 암호

(열 제목 없음)

CSV를 읽고 목록에 저장하십시오.

인증 정보로 List elelments를 사용합니다.

전체 코드.

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 전용 (버전 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

@successhawk이 지적했듯이 "pit"에 대한 github / pypi 링크에는 어떤 문서도 보이지 않지만 위의 설명은 명확합니다. 전반적으로 쉬운보기에서 자격 증명을 "숨김"하기 위해이 솔루션을 좋아합니다 ...
netdesignate

유지 관리되지 않는 모듈을 사용하는 것을 꺼려하며 지시에 따라 사용하려고하면 오류가 발생합니다./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

내가 한 방법은 다음과 같습니다.

파이썬 쉘에서 :

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

'Net에서 파이썬으로 작성된 여러 ROT13 유틸리티가 있습니다-단지 구글을 위해. ROT13은 문자열을 오프라인으로 인코딩하고 소스에 복사하고 전송 지점에서 디코딩합니다.

그러나 이것은 실제로 약한 보호입니다 ...


이 답변이 더 유용하도록 링크 또는 샘플 코드를 포함하십시오
Micah Stubbs
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.