标签归档:security

在python脚本中隐藏密码(仅用于不安全的混淆)

问题:在python脚本中隐藏密码(仅用于不安全的混淆)

我有一个python脚本正在创建ODBC连接。ODBC连接是使用连接字符串生成的。在此连接字符串中,我必须包含此连接的用户名和密码。

有没有一种简便的方法来隐藏文件中的此密码(只是在我编辑文件时没人能读取该密码)?

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


回答 0

Base64编码在标准库中,并且可以阻止肩膀冲浪者:

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

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

回答 1

当您需要为远程登录指定密码时,Douglas F Shearer’s是Unix中公认的解决方案。
您添加–password-from-file选项来指定路径并从文件中读取纯文本。
然后,该文件可以位于受操作系统保护的用户自己的区域中。它还允许不同的用户自动选择自己的文件。

对于不允许脚本用户知道的密码-您可以使用高级权限运行脚本,并让该root / admin用户拥有密码文件。

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.


回答 2

这是一个简单的方法:

  1. 创建一个python模块-我们称之为peekaboo.py。
  2. 在peekaboo.py中,同时包含密码和需要该密码的任何代码
  3. 通过导入此模块(通过python命令行等)创建一个编译版本-peekaboo.pyc。
  4. 现在,删除peekaboo.py。
  5. 现在,您可以仅依靠peekaboo.pyc来愉快地导入peekaboo。由于peekaboo.pyc是字节编译的,因此临时用户无法读取。

尽管它容易受到py_to_pyc反编译器的攻击,但它应该比base64解码更加安全。

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.


回答 3

如果您在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

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

回答 4

假设用户无法在运行时提供用户名和密码,最好的解决方案可能是单独的源文件,其中仅包含导入到您的主代码中的用户名和密码的变量初始化。仅在凭据更改时才需要编辑此文件。否则,如果您只担心具有平均记忆的冲浪者,那么base 64编码可能是最简单的解决方案。ROT13太容易手动解码,不区分大小写,并且在加密状态下保留了太多含义。在python脚本之外对您的密码和用户ID进行编码。让他在运行时对脚本进行解码以供使用。

为自动化任务提供脚本凭证始终是一个冒险的建议。您的脚本应具有其自己的凭据,并且所使用的帐户应完全不需要访问权限。至少密码应该是长且相当随机的。

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.


回答 5

如何从脚本外部的文件中导入用户名和密码?这样,即使有人掌握了该脚本,他们也不会自动获得密码。

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.


回答 6

base64是满足您简单需求的方法。无需导入任何内容:

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

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'

回答 7

对于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如何处理字节(以及相应的字符串)的更多信息,请参见官方文档

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.


回答 8

这是一个很常见的问题。通常,您能做的最好的就是

A)创建某种ceasar密码函数来进行编码/解码(但不是rot13)或

B)首选方法是在程序可及的范围内使用加密密钥对密码进行编码/解码。您可以在其中使用文件保护来保护访问密钥。

如果您的应用程序作为服务/守护程序(例如Web服务器)运行,则可以将密钥放入密码保护的密钥库中,并在服务启动过程中输入密码。管理员需要重新启动您的应用程序,但是您对配置密码的保护非常好。

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.


回答 9

您的操作系统可能提供了用于安全加密数据的工具。例如,在Windows上有DPAPI(数据保护API)。为什么不在第一次运行时要求用户提供其凭据,然后将其松散加密以进行后续运行?

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?


回答 10

更多本地化的方式,而不是将身份验证/密码/用户名转换为加密的详细信息。FTPLIB只是示例。“ pass.csv ”是csv文件名

将密码保存为CSV格式,如下所示:

用户名

用户密码

(无列标题)

读取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])

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

回答 11

这是我的摘录。您基本上是将函数导入或复制到代码中。如果加密文件不存在,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()

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

回答 12

将配置信息放置在加密的配置文件中。使用键在代码中查询此信息。将该密钥放在每个环境的单独文件中,不要将其与代码一起存储。

Place the configuration information in a encrypted config file. Query this info in your code using an key. Place this key in a separate file per environment, and don’t store it with your code.


回答 13

你知道坑吗?

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

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

回答 14

如果在Windows上运行,则可以考虑使用win32crypt库。它允许运行脚本的用户存储和检索受保护的数据(键,密码),因此,密码永远不会以明文或混淆格式存储在代码中。我不确定其他平台是否有等效的实现,因此如果严格使用win32crypt,您的代码将无法移植。

我相信可以在这里获得该模块:http : //timgolden.me.uk/pywin32-docs/win32crypt.html

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


回答 15

我执行此操作的方法如下:

在python shell上:

>>> 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之类的代码),则至少您的密码不会在十六进制编辑器中显示为纯文本。

A way that I have done this is as follows:

At the python shell:

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

Then, create a module with the following 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')

Once you’ve done this, you can either import mypassword directly or you can import the token and cipher to decrypt as needed.

Obviously, there are some shortcomings to this approach. If someone has both the token and the key (as they would if they have the script), they can decrypt easily. However it does obfuscate, and if you compile the code (with something like Nuitka) at least your password won’t appear as plain text in a hex editor.


回答 16

这并不能完全回答您的问题,但却是相关的。我本来想添加评论,但不允许。我一直在处理同一问题,因此我们决定使用Jenkins将脚本公开给用户。这使我们可以将数据库凭据存储在单独的文件中,该文件在服务器上已加密并受保护,并且非管理员无法访问。它还为我们提供了一些创建UI和限制执行的捷径。

This doesn’t precisely answer your question, but it’s related. I was going to add as a comment but wasn’t allowed. I’ve been dealing with this same issue, and we have decided to expose the script to the users using Jenkins. This allows us to store the db credentials in a separate file that is encrypted and secured on a server and not accessible to non-admins. It also allows us a bit of a shortcut to creating a UI, and throttling execution.


回答 17

您还可以考虑将密码存储在脚本外部并在运行时提供密码的可能性

例如fred.py

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

可以像

$ PASSWORD=password123 python fred.py
fred password123

可以通过使用base64(如上所述),在代码中使用不太明显的名称以及使实际密码与代码之间的距离进一步达到“通过模糊性实现安全性” 的目的。

如果代码位于存储库中,通常将机密存储在存储库之外很有用,因此可以将其添加到~/.bashrc(或添加到Vault或启动脚本中,…)

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

You could also consider the possibility of storing the password outside the script, and supplying it at runtime

e.g. fred.py

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

which can be run like

$ PASSWORD=password123 python fred.py
fred password123

Extra layers of “security through obscurity” can be achieved by using base64 (as suggested above), using less obvious names in the code and further distancing the actual password from the code.

If the code is in a repository, it is often useful to store secrets outside it, so one could add this to ~/.bashrc (or to a vault, or a launch script, …)

export SURNAME=cGFzc3dvcmQxMjM=

and change fred.py to

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

then re-login and

$ python fred.py
fred password123

回答 18

为什么不拥有简单的异或?

优点:

  • 看起来像二进制数据
  • 任何人都无法在不知道键的情况下读取它(即使它是一个字符)

我到了可以识别普通单词和rot13的简单b64字符串的地步。Xor会让它变得更加困难。

Why not have a simple xor?

Advantages:

  • looks like binary data
  • noone can read it without knowing the key (even if it’s a single char)

I get to the point where I recognize simple b64 strings for common words and rot13 as well. Xor would make it much harder.


回答 19

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

回答 20

在网上有几种用Python编写的ROT13实用程序-只是谷歌搜索它们。ROT13离线编码字符串,将其复制到源中,然后在传输点解码。

但这确实是薄弱的保护…

There are several ROT13 utilities written in Python on the ‘Net — just google for them. ROT13 encode the string offline, copy it into the source, decode at point of transmission.

But this is really weak protection…


Python 3.3中的哈希函数在会话之间返回不同的结果

问题:Python 3.3中的哈希函数在会话之间返回不同的结果

我已经在python 3.3中实现了BloomFilter,并且每次会话都得到不同的结果。深入研究这种奇怪的行为,使我进入了内部hash()函数-它在每个会话中为同一字符串返回不同的哈希值。

例:

>>> hash("235")
-310569535015251310

—–打开一个新的python控制台—–

>>> hash("235")
-1900164331622581997

为什么会这样呢?为什么这有用?

I’ve implemented a BloomFilter in python 3.3, and got different results every session. Drilling down this weird behavior got me to the internal hash() function – it returns different hash values for the same string every session.

Example:

>>> hash("235")
-310569535015251310

—– opening a new python console —–

>>> hash("235")
-1900164331622581997

Why is this happening? Why is this useful?


回答 0

Python使用随机散列种子,通过向您发送旨在冲突的密钥来防止攻击者对应用程序进行处理。请参阅原始漏洞披露。通过使用随机种子(在启动时设置一次)偏移哈希值,攻击者无法再预测哪些键会发生冲突。

您可以通过设置PYTHONHASHSEED环境变量来设置固定种子或禁用功能;默认值为,random但您可以将其设置为固定的正整数值,同时0完全禁用该功能。

Python 2.7和3.2版本默认情况下禁用此功能(使用-R开关或设置PYTHONHASHSEED=random启用该功能);默认在Python 3.3及更高版本中启用它。

如果您依赖于Python集合中键的顺序,那么就不用了。Python使用哈希表来实现这些类型,它们的顺序取决于插入和删除的历史记录以及随机哈希种子。请注意,在Python 3.5及更低版本中,这也适用于字典。

另请参见object.__hash__()特殊方法文档

注意:默认情况下,__hash__()str,bytes和datetime对象的值使用不可预测的随机值“加盐”。尽管它们在单个Python进程中保持不变,但在重复调用Python之间是不可预测的。

这旨在提供保护,防止由于精心选择的输入而导致的拒绝服务,这些输入利用了dict插入的最坏情况的性能O(n ^ 2)复杂性。有关详细信息,请参见http://www.ocert.org/advisories/ocert-2011-003.html

更改哈希值会影响字典,集合和其他映射的迭代顺序。Python从未保证过这种顺序(通常在32位和64位版本之间有所不同)。

另请参阅PYTHONHASHSEED

如果需要稳定的哈希实现,则可能需要查看hashlib模块;这实现了加密哈希函数。该pybloom项目采用这种做法

由于偏移量由前缀和后缀(分别为起始值和最终XORed值)组成,因此,不幸的是,您不能仅存储偏移量。从正面来看,这确实意味着攻击者也无法通过定时攻击轻松确定偏移量。

Python uses a random hash seed to prevent attackers from tar-pitting your application by sending you keys designed to collide. See the original vulnerability disclosure. By offsetting the hash with a random seed (set once at startup) attackers can no longer predict what keys will collide.

You can set a fixed seed or disable the feature by setting the PYTHONHASHSEED environment variable; the default is random but you can set it to a fixed positive integer value, with 0 disabling the feature altogether.

Python versions 2.7 and 3.2 have the feature disabled by default (use the -R switch or set PYTHONHASHSEED=random to enable it); it is enabled by default in Python 3.3 and up.

If you were relying on the order of keys in a Python set, then don’t. Python uses a hash table to implement these types and their order depends on the insertion and deletion history as well as the random hash seed. Note that in Python 3.5 and older, this applies to dictionaries, too.

Also see the object.__hash__() special method documentation:

Note: By default, the __hash__() values of str, bytes and datetime objects are “salted” with an unpredictable random value. Although they remain constant within an individual Python process, they are not predictable between repeated invocations of Python.

This is intended to provide protection against a denial-of-service caused by carefully-chosen inputs that exploit the worst case performance of a dict insertion, O(n^2) complexity. See http://www.ocert.org/advisories/ocert-2011-003.html for details.

Changing hash values affects the iteration order of dicts, sets and other mappings. Python has never made guarantees about this ordering (and it typically varies between 32-bit and 64-bit builds).

See also PYTHONHASHSEED.

If you need a stable hash implementation, you probably want to look at the hashlib module; this implements cryptographic hash functions. The pybloom project uses this approach.

Since the offset consists of a prefix and a suffix (start value and final XORed value, respectively) you cannot just store the offset, unfortunately. On the plus side, this does mean that attackers cannot easily determine the offset with timing attacks either.


回答 1

默认情况下,Python 3中启用了哈希随机化。这是一个安全功能:

散列随机化旨在提供保护,防止由于精心选择的输入而导致的拒绝服务攻击,这些输入利用了dict构造的最坏情况性能

在2.6.8之前的版本中,可以使用-R或PYTHONHASHSEED环境选项在命令行中将其打开

您可以将其设置PYTHONHASHSEED为零以将其关闭。

Hash randomisation is turned on by default in Python 3. This is a security feature:

Hash randomization is intended to provide protection against a denial-of-service caused by carefully-chosen inputs that exploit the worst case performance of a dict construction

In previous versions from 2.6.8, you could switch it on at the command line with -R, or the PYTHONHASHSEED environment option.

You can switch it off by setting PYTHONHASHSEED to zero.


回答 2

hash()是Python的内置函数,可用于为对象而不是字符串或num 计算哈希值。

您可以在以下页面中查看详细信息:https : //docs.python.org/3.3/library/functions.html#hash

hash()值来自对象的__hash__方法。该文档说以下内容:

默认情况下,str,bytes和datetime对象的hash()值会以不可预测的随机值“成盐”。尽管它们在单个Python进程中保持不变,但在重复调用Python之间是不可预测的。

这就是为什么您在不同的控制台中对同一字符串具有不同的哈希值的原因。

您实施的方法不是一个好方法。

当您要计算字符串哈希值时,只需使用hashlib

hash()的目的是获取对象的哈希值,而不是搅动。

hash() is a Python built-in function and use it to calculate a hash value for object, not for string or num.

You can see the detail in this page: https://docs.python.org/3.3/library/functions.html#hash.

and hash() values comes from the object’s __hash__ method. The doc says the followings:

By default, the hash() values of str, bytes and datetime objects are “salted” with an unpredictable random value. Although they remain constant within an individual Python process, they are not predictable between repeated invocations of Python.

That’s why your have diffent hash value for the same string in different console.

What you implement is not a good way.

When you want to calculate a string hash value, just use hashlib

hash() is aim to get a object hash value, not a stirng.


我需要在Python中安全地存储用户名和密码,我有哪些选择?

问题:我需要在Python中安全地存储用户名和密码,我有哪些选择?

我正在编写一个小的Python脚本,该脚本将使用用户名和密码组合定期从第三方服务中获取信息。我不需要创建100%防弹的东西(甚至存在100%的东西吗?),但是我想采用一种很好的安全措施,因此至少有人要花很长时间才能破解它。

该脚本没有GUI,将由定期运行cron,因此每次运行解密内容时都不会真正输入密码,因此我必须将用户名和密码存储在加密文件或加密文件中在SQLite数据库中,这将是更好的选择,因为无论如何我都将使用SQLite,并且可能需要在某个时候编辑密码。另外,我可能会将整个程序包装在EXE中,因为这时它仅适用于Windows。

如何安全地存储通过cron作业定期使用的用户名和密码组合?

I’m writing a small Python script which will periodically pull information from a 3rd party service using a username and password combo. I don’t need to create something that is 100% bulletproof (does 100% even exist?), but I would like to involve a good measure of security so at the very least it would take a long time for someone to break it.

This script won’t have a GUI and will be run periodically by cron, so entering a password each time it’s run to decrypt things won’t really work, and I’ll have to store the username and password in either an encrypted file or encrypted in a SQLite database, which would be preferable as I’ll be using SQLite anyway, and I might need to edit the password at some point. In addition, I’ll probably be wrapping the whole program in an EXE, as it’s exclusively for Windows at this point.

How can I securely store the username and password combo to be used periodically via a cron job?


回答 0

我推荐一种类似于ssh-agent的策略。如果您不能直接使用ssh-agent,则可以实现类似的方法,以便密码仅保存在RAM中。cron作业可能已经配置了凭据,以便在每次运行时从代理获取实际密码,一次使用,然后立即使用该del语句取消引用。

管理员仍必须在启动时或在启动时输入密码以启动ssh-agent,但这是一个合理的折衷方案,可以避免将纯文本密码存储在磁盘上的任何位置。

I recommend a strategy similar to ssh-agent. If you can’t use ssh-agent directly you could implement something like it, so that your password is only kept in RAM. The cron job could have configured credentials to get the actual password from the agent each time it runs, use it once, and de-reference it immediately using the del statement.

The administrator still has to enter the password to start ssh-agent, at boot-time or whatever, but this is a reasonable compromise that avoids having a plain-text password stored anywhere on disk.


回答 1

Python钥匙圈库集成了CryptProtectData在Windows API(以及Mac和Linux相关的API)进行加密与用户的登录凭据数据。

简单用法:

import keyring

# the service is just a namespace for your app
service_id = 'IM_YOUR_APP!'

keyring.set_password(service_id, 'dustin', 'my secret password')
password = keyring.get_password(service_id, 'dustin') # retrieve password

要将用户名存储在密钥环上的用法:

import keyring

MAGIC_USERNAME_KEY = 'im_the_magic_username_key'

# the service is just a namespace for your app
service_id = 'IM_YOUR_APP!'  

username = 'dustin'

# save password
keyring.set_password(service_id, username, "password")

# optionally, abuse `set_password` to save username onto keyring
# we're just using some known magic string in the username field
keyring.set_password(service_id, MAGIC_USERNAME_KEY, username)

稍后从钥匙圈获取您的信息

# again, abusing `get_password` to get the username.
# after all, the keyring is just a key-value store
username = keyring.get_password(service_id, MAGIC_USERNAME_KEY)
password = keyring.get_password(service_id, username)  

使用用户的操作系统凭据对项目进行加密,因此,以您的用户帐户运行的其他应用程序将能够访问密码。

为了稍微掩盖该漏洞,您可以在将密码存储在密钥环上之前以某种方式对密码进行加密/混淆。当然,任何以您的脚本为目标的人都只能查看源代码,并弄清楚如何对密码进行解密/取消混淆,但是您至少要防止某些应用程序清除库中的所有密码并获取您的密码。 。

The python keyring library integrates with the CryptProtectData API on Windows (along with relevant API’s on Mac and Linux) which encrypts data with the user’s logon credentials.

Simple usage:

import keyring

# the service is just a namespace for your app
service_id = 'IM_YOUR_APP!'

keyring.set_password(service_id, 'dustin', 'my secret password')
password = keyring.get_password(service_id, 'dustin') # retrieve password

Usage if you want to store the username on the keyring:

import keyring

MAGIC_USERNAME_KEY = 'im_the_magic_username_key'

# the service is just a namespace for your app
service_id = 'IM_YOUR_APP!'  

username = 'dustin'

# save password
keyring.set_password(service_id, username, "password")

# optionally, abuse `set_password` to save username onto keyring
# we're just using some known magic string in the username field
keyring.set_password(service_id, MAGIC_USERNAME_KEY, username)

Later to get your info from the keyring

# again, abusing `get_password` to get the username.
# after all, the keyring is just a key-value store
username = keyring.get_password(service_id, MAGIC_USERNAME_KEY)
password = keyring.get_password(service_id, username)  

Items are encrypted with the user’s operating system credentials, thus other applications running in your user account would be able to access the password.

To obscure that vulnerability a bit you could encrypt/obfuscate the password in some manner before storing it on the keyring. Of course, anyone who was targeting your script would just be able to look at the source and figure out how to unencrypt/unobfuscate the password, but you’d at least prevent some application vacuuming up all passwords in the vault and getting yours as well.


回答 2

在查看了有关此问题和相关问题的答案之后,我使用一些建议的加密和隐藏秘密数据的方法整理了一些代码。此代码专门用于脚本必须在没有用户干预的情况下运行的情况(如果用户手动启动该脚本,则最好将其放入密码中,并仅将其保存在内存中,以解决此问题)。这种方法不是超级安全的。从根本上讲,脚本可以访问机密信息,因此具有完全系统访问权限的任何人都可以使用脚本及其关联文件,并且可以访问它们。id的作用是使偶然检查的数据变得模糊不清,并且如果对数据文件进行单独检查或一起检查而不使用脚本,则数据文件本身将保持安全。

我这样做的动机是通过一个项目对我的一些银行帐户进行轮询以监视交易-我需要它在后台运行,而不必每隔一两分钟重新输入一次密码。

只需将此代码粘贴到脚本的顶部,更改saltSeed,然后根据需要在代码中使用store(),retrieve()和require():

from getpass import getpass
from pbkdf2 import PBKDF2
from Crypto.Cipher import AES
import os
import base64
import pickle


### Settings ###

saltSeed = 'mkhgts465wef4fwtdd' # MAKE THIS YOUR OWN RANDOM STRING

PASSPHRASE_FILE = './secret.p'
SECRETSDB_FILE = './secrets'
PASSPHRASE_SIZE = 64 # 512-bit passphrase
KEY_SIZE = 32 # 256-bit key
BLOCK_SIZE = 16  # 16-bit blocks
IV_SIZE = 16 # 128-bits to initialise
SALT_SIZE = 8 # 64-bits of salt


### System Functions ###

def getSaltForKey(key):
    return PBKDF2(key, saltSeed).read(SALT_SIZE) # Salt is generated as the hash of the key with it's own salt acting like a seed value

def encrypt(plaintext, salt):
    ''' Pad plaintext, then encrypt it with a new, randomly initialised cipher. Will not preserve trailing whitespace in plaintext!'''

    # Initialise Cipher Randomly
    initVector = os.urandom(IV_SIZE)

    # Prepare cipher key:
    key = PBKDF2(passphrase, salt).read(KEY_SIZE)

    cipher = AES.new(key, AES.MODE_CBC, initVector) # Create cipher

    return initVector + cipher.encrypt(plaintext + ' '*(BLOCK_SIZE - (len(plaintext) % BLOCK_SIZE))) # Pad and encrypt

def decrypt(ciphertext, salt):
    ''' Reconstruct the cipher object and decrypt. Will not preserve trailing whitespace in the retrieved value!'''

    # Prepare cipher key:
    key = PBKDF2(passphrase, salt).read(KEY_SIZE)

    # Extract IV:
    initVector = ciphertext[:IV_SIZE]
    ciphertext = ciphertext[IV_SIZE:]

    cipher = AES.new(key, AES.MODE_CBC, initVector) # Reconstruct cipher (IV isn't needed for edecryption so is set to zeros)

    return cipher.decrypt(ciphertext).rstrip(' ') # Decrypt and depad


### User Functions ###

def store(key, value):
    ''' Sore key-value pair safely and save to disk.'''
    global db

    db[key] = encrypt(value, getSaltForKey(key))
    with open(SECRETSDB_FILE, 'w') as f:
        pickle.dump(db, f)

def retrieve(key):
    ''' Fetch key-value pair.'''
    return decrypt(db[key], getSaltForKey(key))

def require(key):
    ''' Test if key is stored, if not, prompt the user for it while hiding their input from shoulder-surfers.'''
    if not key in db: store(key, getpass('Please enter a value for "%s":' % key))


### Setup ###

# Aquire passphrase:
try:
    with open(PASSPHRASE_FILE) as f:
        passphrase = f.read()
    if len(passphrase) == 0: raise IOError
except IOError:
    with open(PASSPHRASE_FILE, 'w') as f:
        passphrase = os.urandom(PASSPHRASE_SIZE) # Random passphrase
        f.write(base64.b64encode(passphrase))

        try: os.remove(SECRETSDB_FILE) # If the passphrase has to be regenerated, then the old secrets file is irretrievable and should be removed
        except: pass
else:
    passphrase = base64.b64decode(passphrase) # Decode if loaded from already extant file

# Load or create secrets database:
try:
    with open(SECRETSDB_FILE) as f:
        db = pickle.load(f)
    if db == {}: raise IOError
except (IOError, EOFError):
    db = {}
    with open(SECRETSDB_FILE, 'w') as f:
        pickle.dump(db, f)

### Test (put your code here) ###
require('id')
require('password1')
require('password2')
print
print 'Stored Data:'
for key in db:
    print key, retrieve(key) # decode values on demand to avoid exposing the whole database in memory
    # DO STUFF

如果在秘密文件上设置os权限以仅允许脚本本身读取它们,并且脚本本身被编译并标记为仅可执行文件(不可读),则该方法的安全性将得到显着提高。其中一些可以自动化,但是我没有打扰。可能需要为该脚本设置一个用户,然后以该用户身份运行该脚本(并将脚本文件的所有权设置给该用户)。

我喜欢任何人都能想到的任何建议,批评或其他弱点。我对编写加密代码非常陌生,因此我所做的工作几乎可以肯定会得到改善。

After looking though the answers to this and related questions, I’ve put together some code using a few of the suggested methods for encrypting and obscuring secret data. This code is specifically for when the script has to run without user intervention (if the user starts it manually, it’s best to have them put in the password and only keep it in memory as the answer to this question suggests). This method isn’t super-secure; fundamentally, the script can access the secret info so anyone who has full system access has the script and its associated files and can access them. What this does do id obscures the data from casual inspection and leaves the data files themselves secure if they are examined individually, or together without the script.

My motivation for this is a project that polls some of my bank accounts to monitor transactions – I need it to run in the background without me re-entering passwords every minute or two.

Just paste this code at the top of your script, change the saltSeed and then use store() retrieve() and require() in your code as needed:

from getpass import getpass
from pbkdf2 import PBKDF2
from Crypto.Cipher import AES
import os
import base64
import pickle


### Settings ###

saltSeed = 'mkhgts465wef4fwtdd' # MAKE THIS YOUR OWN RANDOM STRING

PASSPHRASE_FILE = './secret.p'
SECRETSDB_FILE = './secrets'
PASSPHRASE_SIZE = 64 # 512-bit passphrase
KEY_SIZE = 32 # 256-bit key
BLOCK_SIZE = 16  # 16-bit blocks
IV_SIZE = 16 # 128-bits to initialise
SALT_SIZE = 8 # 64-bits of salt


### System Functions ###

def getSaltForKey(key):
    return PBKDF2(key, saltSeed).read(SALT_SIZE) # Salt is generated as the hash of the key with it's own salt acting like a seed value

def encrypt(plaintext, salt):
    ''' Pad plaintext, then encrypt it with a new, randomly initialised cipher. Will not preserve trailing whitespace in plaintext!'''

    # Initialise Cipher Randomly
    initVector = os.urandom(IV_SIZE)

    # Prepare cipher key:
    key = PBKDF2(passphrase, salt).read(KEY_SIZE)

    cipher = AES.new(key, AES.MODE_CBC, initVector) # Create cipher

    return initVector + cipher.encrypt(plaintext + ' '*(BLOCK_SIZE - (len(plaintext) % BLOCK_SIZE))) # Pad and encrypt

def decrypt(ciphertext, salt):
    ''' Reconstruct the cipher object and decrypt. Will not preserve trailing whitespace in the retrieved value!'''

    # Prepare cipher key:
    key = PBKDF2(passphrase, salt).read(KEY_SIZE)

    # Extract IV:
    initVector = ciphertext[:IV_SIZE]
    ciphertext = ciphertext[IV_SIZE:]

    cipher = AES.new(key, AES.MODE_CBC, initVector) # Reconstruct cipher (IV isn't needed for edecryption so is set to zeros)

    return cipher.decrypt(ciphertext).rstrip(' ') # Decrypt and depad


### User Functions ###

def store(key, value):
    ''' Sore key-value pair safely and save to disk.'''
    global db

    db[key] = encrypt(value, getSaltForKey(key))
    with open(SECRETSDB_FILE, 'w') as f:
        pickle.dump(db, f)

def retrieve(key):
    ''' Fetch key-value pair.'''
    return decrypt(db[key], getSaltForKey(key))

def require(key):
    ''' Test if key is stored, if not, prompt the user for it while hiding their input from shoulder-surfers.'''
    if not key in db: store(key, getpass('Please enter a value for "%s":' % key))


### Setup ###

# Aquire passphrase:
try:
    with open(PASSPHRASE_FILE) as f:
        passphrase = f.read()
    if len(passphrase) == 0: raise IOError
except IOError:
    with open(PASSPHRASE_FILE, 'w') as f:
        passphrase = os.urandom(PASSPHRASE_SIZE) # Random passphrase
        f.write(base64.b64encode(passphrase))

        try: os.remove(SECRETSDB_FILE) # If the passphrase has to be regenerated, then the old secrets file is irretrievable and should be removed
        except: pass
else:
    passphrase = base64.b64decode(passphrase) # Decode if loaded from already extant file

# Load or create secrets database:
try:
    with open(SECRETSDB_FILE) as f:
        db = pickle.load(f)
    if db == {}: raise IOError
except (IOError, EOFError):
    db = {}
    with open(SECRETSDB_FILE, 'w') as f:
        pickle.dump(db, f)

### Test (put your code here) ###
require('id')
require('password1')
require('password2')
print
print 'Stored Data:'
for key in db:
    print key, retrieve(key) # decode values on demand to avoid exposing the whole database in memory
    # DO STUFF

The security of this method would be significantly improved if os permissions were set on the secret files to only allow the script itself to read them, and if the script itself was compiled and marked as executable only (not readable). Some of that could be automated, but I haven’t bothered. It would probably require setting up a user for the script and running the script as that user (and setting ownership of the script’s files to that user).

I’d love any suggestions, criticisms or other points of vulnerability that anyone can think of. I’m pretty new to writing crypto code so what I’ve done could almost certainly be improved.


回答 3

有一些选项可以存储Python程序需要使用的密码和其他机密信息,特别是需要在后台运行的程序,它不能仅仅要求用户输入密码。

应避免的问题:

  1. 将密码签入源代码管理,其他开发人员甚至公众都可以在其中看到它。
  2. 同一服务器上的其他用户从配置文件或源代码中读取密码。
  3. 将密码保存在源文件中,其他人在编辑时可以在您的肩膀上看到它。

选项1:SSH

这并不总是一个选择,但可能是最好的选择。您的私钥永远不会通过网络传输,SSH只是运行数学计算以证明您拥有正确的密钥。

为了使其工作,您需要以下内容:

  • 需要通过SSH访问数据库或您正在访问的任何内容。尝试搜索“ SSH”以及您正在访问的任何服务。例如,“ ssh postgresql”。如果这不是您数据库的功能,请转到下一个选项。
  • 创建一个帐户来运行将调用数据库的服务,并生成一个SSH密钥
  • 将公钥添加到要调用的服务中,或者在该服务器上创建本地帐户,然后在此处安装公钥。

选项2:环境变量

这是最简单的一个,因此它可能是一个不错的起点。十二因子应用程序对此进行了很好的描述。基本思想是,您的源代码只是从环境变量中提取密码或其他机密,然后在运行程序的每个系统上配置这些环境变量。如果您使用适用于大多数开发人员的默认值,则可能也很不错。您必须权衡这与使软件“默认情况下安全”有关。

这是一个从环境变量中提取服务器,用户名和密码的示例。

import os

server = os.getenv('MY_APP_DB_SERVER', 'localhost')
user = os.getenv('MY_APP_DB_USER', 'myapp')
password = os.getenv('MY_APP_DB_PASSWORD', '')

db_connect(server, user, password)

查找如何在操作系统中设置环境变量,并考虑以其自己的帐户运行服务。这样,当您使用自己的帐户运行程序时,环境变量中不会包含敏感数据。设置这些环境变量时,请格外小心,以免其他用户无法读取它们。例如,检查文件权限。当然,具有root权限的任何用户都可以阅读它们,但这无济于事。

选项3:配置文件

这与环境变量非常相似,但是您从文本文件中读取机密。我仍然发现环境变量在部署工具和持续集成服务器等方面更灵活。如果决定使用配置文件,Python会在标准库中支持几种格式,例如JSONINInetrcXML。您还可以找到外部软件包,例如PyYAMLTOML。就个人而言,我发现JSON和YAML最容易使用,并且YAML允许注释。

配置文件要考虑的三件事:

  1. 文件在哪里?也许是默认位置(如~/.my_app)和命令行选项以使用其他位置。
  2. 确保其他用户无法读取该文件。
  3. 显然,不要将配置文件提交给源代码。您可能想要提交一个模板,用户可以将其复制到其主目录。

选项4:Python模块

一些项目只是将其秘密直接放入Python模块中。

# settings.py
db_server = 'dbhost1'
db_user = 'my_app'
db_password = 'correcthorsebatterystaple'

然后导入该模块以获取值。

# my_app.py
from settings import db_server, db_user, db_password

db_connect(db_server, db_user, db_password)

使用此技术的一个项目是Django。显然,settings.py尽管您可能想要提交一个名为settings_template.py用户可以复制和修改的文件,但您不应提交到源代码管理。

我发现此技术存在一些问题:

  1. 开发人员可能会不小心将文件提交给源代码管理。添加它可以.gitignore降低这种风险。
  2. 您的某些代码不受源代码控制。如果您训练有素,只在这里输入字符串和数字,那将不是问题。如果您在此处开始编写日志记录过滤器类,请停止!

如果您的项目已使用此技术,则很容易过渡到环境变量。只需将所有设置值移至环境变量,然后更改Python模块以从这些环境变量中读取。

There are a few options for storing passwords and other secrets that a Python program needs to use, particularly a program that needs to run in the background where it can’t just ask the user to type in the password.

Problems to avoid:

  1. Checking the password in to source control where other developers or even the public can see it.
  2. Other users on the same server reading the password from a configuration file or source code.
  3. Having the password in a source file where others can see it over your shoulder while you are editing it.

Option 1: SSH

This isn’t always an option, but it’s probably the best. Your private key is never transmitted over the network, SSH just runs mathematical calculations to prove that you have the right key.

In order to make it work, you need the following:

  • The database or whatever you are accessing needs to be accessible by SSH. Try searching for “SSH” plus whatever service you are accessing. For example, “ssh postgresql”. If this isn’t a feature on your database, move on to the next option.
  • Create an account to run the service that will make calls to the database, and generate an SSH key.
  • Either add the public key to the service you’re going to call, or create a local account on that server, and install the public key there.

Option 2: Environment Variables

This one is the simplest, so it might be a good place to start. It’s described well in the Twelve Factor App. The basic idea is that your source code just pulls the password or other secrets from environment variables, and then you configure those environment variables on each system where you run the program. It might also be a nice touch if you use default values that will work for most developers. You have to balance that against making your software “secure by default”.

Here’s an example that pulls the server, user name, and password from environment variables.

import os

server = os.getenv('MY_APP_DB_SERVER', 'localhost')
user = os.getenv('MY_APP_DB_USER', 'myapp')
password = os.getenv('MY_APP_DB_PASSWORD', '')

db_connect(server, user, password)

Look up how to set environment variables in your operating system, and consider running the service under its own account. That way you don’t have sensitive data in environment variables when you run programs in your own account. When you do set up those environment variables, take extra care that other users can’t read them. Check file permissions, for example. Of course any users with root permission will be able to read them, but that can’t be helped. If you’re using systemd, look at the service unit, and be careful to use EnvironmentFile instead of Environment for any secrets. Environment values can be viewed by any user with systemctl show.

Option 3: Configuration Files

This is very similar to the environment variables, but you read the secrets from a text file. I still find the environment variables more flexible for things like deployment tools and continuous integration servers. If you decide to use a configuration file, Python supports several formats in the standard library, like JSON, INI, netrc, and XML. You can also find external packages like PyYAML and TOML. Personally, I find JSON and YAML the simplest to use, and YAML allows comments.

Three things to consider with configuration files:

  1. Where is the file? Maybe a default location like ~/.my_app, and a command-line option to use a different location.
  2. Make sure other users can’t read the file.
  3. Obviously, don’t commit the configuration file to source code. You might want to commit a template that users can copy to their home directory.

Option 4: Python Module

Some projects just put their secrets right into a Python module.

# settings.py
db_server = 'dbhost1'
db_user = 'my_app'
db_password = 'correcthorsebatterystaple'

Then import that module to get the values.

# my_app.py
from settings import db_server, db_user, db_password

db_connect(db_server, db_user, db_password)

One project that uses this technique is Django. Obviously, you shouldn’t commit settings.py to source control, although you might want to commit a file called settings_template.py that users can copy and modify.

I see a few problems with this technique:

  1. Developers might accidentally commit the file to source control. Adding it to .gitignore reduces that risk.
  2. Some of your code is not under source control. If you’re disciplined and only put strings and numbers in here, that won’t be a problem. If you start writing logging filter classes in here, stop!

If your project already uses this technique, it’s easy to transition to environment variables. Just move all the setting values to environment variables, and change the Python module to read from those environment variables.


回答 4

尝试加密密码没有多大意义:您要隐藏密码的人拥有Python脚本,该脚本将具有解密密码。最快的获取密码的方法是在将Python脚本与第三方服务一起使用密码之前,将打印语句添加到Python脚本中。

因此,将密码作为字符串存储在脚本中,并对base64进行编码,这样仅读取文件就不够,然后每天调用它。

There’s not much point trying to encrypt the password: the person you’re trying to hide it from has the Python script, which will have the code to decrypt it. The fastest way to get the password will be to add a print statement to the Python script just before it uses the password with the third-party service.

So store the password as a string in the script, and base64 encode it so that just reading the file isn’t enough, then call it a day.


回答 5

我认为您所能做的最好就是保护脚本文件及其正在运行的系统。

基本上执行以下操作:

  • 使用文件系统权限(chmod 400)
  • 系统上所有者帐户的强密码
  • 降低系统受到破坏的能力(防火墙,禁用不需要的服务等)
  • 删除不需要的管理员/ root / sudo特权

I think the best you can do is protect the script file and system it’s running on.

Basically do the following:

  • Use file system permissions (chmod 400)
  • Strong password for owner’s account on the system
  • Reduce ability for system to be compromised (firewall, disable unneeded services, etc)
  • Remove administrative/root/sudo privileges for those that do not need it

回答 6

操作系统通常支持为用户保护数据。对于Windows,它看起来像是http://msdn.microsoft.com/en-us/library/aa380261.aspx

您可以使用http://vermeulen.ca/python-win32api.html从python调用win32 api

据我了解,这将存储数据,以便只能从用于存储它的帐户访问它。如果要编辑数据,可以通过编写代码来提取,更改和保存值来进行。

operating systems often have support for securing data for the user. in the case of windows it looks like it’s http://msdn.microsoft.com/en-us/library/aa380261.aspx

you can call win32 apis from python using http://vermeulen.ca/python-win32api.html

as far as i understand, this will store the data so that it can be accessed only from the account used to store it. if you want to edit the data you can do so by writing code to extract, change and save the value.


回答 7

我使用密码术是因为我在系统上安装(编译)其他常用库时遇到了麻烦。(Win7 x64,Python 3.5)

from cryptography.fernet import Fernet
key = Fernet.generate_key()
cipher_suite = Fernet(key)
cipher_text = cipher_suite.encrypt(b"password = scarybunny")
plain_text = cipher_suite.decrypt(cipher_text)

我的脚本在物理安全的系统/房间中运行。我使用“加密脚本”将凭据加密到配置文件中。然后在需要使用它们时解密。实际系统中没有“加密脚本”,只有加密的配置文件存在。分析代码的人可以通过分析代码轻松地破坏加密,但是如果需要,您仍然可以将其编译为EXE。

I used Cryptography because I had troubles installing (compiling) other commonly mentioned libraries on my system. (Win7 x64, Python 3.5)

from cryptography.fernet import Fernet
key = Fernet.generate_key()
cipher_suite = Fernet(key)
cipher_text = cipher_suite.encrypt(b"password = scarybunny")
plain_text = cipher_suite.decrypt(cipher_text)

My script is running in a physically secure system/room. I encrypt credentials with an “encrypter script” to a config file. And then decrypt when I need to use them. “Encrypter script” is not on the real system, only encrypted config file is. Someone who analyses the code can easily break the encryption by analysing the code, but you can still compile it into an EXE if necessary.


运行“ sudo pip”有什么风险?

问题:运行“ sudo pip”有什么风险?

有时,我会遇到一些评论或回应,它们强调说pipsudo“错误”或“不良”情况下运行,但在某些情况下(包括我设置了一堆工具的方式),情况可能要简单得多,甚至有必要这样运行。

什么是与运行相关的风险pipsudo


请注意,这个问题与这个问题不同,尽管有标题,但没有提供有关风险的信息。这也不是关于如何避免使用的问题sudo,而是关于为什么要使用的问题。

Occasionally I run into comments or responses that state emphatically that running pip under sudo is “wrong” or “bad”, but there are cases (including the way I have a bunch of tools set up) where it is either much simpler, or even necessary to run it that way.

What are the risks associated with running pip under sudo?


Note that this in not the same question as this one, which, despite the title, provides no information about risks. This also isn’t a question about how to avoid using sudo, but about specifically why one would want to.


回答 0

当您pip使用时sudo,您会setup.py使用sudo。换句话说,您可以从互联网上以根用户身份运行任意Python代码。如果有人在PyPI上放置了一个恶意项目,然后安装了该项目,则可以使攻击者具有对计算机的根访问权限。在对pipPyPI和PyPI 进行一些最新修复之前,攻击者还可能在您下载值得信赖的项目时,在中间攻击中让一名男子注入他们的代码。

When you run pip with sudo, you run setup.py with sudo. In other words, you run arbitrary Python code from the Internet as root. If someone puts up a malicious project on PyPI and you install it, you give an attacker root access to your machine. Prior to some recent fixes to pip and PyPI, an attacker could also run a man in the middle attack to inject their code when you download a trustworthy project.


回答 1

除了明显的安全风险(我认为安装已知的软件时,风险实际上较低)之外,还有其他原因。系统随附的Python是该系统的一部分,当您要管理系统时,可以使用专为系统维护而设计的工具,例如在安装/升级/卸载软件时的软件包管理器。当您开始使用第三方工具(在本例中为pip)修改系统软件时,就无法保证系统状态。另一个原因是,sudo可能会给您带来问题,否则您将没有机会或很少会有其他问题。例如,请参阅python中sys.executable和sys.version之间的不匹配

发行版已意识到此问题,并尝试减轻它。例如,Fedora – 使sudo pip安全; Debian – dist-packages而不是site-packages

Besides obvious security risks (which I think are in fact low when you install software you know) brought in other answers there is another reason. Python that comes with the system is part of this system and when you want to manage system you use tools designated for system maintenance like package manager in case of installing/upgrading/uninstalling software. When you start to modify system’s software with third party tools (pip in this instance) then you have no guarantee about the state of your system. Yet another reason is that sudo can bring you problems you wouldn’t have a chance or have a very small chance to have otherwise. See for example Mismatch between sys.executable and sys.version in Python

Distros are aware of this problem and try to mitigate it. For example Fedora – Making sudo pip safe and Debian – dist-packages instead of site-packages.


回答 2

以这种方式使用pip意味着您可以信任它到允许它对系统进行任何操作的程度。不仅是点子,而且还会从您可能不信任的来源下载并执行的任何代码,这可能是恶意的。

pip不需要所有这些特权,只需要对特定文件和目录的写权限。如果您不能使用系统的程序包管理器并且不想使用虚拟环境,则可以创建一个对python安装目录具有写权限的特定用户,并将其用于pip。这样,您可以更好地控制可以做什么和不可以做什么。您可以使用sudo -u它!

Using pip that way means you trust it to the level you allow it to make anything to your system. Not only pip, but also any code it will download and execute from sources you may not trust and that can be malicious.

And pip doesn’t need all that privileges, only the write access to specific files and directories. If you can’t use your system’s package manager and do not want to go the virtual environment way, you may create a specific user that has write privilege to the python installation directory and use it for pip. That way you better control what can pip do and not do. And you can use sudo -u for that!


回答 3

唯一“错误”的地方sudo是,它确实是以超级用户ala根身份运行的,这意味着您可能使用错误的命令破坏安装。由于PIP是特定程序的软件包维护,因此无论如何都需要这种访问权限才能进行更改…

The only thing “wrong” with sudo is that it, well, DOes as Super User ala root meaning you can potentially destroy an installation with the wrong command. As PIP is a package maintenance for a particular program you would need such access anyhow to make changes…


Google Authenticator在Python中的实现

问题:Google Authenticator在Python中的实现

我正在尝试使用可以通过Google Authenticator应用程序生成的一次性密码。

Google身份验证器的功能

基本上,Google身份验证器实现两种类型的密码:

  • HOTP-基于HMAC的一次性密码,这意味着密码会在每次呼叫时更改,以符合RFC4226的要求,并且
  • TOTP-基于时间的一次性密码,每30秒更改一次(据我所知)。

Google身份验证器也可以在此处作为开源使用:code.google.com/p/google-authenticator

当前代码

我一直在寻找用于生成HOTP和TOTP密码的现有解决方案,但没有找到太多。我拥有的代码是负责生成HOTP的以下代码段:

import hmac, base64, struct, hashlib, time

def get_token(secret, digest_mode=hashlib.sha1, intervals_no=None):
    if intervals_no == None:
        intervals_no = int(time.time()) // 30
    key = base64.b32decode(secret)
    msg = struct.pack(">Q", intervals_no)
    h = hmac.new(key, msg, digest_mode).digest()
    o = ord(h[19]) & 15
    h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
    return h

我面临的问题是,使用上述代码生成的密码与使用Android的Google Authenticator应用生成的密码不同。即使我努力过多个intervals_no值(第一完全相同10000,开头intervals_no = 0),以secret等于在GA的应用程序内提供的密钥。

我有问题

我的问题是:

  1. 我究竟做错了什么?
  2. 如何在Python中生成HOTP和/或TOTP?
  3. 有没有现成的Python库?

总结一下:请给我提供一些线索,这些线索将有助于我在Python代码中实现Google Authenticator身份验证。

I am trying to use one-time passwords that can be generated using Google Authenticator application.

What Google Authenticator does

Basically, Google Authenticator implements two types of passwords:

  • HOTP – HMAC-based One-Time Password, which means the password is changed with each call, in compliance to RFC4226, and
  • TOTP – Time-based One-Time Password, which changes for every 30-seconds period (as far as I know).

Google Authenticator is also available as Open Source here: code.google.com/p/google-authenticator

Current code

I was looking for existing solutions to generate HOTP and TOTP passwords, but did not find much. The code I have is the following snippet responsible for generating HOTP:

import hmac, base64, struct, hashlib, time

def get_token(secret, digest_mode=hashlib.sha1, intervals_no=None):
    if intervals_no == None:
        intervals_no = int(time.time()) // 30
    key = base64.b32decode(secret)
    msg = struct.pack(">Q", intervals_no)
    h = hmac.new(key, msg, digest_mode).digest()
    o = ord(h[19]) & 15
    h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
    return h

The problem I am facing is that the password I generate using the above code is not the same as generated using Google Authenticator app for Android. Even though I tried multiple intervals_no values (exactly first 10000, beginning with intervals_no = 0), with secret being equal to key provided within the GA app.

Questions I have

My questions are:

  1. What am I doing wrong?
  2. How can I generate HOTP and/or TOTP in Python?
  3. Are there any existing Python libraries for this?

To sum up: please give me any clues that will help me implement Google Authenticator authentication within my Python code.


回答 0

我想悬赏我的问题,但是我成功地找到了解决方案。我的问题似乎与不正确的secret键值有关(它必须是base64.b32decode()功能的正确参数)。

下面,我发布完整的工作解决方案,并说明如何使用它。

下面的代码就足够了。我也将它作为名为onetimepass的单独模块上传到GitHub (可在此处找到:https : //github.com/tadeck/onetimepass)。

import hmac, base64, struct, hashlib, time

def get_hotp_token(secret, intervals_no):
    key = base64.b32decode(secret, True)
    msg = struct.pack(">Q", intervals_no)
    h = hmac.new(key, msg, hashlib.sha1).digest()
    o = ord(h[19]) & 15
    h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
    return h

def get_totp_token(secret):
    return get_hotp_token(secret, intervals_no=int(time.time())//30)

它具有两个功能:

  • get_hotp_token() 生成一次性令牌(单次使用后应失效),
  • get_totp_token() 根据时间生成令牌(每30秒更改一次),

参量

关于参数:

  • secret 是服务器(上述脚本)和客户端(Google身份验证器,通过在应用程序中将其作为密码提供)已知的秘密值,
  • intervals_no 是每代令牌生成后增加的数字(可能应该在服务器上通过检查过去一次成功的整数之后检查一些有限数量的整数来解决)

如何使用它

  1. 生成secret(必须是的正确参数base64.b32decode())-最好为16个字符(无=符号),因为它肯定适用于脚本和Google身份验证器。
  2. 使用get_hotp_token(),如果你想在每次使用后无效一次性密码。在Google Authenticator中,我提到了这种基于计数器的密码。为了在服务器上检查它,您将需要检查多个值intervals_no(因为您没有隔离该用户由于某种原因未在请求之间生成传递的密码),但不能小于最后一个工作intervals_no值(因此您可能应该存储它)某处)。
  3. get_totp_token()如果您希望令牌以30秒的间隔工作,请使用。您必须确保两个系统都设置了正确的时间(这意味着它们在任何给定的时间点都生成相同的Unix时间戳)。
  4. 确保保护自己免受暴力攻击。如果使用基于时间的密码,则在不到30秒的时间内尝试输入1000000个值将使您有100%的机会猜测密码。在基于HMAC的密码(HOTP)的情况下,情况甚至更糟。

当将以下代码用于基于HMAC的一次性密码时:

secret = 'MZXW633PN5XW6MZX'
for i in xrange(1, 10):
    print i, get_hotp_token(secret, intervals_no=i)

您将得到以下结果:

1 448400
2 656122
3 457125
4 35022
5 401553
6 581333
7 16329
8 529359
9 171710

对应于Google Authenticator应用生成的令牌(除非少于6个符号,应用会在开头添加零,以达到6个字符的长度)。

I wanted to set a bounty on my question, but I have succeeded in creating solution. My problem seemed to be connected with incorrect value of secret key (it must be correct parameter for base64.b32decode() function).

Below I post full working solution with explanation on how to use it.

Code

The following code is enough. I have also uploaded it to GitHub as separate module called onetimepass (available here: https://github.com/tadeck/onetimepass).

import hmac, base64, struct, hashlib, time

def get_hotp_token(secret, intervals_no):
    key = base64.b32decode(secret, True)
    msg = struct.pack(">Q", intervals_no)
    h = hmac.new(key, msg, hashlib.sha1).digest()
    o = ord(h[19]) & 15
    h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
    return h

def get_totp_token(secret):
    return get_hotp_token(secret, intervals_no=int(time.time())//30)

It has two functions:

  • get_hotp_token() generates one-time token (that should invalidate after single use),
  • get_totp_token() generates token based on time (changed in 30-second intervals),

Parameters

When it comes to parameters:

  • secret is a secret value known to server (the above script) and client (Google Authenticator, by providing it as password within application),
  • intervals_no is the number incremeneted after each generation of the token (this should be probably resolved on the server by checking some finite number of integers after last successful one checked in the past)

How to use it

  1. Generate secret (it must be correct parameter for base64.b32decode()) – preferably 16-char (no = signs), as it surely worked for both script and Google Authenticator.
  2. Use get_hotp_token() if you want one-time passwords invalidated after each use. In Google Authenticator this type of passwords i mentioned as based on the counter. For checking it on the server you will need to check several values of intervals_no (as you have no quarantee that user did not generate the pass between the requests for some reason), but not less than the last working intervals_no value (thus you should probably store it somewhere).
  3. Use get_totp_token(), if you want a token working in 30-second intervals. You have to make sure both systems have correct time set (meaning that they both generate the same Unix timestamp in any given moment in time).
  4. Make sure to protect yourself from brute-force attack. If time-based password is used, then trying 1000000 values in less than 30 seconds gives 100% chance of guessing the password. In case of HMAC-based passowrds (HOTPs) it seems to be even worse.

Example

When using the following code for one-time HMAC-based password:

secret = 'MZXW633PN5XW6MZX'
for i in xrange(1, 10):
    print i, get_hotp_token(secret, intervals_no=i)

you will get the following result:

1 448400
2 656122
3 457125
4 35022
5 401553
6 581333
7 16329
8 529359
9 171710

which is corresponding to the tokens generated by the Google Authenticator app (except if shorter than 6 signs, app adds zeros to the beginning to reach a length of 6 chars).


回答 1

我想要一个Python脚本来生成TOTP密码。因此,我编写了python脚本。这是我的实现。我在Wikipedia上有此信息,并且有一些有关HOTP和TOTP的知识可以编写此脚本。

import hmac, base64, struct, hashlib, time, array

def Truncate(hmac_sha1):
    """
    Truncate represents the function that converts an HMAC-SHA-1
    value into an HOTP value as defined in Section 5.3.

    http://tools.ietf.org/html/rfc4226#section-5.3

    """
    offset = int(hmac_sha1[-1], 16)
    binary = int(hmac_sha1[(offset * 2):((offset * 2) + 8)], 16) & 0x7fffffff
    return str(binary)

def _long_to_byte_array(long_num):
    """
    helper function to convert a long number into a byte array
    """
    byte_array = array.array('B')
    for i in reversed(range(0, 8)):
        byte_array.insert(0, long_num & 0xff)
        long_num >>= 8
    return byte_array

def HOTP(K, C, digits=6):
    """
    HOTP accepts key K and counter C
    optional digits parameter can control the response length

    returns the OATH integer code with {digits} length
    """
    C_bytes = _long_to_byte_array(C)
    hmac_sha1 = hmac.new(key=K, msg=C_bytes, digestmod=hashlib.sha1).hexdigest()
    return Truncate(hmac_sha1)[-digits:]

def TOTP(K, digits=6, window=30):
    """
    TOTP is a time-based variant of HOTP.
    It accepts only key K, since the counter is derived from the current time
    optional digits parameter can control the response length
    optional window parameter controls the time window in seconds

    returns the OATH integer code with {digits} length
    """
    C = long(time.time() / window)
    return HOTP(K, C, digits=digits)

I wanted a python script to generate TOTP password. So, I wrote the python script. This is my implementation. I have this info on wikipedia and some knowledge about HOTP and TOTP to write this script.

import hmac, base64, struct, hashlib, time, array

def Truncate(hmac_sha1):
    """
    Truncate represents the function that converts an HMAC-SHA-1
    value into an HOTP value as defined in Section 5.3.

    http://tools.ietf.org/html/rfc4226#section-5.3

    """
    offset = int(hmac_sha1[-1], 16)
    binary = int(hmac_sha1[(offset * 2):((offset * 2) + 8)], 16) & 0x7fffffff
    return str(binary)

def _long_to_byte_array(long_num):
    """
    helper function to convert a long number into a byte array
    """
    byte_array = array.array('B')
    for i in reversed(range(0, 8)):
        byte_array.insert(0, long_num & 0xff)
        long_num >>= 8
    return byte_array

def HOTP(K, C, digits=6):
    """
    HOTP accepts key K and counter C
    optional digits parameter can control the response length

    returns the OATH integer code with {digits} length
    """
    C_bytes = _long_to_byte_array(C)
    hmac_sha1 = hmac.new(key=K, msg=C_bytes, digestmod=hashlib.sha1).hexdigest()
    return Truncate(hmac_sha1)[-digits:]

def TOTP(K, digits=6, window=30):
    """
    TOTP is a time-based variant of HOTP.
    It accepts only key K, since the counter is derived from the current time
    optional digits parameter can control the response length
    optional window parameter controls the time window in seconds

    returns the OATH integer code with {digits} length
    """
    C = long(time.time() / window)
    return HOTP(K, C, digits=digits)

Wifiphisher 无线连接渗透破解框架

关于

Wifiphisher是用于执行RED团队活动或Wi-Fi安全测试的恶意接入点框架。使用Wifiphisher,渗透测试员可以通过执行有针对性的Wi-Fi关联攻击,轻松实现对无线客户端的中间人位置。Wifiphisher还可以用于对连接的客户端安装受害者定制的网络钓鱼攻击,以便捕获凭证(例如,从第三方登录页面或WPA/WPA2预共享密钥)或用恶意软件感染受害者站

特性:

  • 很强大。Wifiphisher可以在树莓PI设备内运行数小时,执行所有现代Wi-Fi关联技术(包括“邪恶双胞胎”、“因果报应”和“已知信标”)。
  • 很灵活。支持数十个参数,并为不同的部署方案提供了一组社区驱动的网络钓鱼模板
  • 模块化的。用户可以write simple or complicated modules在Python中扩展该工具的功能,或者create custom phishing scenarios为了进行特定的目标导向的袭击
  • 使用方便。高级用户可以使用Wifiphisher提供的丰富功能集,而初学者可能只需简单地使用“./bin/wifiphisher”即可。交互式文本用户界面引导测试人员完成攻击的构建过程
  • 广泛研究的结果。我们的开发人员披露了诸如“已知信标”和“Lure10”之类的攻击以及最先进的网络钓鱼技术,Wifiphisher是第一个集成它们的工具
  • 由令人敬畏的开发人员和用户社区支持
  • 免费的。Wifiphisher可以免费下载,并且还附带完整的源代码,您可以根据GPLv3许可证的条款研究、更改或分发这些源代码

它是如何工作的

Wi-Fi网络钓鱼包括两个步骤:

  1. 第一步涉及在不知情的情况下与Wi-Fi客户端关联的过程,换句话说,就是获得中间人(MITM)位置。Wifiphisher使用许多不同的技术来实现这一点,包括:
    • 邪恶双胞胎,Wifiphisher创建了一个看起来与合法网络相似的假无线网络
    • Karma,Wifiphisher伪装成附近Wi-Fi客户端搜索的公共网络
    • 已知的信标,其中Wifiphisher广播公共ESSID的字典,周围的无线站在过去可能已经连接到这些ESSID

    与此同时,Wifiphisher不断伪造“解除身份验证”或“解除关联”数据包,以破坏现有的关联,并最终使用上述技术引诱受害者


执行MITM攻击

  1. (可选)一旦Wifiphisher授予渗透测试仪一个中间人的位置,就可以执行许多不同的攻击。例如,测试器可以执行数据嗅探或扫描受害者站的漏洞

    通过使用Wifiphisher,可以从目标环境和受害用户收集信息,从而实现高级Web网络钓鱼技术。例如,在我们的一个场景中,Wifiphisher将从广播的信标帧和HTTP User-Agent报头中提取信息,以显示Windows网络管理器的基于Web的模拟,以便捕获预共享密钥


假的web-based network manager

要求

以下是充分利用Wifiphisher的要求:

  • 一个工作正常的Linux系统。人们已经让Wifiphisher在许多发行版上工作,但Kali Linux是官方支持的发行版,因此所有新功能都主要在这个平台上进行测试
  • 一个支持AP&Monitor模式并能够注入的无线网络适配器。驱动程序应支持NetLink

安装

要安装最新的开发版本,请键入以下命令:

git clone https://github.com/wifiphisher/wifiphisher.git # Download the latest revision
cd wifiphisher # Switch to tool's directory
sudo python setup.py install # Install any dependencies

或者,您也可以从Releases page

用法

通过输入以下命令运行该工具wifiphisherpython bin/wifiphisher(从工具的目录内)

通过在没有任何选项的情况下运行该工具,它将找到正确的接口,并交互地要求用户选择目标网络的ESSID(从周围区域具有所有ESSID的列表中)以及要执行的网络钓鱼场景。默认情况下,该工具将同时执行Evil Twin和Karma攻击


wifiphisher -aI wlan0 -jI wlan4 -p firmware-upgrade --handshake-capture handshake.pcap

使用wlan0生成恶意接入点,使用wlan4进行DoS攻击。从列表中手动选择目标网络,然后执行“固件升级”场景。通过对照handshake.pcap文件中的握手进行检查,验证捕获的预共享密钥是否正确

对于手动选择无线适配器非常有用。这个“Firmware Upgrade”方案是从受密码保护的网络获取PSK的一种简单方法


wifiphisher --essid CONFERENCE_WIFI -p plugin_update -pK s3cr3tp4ssw0rd

自动选择正确的接口。使用Essid“Conference_WiFi”定位Wi-Fi,并执行“插件更新”场景。邪恶双胞胎将使用PSK“s3cr3tp4ssw0rd”进行密码保护

对具有公开的PSK的网络有用(例如,在会议中)。这个“Plugin Update”Scenario提供了一种让受害者下载恶意可执行文件(例如,包含反向外壳有效负载的恶意软件)的简单方法


wifiphisher --essid "FREE WI-FI" -p oauth-login -kB

只需使用Essid“免费WI-FI”生成一个开放的Wi-Fi网络,然后执行“OAuth登录”方案。此外,挂载“已知信标”Wi-Fi自动关联技术

对公共场所的受害者很有用。这个“OAuth Login”Scenario提供了一种从Facebook等社交网络获取凭据的简单方法

以下是所有选项及其说明(也可用于wifiphisher -h):

缩写形式 长型 解释
-h –救命 显示此帮助消息并退出
-i接口 –接口接口 手动选择既支持AP模式又支持监控模式的接口,以生成恶意AP并从扩展(即deauth)安装其他Wi-Fi攻击。示例:-I wlan1
-EI EXTENSIONSINTERFACE –扩展接口扩展SINTERFACE 手动选择支持监控模式的接口来运行扩展。示例:-ei wlan1
-AI APINTERFACE –apinterface APINTERFACE 手动选择支持AP模式的接口以派生AP。示例:-AI wlan0
-PI接口 –保护接口接口 指定将保护其连接不受NetworkManager管理的一个或多个接口
-KN –保留网络管理器 请勿杀死NetworkManager
-ne –无扩展 不加载任何扩展
-e Essid –Essid Essid 输入无管理AP的ESSID。此选项将跳过接入点选择阶段。示例:–Essid“免费WiFi”
-PPD网络钓鱼页面目录 –网络钓鱼页面目录网络钓鱼页面目录 在此位置搜索网络钓鱼页面
-p PHISHING SCENARIO –网络钓鱼方案PHISHING SCENARIO 选择要运行的网络钓鱼方案。此选项将跳过方案选择阶段。示例:-p Firmware_Upgrade
-PK预共享密钥 –预共享密钥预共享密钥 在恶意接入点上添加WPA/WPA2保护。示例:-pk s3cr3tp4ssw0rd
-QS –不折不扣的成功 成功检索一对凭据后停止脚本
-LC –lure10-捕获 捕获在AP选择阶段发现的AP的BSSID。此选项是Lure10攻击的一部分
-LE LURE10_利用漏洞 –lure10-利用LURE10_利用 愚弄附近Windows用户的Windows location Service,使其相信它在以前使用–lure10-capture捕获的区域内。Lure10攻击的一部分
-IAM –mac-ap-interface 指定AP接口的MAC地址。示例:-IAM 38:EC:11:00:00:00
-IEM –mac-tensions-interface 指定扩展接口的MAC地址。示例:-IEM E8:2A:EA:00:00:00
-INM –无mac随机化 不更改任何MAC地址
-HC –握手-捕获 捕获用于验证密码的WPA/WPA2握手。需要柯帕蒂。示例:-hc capture.pcap
-德·埃西德(De Essid) –Deauth-Essid Essid 使用该ESSID对WLAN中的所有BSSID进行身份验证
-直流通道 –双通道通道 要收听的频道。示例:–deauth-channel 1,3,7
–日志记录 启用日志记录。输出将保存到wifiphisher.log文件
-LP LOGPATH –日志路径LOGPATH 确定日志文件的完整路径
-CP凭据日志路径 –凭据日志路径凭据日志路径 确定将存储所有捕获的凭据的文件的完整路径
-厘米 –通道监视器 监控目标接入点是否更改了信道
–负载路径 启用有效负载路径。旨在与服务有效负载的场景一起使用
-WP –wps-pbc 监控WPS-PBC注册器侧的按钮是否被按下
–WAI –wpspbc-assoc-interface 用于关联到WPS接入点的WLAN接口
-kB –已知信标 执行已知的信标Wi-Fi自动关联技术
-fh –force-hostapd 强制使用系统中安装的hostapd
–dnsmasq-conf DNSMASQ_conf 确定dnmasq.conf文件的完整路径
-DK –禁用-业力 禁用业力攻击
-PE –网络钓鱼-Essid 确定要用于网络钓鱼页面的Essid

屏幕截图


瞄准接入点


一次成功的袭击


假的router configuration page


假的OAuth Login Page


假的web-based network manager

需要帮助

如果您是Python开发人员或网页设计师,您可以帮助我们改进Wifiphisher。您可以随时查看bug tracker对于要执行的某些任务

如果您不知道如何编码,您可以通过以下方式帮助我们proposing improvements or reporting bugs请查看错误报告指南和FAQ document在此之前。请注意,该工具的目标不是对脚本儿童友好。在打开问题之前,请确保您确实了解该工具的工作原理

学分

剧本是基于来自Dan McInerney早在2015年

一份完整的贡献者名单here

许可证

Wifiphisher在GPLv3许可下获得许可。看见LICENSE了解更多信息

项目状态

Wifiphisher的当前版本是1.4您可以从以下地址下载最新版本here否则,您可以通过克隆此存储库来获取最新的开发版本

免责声明

  • 在没有事先相互一致的情况下使用Wifiphisher攻击基础设施可被视为非法活动。最终用户有责任遵守所有适用的地方、州和联邦法律。作者不承担任何责任,也不对本程序造成的任何误用或损坏负责

注意事项:注意那些假装与Wifiphisher项目有关的网站。他们可能在传送恶意软件

有关Wifiphisher新闻,请关注我们Twitter或者像我们一样Facebook

Django设置“ SECRET_KEY”的目的

问题:Django设置“ SECRET_KEY”的目的

SECRET_KEYdjango 的意义到底是什么?我做了一些Google搜索,并检查了文档(https://docs.djangoproject.com/en/dev/ref/settings/#secret-key),但是我正在寻找对此的更深入的说明,以及为什么需要它。

例如,如果密钥被泄露/其他人知道密钥是什么,会发生什么?谢谢。

What exactly is the point of the SECRET_KEY in django? I did a few google searches and checked out the docs ( https://docs.djangoproject.com/en/dev/ref/settings/#secret-key ), but I was looking for a more in-depth explanation of this, and why it is required.

For example, what could happen if the key was compromised / others knew what it was? Thank you.


回答 0

它用于制作哈希。看:

>grep -Inr SECRET_KEY *
conf/global_settings.py:255:SECRET_KEY = ''
conf/project_template/settings.py:61:SECRET_KEY = ''
contrib/auth/tokens.py:54:        hash = sha_constructor(settings.SECRET_KEY + unicode(user.id) +
contrib/comments/forms.py:86:        info = (content_type, object_pk, timestamp, settings.SECRET_KEY)
contrib/formtools/utils.py:15:    order, pickles the result with the SECRET_KEY setting, then takes an md5
contrib/formtools/utils.py:32:    data.append(settings.SECRET_KEY)
contrib/messages/storage/cookie.py:112:        SECRET_KEY, modified to make it unique for the present purpose.
contrib/messages/storage/cookie.py:114:        key = 'django.contrib.messages' + settings.SECRET_KEY
contrib/sessions/backends/base.py:89:        pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
contrib/sessions/backends/base.py:95:        if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
contrib/sessions/backends/base.py:134:        # Use settings.SECRET_KEY as added salt.
contrib/sessions/backends/base.py:143:                       settings.SECRET_KEY)).hexdigest()
contrib/sessions/models.py:16:        pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
contrib/sessions/models.py:59:        if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
core/management/commands/startproject.py:32:        # Create a random SECRET_KEY hash, and put it in the main settings.
core/management/commands/startproject.py:37:        settings_contents = re.sub(r"(?<=SECRET_KEY = ')'", secret_key + "'", settings_contents)
middleware/csrf.py:38:                % (randrange(0, _MAX_CSRF_KEY), settings.SECRET_KEY)).hexdigest()
middleware/csrf.py:41:    return md5_constructor(settings.SECRET_KEY + session_id).hexdigest()

It is used for making hashes. Look:

>grep -Inr SECRET_KEY *
conf/global_settings.py:255:SECRET_KEY = ''
conf/project_template/settings.py:61:SECRET_KEY = ''
contrib/auth/tokens.py:54:        hash = sha_constructor(settings.SECRET_KEY + unicode(user.id) +
contrib/comments/forms.py:86:        info = (content_type, object_pk, timestamp, settings.SECRET_KEY)
contrib/formtools/utils.py:15:    order, pickles the result with the SECRET_KEY setting, then takes an md5
contrib/formtools/utils.py:32:    data.append(settings.SECRET_KEY)
contrib/messages/storage/cookie.py:112:        SECRET_KEY, modified to make it unique for the present purpose.
contrib/messages/storage/cookie.py:114:        key = 'django.contrib.messages' + settings.SECRET_KEY
contrib/sessions/backends/base.py:89:        pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
contrib/sessions/backends/base.py:95:        if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
contrib/sessions/backends/base.py:134:        # Use settings.SECRET_KEY as added salt.
contrib/sessions/backends/base.py:143:                       settings.SECRET_KEY)).hexdigest()
contrib/sessions/models.py:16:        pickled_md5 = md5_constructor(pickled + settings.SECRET_KEY).hexdigest()
contrib/sessions/models.py:59:        if md5_constructor(pickled + settings.SECRET_KEY).hexdigest() != tamper_check:
core/management/commands/startproject.py:32:        # Create a random SECRET_KEY hash, and put it in the main settings.
core/management/commands/startproject.py:37:        settings_contents = re.sub(r"(?<=SECRET_KEY = ')'", secret_key + "'", settings_contents)
middleware/csrf.py:38:                % (randrange(0, _MAX_CSRF_KEY), settings.SECRET_KEY)).hexdigest()
middleware/csrf.py:41:    return md5_constructor(settings.SECRET_KEY + session_id).hexdigest()

回答 1

用于加密签名Django文档介绍了“ SECRET_KEY”设置的用法:

此值[ SECRET_KEY设置]是保护​​签名数据的关键-务必确保此安全性,否则攻击者可能会使用它来生成自己的签名值。

对于SECRET_KEY设置,也从Django文档中引用此部分。)

Django中的加密签名API可供任何应用程序用于值的加密安全签名。Django本身在各种高级功能中使用了此功能:

  • 签名序列化数据(例如JSON文档)。

  • 用户会话,密码重置请求,消息等的唯一令牌。

  • 通过添加(然后期望)请求的唯一值来防止跨站点或重放攻击。

  • 为哈希函数生成唯一的盐。

因此,通常的答案是:Django应用程序中有很多东西需要加密签名,而“ SECRET_KEY”设置是用于这些目的的密钥。它需要具有密码学上很强的熵(计算机难以猜测),并且在所有Django实例之间都是唯一的。

The Django documentation for cryptographic signing covers the uses of the ‘SECRET_KEY’ setting:

This value [the SECRET_KEY setting] is the key to securing signed data – it is vital you keep this secure, or attackers could use it to generate their own signed values.

(This section is also referenced from the Django documentation for the ‘SECRET_KEY’ setting.)

The cryptographic signing API in Django is available to any app for cryptographically-secure signatures on values. Django itself makes use of this in various higher-level features:

  • Signing serialised data (e.g. JSON documents).

  • Unique tokens for a user session, password reset request, messages, etc.

  • Prevention of cross-site or replay attacks by adding (and then expecting) unique values for the request.

  • Generating a unique salt for hash functions.

So, the general answer is: There are many things in a Django app which require a cryptographic signature, and the ‘SECRET_KEY’ setting is the key used for those. It needs to have a cryptographically strong amount of entropy (hard for computers to guess) and unique between all Django instances.


回答 2

根据上的Django文档SECRET_KEY

密钥用于:

  • 如果您使用的会话后端不是django.contrib.sessions.backends.cache或使用默认会话,则所有会话get_session_auth_hash()
  • 如果使用CookieStorage或,则显示所有消息FallbackStorage
  • 所有PasswordResetView令牌。
  • 加密签名的任何用法,除非提供了不同的密钥。

如果旋转密钥,则以上所有内容都会失效。秘密密钥不用于用户密码,密钥旋转不会影响它们。

According to the Django Documentation on SECRET_KEY:

The secret key is used for:

  • All sessions if you are using any other session backend than django.contrib.sessions.backends.cache, or are using the default get_session_auth_hash().
  • All messages if you are using CookieStorage or FallbackStorage.
  • All PasswordResetView tokens.
  • Any usage of cryptographic signing, unless a different key is provided.

If you rotate your secret key, all of the above will be invalidated. Secret keys are not used for passwords of users and key rotation will not affect them.


Security Monkey监控AWS、GCP、OpenStack和GitHub组织的资产及其随时间的变化

Security Monkey监控您的AWS and GCP accounts有关不安全配置的策略更改和警报。支持OpenStack公共云和私有云。Security Monkey还可以监视和监控您的GitHub组织、团队和存储库

它提供单个UI来浏览和搜索您的所有帐户、地区和云服务。猴子会记住以前的状态,并能准确地告诉你什么时候发生了变化

Security Monkey可以扩展为custom account typescustom watcherscustom auditors,以及custom alerters

它可以在CPython2.7上运行。众所周知,它可以在Ubuntu Linux和OS X上运行

发展分支机构 大师级分支机构

特别注意事项:

Netflix对Security Monkey的支持已经减少,只对小错误进行了修复。也就是说,我们乐于接受并合并修复bug并添加新功能的请求(Pull-Request)

🚨⚠️🥁🎺请阅读:打破1.0的更改🎺🥁⚠️🚨

如果您是第一次升级到1.0,请查看Quickstart以及Autostarting文档,因为Security Monkey有一个新的部署模式。此外,还添加了新的IAM权限

项目资源

实例关系图

组成Security Monkey的组件如下(不是特定于AWS的):

访问图

Security Monkey通过提供的凭据访问帐户以进行扫描(“角色假设”,如果可用)

PyWhat-🐸识别任何东西。pyWhat让您轻松识别电子邮件、IP地址等

想象一下:你会看到一些神秘的文字🧙‍♂️5f4dcc3b5aa765d61d8327deb882cf99你想知道这是什么。你的工作是什么?

嗯,有了what你所要做的就是问what "5f4dcc3b5aa765d61d8327deb882cf99"what我会告诉你的!

what的工作就是识别什么有些事是不管是文件还是文本!甚至是祸不单行的一个文件!那文本呢?文件?我们也有那个!what是递归的,它将标识所有的一切在文本和更多方面!

⚙用例

🦠Wannacry

您会遇到一款名为WantToCry的新恶意软件。你回想起Wannacry,并记得它被停止是因为一名研究人员在代码中发现了一个杀死开关

当硬编码到Wannacry中的域名注册后,病毒就会停止

您使用的是What识别恶意软件中的所有域,并使用域注册器API注册所有域。如果Wannacry再次发生,你可以在几分钟内阻止它,而不是几周

🦈更快地分析PCAP文件

假设你有一个.pcap来自网络攻击的文件。What可以识别这一点并快速找到您:

  • 所有散列
  • 信用卡号码
  • 加密货币地址
  • 社保号码
  • 还有更多

使用what,您可以在几秒内识别出pcap中的重要内容,而不是几分钟。

🌌什么都行

任何时候,只要您有一个文件,并且想要在其中找到有用的结构化数据,What是给你的

或者如果你遇到一段文字,而你不知道它是什么,What会告诉你

文件打开您可以通过以下方式传入文件路径what 'this/is/a/file/path'What聪明到能认出这是个文件!

一整套怎么样?目录What我也能应付得来!它会的递归地搜索文件并输出所需的所有内容!

过滤您可以使用以下命令过滤输出what --rarity 0.2:0.8 --include_tags tag1,tag2 TEXT使用what --help获取更多信息

排序您可以使用以下命令对输出进行排序what -k rarity --reverse TEXT使用what --help获取更多信息

正在导出您可以使用以下命令导出到jsonwhat --json并且可以使用以下命令将结果直接发送到文件what --json > file.json

无边界模式What有一种特殊的模式来匹配字符串中的可识别信息。默认情况下,它在CLI中处于启用状态,但在API中处于禁用状态。使用what --help或参阅API Documentation了解更多信息

🍕API接口

PyWhat有API!单击此处https://github.com/bee-san/pyWhat/wiki/API读到关于这件事的报道

👾贡献

what不仅依靠贡献者茁壮成长,而且离不开他们!如果您想要添加一个新的正则表达式进行检查,您可以阅读我们的文档here

我们邀请投稿人加入不和谐的行列,以便更快地进行讨论,但这并不是必要的:

Urh-通用无线电黑客:像老板一样调查无线协议

通用无线电黑客(URH)是一套完整的无线协议研究套件,具有本机支持many常见软件定义的无线电URH允许易于解调的信号组合在一起automatic调制参数的检测使得识别飞翔空中传输的比特和字节变得轻而易举。因为数据通常会已编码在传输之前,URH提供可定制的解码甚至可以破解像CC1101数据白化这样的复杂编码。当涉及到协议逆向工程,URH在两个方面都有帮助。您可以手动分配协议字段和消息类型,也可以让URH自动推断协议字段使用一个rule-based intelligence最后,市建局需要一个模糊组件针对无状态协议和仿真环境用于状态攻击

快速入门

为了开始工作,

如果您喜欢URH,请⭐此存储库和join our Slack channel感谢您的支持!

引用URH

我们鼓励与URH合作的研究人员引用thisWOOT‘18纸或直接使用下面的BibTeX条目

URH BibTeX条目用于您的研究论文
@inproceedings {220562,
author = {Johannes Pohl and Andreas Noack},
title = {Universal Radio Hacker: A Suite for Analyzing and Attacking Stateful Wireless Protocols},
booktitle = {12th {USENIX} Workshop on Offensive Technologies ({WOOT} 18)},
year = {2018},
address = {Baltimore, MD},
url = {https://www.usenix.org/conference/woot18/presentation/pohl},
publisher = {{USENIX} Association},
}

安装

URH可以在Windows、Linux和MacOS上运行。单击下面的操作系统查看安装说明

窗口

在Windows上,URH可以通过其Installer不需要进一步的依赖关系

如果您收到关于丢失的错误api-ms-win-crt-runtime-l1-1-0.dll、运行Windows Update或直接安装KB2999226

Linux操作系统
使用pip进行常规安装(推荐)

有关URH的信息,请访问PyPi因此,您可以使用以下命令进行安装

# IMPORTANT: Make sure your pip is up to date
sudo python3 -m pip install --upgrade pip  # Update your pip installation
sudo python3 -m pip install urh            # Install URH

这是在Linux上安装URH的推荐方式,因为它附带所有本地扩展预编译

要以非root用户身份访问您的SDR,请安装相应的UDEV规则你可以找到他们in the wiki

通过软件包管理器安装

URH包含在许多Linux发行版的存储库中,例如Arch Linux根图(Gentoo)软呢帽OpenSUSENixOS还有一个套餐是FreeBSD如果可用,只需使用包管理器安装URH

注意事项:要获得本机支持,您必须安装相应的-dev您的SDR包,例如hackrf-dev在此之前安装URH

捕捉

URH以快照形式提供:https://snapcraft.io/urh

Docker镜像

市建局的官方对接图片现已推出。here它包含所有本机后端,并且随时可以运行

MacOS
使用DMG

建议使用至少MacOS 10.14使用可用的DMG时here

带管道
  1. 安装Python 3 for Mac OS X如果您遇到预安装的Python问题,请确保使用给定链接更新到最新版本
  2. (可选)安装所需的本地库,例如brew install librtlsdr以获得相应的本机设备支持
  3. 在终端中,键入:pip3 install urh
  4. 类型urh在终端中启动它
更新您的安装

如果您通过pip安装了urh,则可以使用python3 -m pip install --upgrade urh

从源运行
不安装的情况下

要在不安装的情况下执行Universal Radio Hacker,只需运行:

git clone https://github.com/jopohl/urh/
cd urh/src/urh
./main.py

请注意,在首次使用之前,将构建C++扩展

从源安装

要从源安装URH,您需要具备python-setuptools已安装。你可以用以下方式买到它们python3 -m pip install setuptools安装setuptools后,执行:

git clone https://github.com/jopohl/urh/
cd urh
python setup.py install

并通过键入以下命令启动应用程序urh在终端中

物品

用URH破解东西

关于URH的一般演示文稿和教程

外部解码

看见wiki查看我们社区提供的外部解码列表!谢谢你这么说!

屏幕截图

从原始信号中获取数据

即使是复杂的协议也要保持概述

记录和发送信号