• Python 中的安全密码处理


    前言

    几乎每个应用程序都需要某种形式的身份验证、密码处理或使用安全凭据,例如 API 密钥。您可能不是安全专家,但您应该知道如何安全地处理所有这些密码和凭据,以保护应用程序用户的凭据和数据以及您自己的 API 密钥和各种令牌。

    (文末送读者福利)

    确保这些安全元素的安全包括生成、验证它们、安全地存储它们并保护它们免受对手的侵害。因此,在本文中,我们将探索 Python 库、工具和概念,它们将对此有所帮助!

    提示输入密码

    让我们从简单开始 - 你有基本的Python应用程序与命令行界面。您需要向用户询问密码。您可以使用,但这会在终端中显示密码,以避免您应该使用相反:是一个非常简单的包,允许您提示用户输入密码以及通过提取当前用户的登录名来获取他们的用户名。请注意,并非每个系统都支持隐藏密码。Python 会尝试警告你这一点,所以只需在命令行中阅读警告。

    import getpass
    
    user = getpass.getuser()
    password = getpass.getpass()
    # Do Stuff...
    
    • 1
    • 2
    • 3
    • 4
    • 5

    生成

    有时,生成密码而不是提示用户输入密码可能更可取。例如,如果要设置首次登录时更改的初始密码。

    没有任何用于生成密码的库,但实现它并不困难:使用上述代码生成的密码会很强大,但很难记住。如果它只是一个初始的临时密码或短期令牌,那么它很好,但如果用户应该使用更长时间,那么使用密码短语更合适。

    import string
    import secrets
    
    length = 15
    # Choose wide set of characters, but consider what your system can handle
    alphabet = string.ascii_letters + string.digits + string.punctuation
    password = ''.join(secrets.choice(alphabet) for i in range(length))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    我们可以像上面使用简单的密码一样构建一个密码生成器,但是当有可用的库时,为什么要打扰。这个库被称为著名的XKCD,关于密码强度,它完全按照漫画的描述 - 生成由单词组成的强密码短语:此片段首先在您的系统上查找单词/字典文件,例如并选择指定长度的所有单词,然后从中生成用于生成密码短语的单词列表。生成器本身有一些参数,我们可以用来自定义密码短语。除了明显的单词数和长度外,它还具有离合参数,这是一个单词,其字符将用作密码短语中单词的首字母(听起来很复杂?好吧,请参阅上面的示例密码短语)。

    # pip install xkcdpass
    from xkcdpass import xkcd_password as xp
    
    word_file = xp.locate_wordfile()
    words = xp.generate_wordlist(wordfile=word_file, min_length=5, max_length=10)
    
    for i in range(4):
        print(xp.generate_xkcdpassword(words, acrostic="python", numwords=6, delimiter="*"))
    
    # punch*yesterday*throwback*heaviness*overnight*numbing
    # plethora*yesterday*thigh*handlebar*outmost*natural
    # pyromania*yearly*twisty*hyphen*overstuff*nuzzle
    # pandemic*yearly*theology*hatching*overlaid*neurosis
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    如果你真的想自己构建这个,而不是在你的项目中添加依赖项,你可以在Python 文档中使用这个配方。成

    现在我们要求用户输入密码或为他们生成密码,我们该怎么办?我们可能希望将其存储在数据库中的某个位置,但正如您可能(希望)知道的那样,您永远不应该以明文格式存储密码。为什么?

    好吧,密码永远不应该以可恢复的格式存储,无论是纯文本还是加密。它们应该使用加密强度高的单向函数进行哈希处理。这样,如果有人掌握了数据库中的密码,他们将很难恢复任何实际密码,因为从哈希中恢复任何密码的唯一方法是暴力破解它 - 也就是说 - 获取可能的明文密码,使用相同的算法对其进行哈希处理并将结果与数据库中的条目进行比较。

    为了使暴力破解更加困难,应另外使用盐。Salt 是与散列密码一起存储的随机字符串。它在散列之前附加到密码中,使其更加随机,因此更难猜测(使用彩虹表)。

    但是,对于每秒可以尝试数十亿个哈希的现代硬件,使密码难以猜测是不够的,因此使用慢速哈希函数进行密码哈希,使攻击者暴力破解密码的效率要低得多。

    市面上有很多库和单独的哈希算法,但上述要求大大缩小了我们的选择范围。在Python中进行哈希处理的首选解决方案应该是因为它提供了适当的算法,以及即使不精通密码学的人也可以使用的高级接口。在此代码段中,我们使用我们选择的算法,因为它是最流行和经过充分测试的哈希算法之一。首先,我们检查其可能的设置并检查算法使用的默认轮数是多少。然后,我们修改哈希器以使用更高的轮数(成本因素),使哈希更慢,因此哈希更难破解。此数字应是不会对用户造成无法容忍的延迟的最大可能数字 (~300ms)。定期更新默认舍入值,因此您不一定需要更改此值。passlib

    # pip install passlib
    from passlib.hash import bcrypt
    from getpass import getpass
    
    print(bcrypt.setting_kwds)
    # ('salt', 'rounds', 'ident', 'truncate_error')
    print(bcrypt.default_rounds)
    # 12
    
    hasher = bcrypt.using(rounds=13)  # Make it slower
    
    password = getpass()
    hashed_password = hasher.hash(password)
    print(hashed_password)
    # $2b$13$H9.qdcodBFCYOWDVMrjx/uT.fbKzYloMYD7Hj2ItDmEOnX5lw.BX.
    # \__/\/ \____________________/\_____________________________/
    # Alg Rounds  Salt (22 char)            Hash (31 char)
    
    print(hasher.verify(password, hashed_password))
    # True
    print(hasher.verify("not-the-password", hashed_password))
    # False
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    准备好哈希器后,我们提示用户输入密码并对其进行哈希处理。此时我们可以将其存储在数据库中,出于演示目的,我们继续根据原始明文密码对其进行验证。

    从上面的代码中,我们可以看到整个用法归结为我们选择的算法的 toand方法。但是,如果您想更好地控制方案、回合等,那么您可以使用class:此上下文对象允许我们使用多个方案,设置默认值或配置成本因素。如果您的应用程序身份验证很简单,那么这可能不是必需的,但如果您需要能够使用多种哈希算法、弃用它们、重新哈希哈希或类似的高级任务,那么您可能需要查看完全集成教程。

    from passlib.context import CryptContext
    ctx = CryptContext(schemes=["bcrypt", "argon2", "scrypt"],
                       default="bcrypt",
                       bcrypt__rounds=14)
    
    password = getpass()
    hashed_password = ctx.hash(password)
    print(hashed_password)
    # $2b$14$pFTXqnHjn91C8k8ehbuM.uSJM.H5S0l7vkxE8NxgAiS2LiMWMziAe
    
    print(ctx.verify(password, hashed_password))
    print(ctx.verify("not-the-password", hashed_password))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    您可能想要使用的另一个原因是,如果您需要处理操作系统密码,例如密码。为此,您可以使用 中可用的预配置上下文,有关更多详细信息,请参阅此处的示例。CryptContext/etc/shadowpasslib.hosts

    为了完整起见,我还列出了其他几个可用的库,包括它们的(不同的)用例:

    bcrypt是我们上面使用的库和算法。这与使用的代码相同,并且没有真正的理由使用此低级库。passlib

    crypt是一个Python标准库模块,它提供了可用于密码哈希的函数。但是,提供的算法取决于您的系统,文档中列出的算法不如上面显示的算法强大。

    hashlib是另一个内置模块。但是,这个包括适用于密码哈希的强大哈希函数。该库的界面使函数更具可定制性,因此需要更多的知识才能正确(安全地)使用。您绝对可以使用此模块中的函数,例如对密码进行哈希处理。hashlib.scrypt

    hmac,Python 标准库必须提供的最后一个哈希模块不适合密码哈希。HMAC 用于验证消息的完整性和真实性,并且不具有密码哈希所需的属性。

    小旁注:有了所有新获得的有关正确存储密码方法的知识,让我们想象一下您忘记了某些服务的密码。您点击“忘记密码?在网站上,他们向您发送您的实际密码,而不是恢复链接。这意味着他们以明文形式存储您的密码,这也意味着您应该逃离该服务(如果您在其他地方使用相同的密码,请更改它)。

    安全存储
    在上一节中,我们假设目的是存储其他用户的凭据,但是您自己用于登录远程系统的密码呢?

    将密码留在代码中显然是一个糟糕的选择,因为它以明文形式躺在那里供任何人查看,并且您还冒着意外将其推送到 git repo 的风险。更好的选择是将其存储在环境变量中。您可以创建文件,将其添加到当前项目所需的凭据,并填充它。然后,您可以使用package将所有这些变量放入您的应用程序中,如下所示:此代码段首先构建文件的路径 using 函数,然后用于加载环境变量。如果您的文件位于当前目录中,如上例所示,那么您可以简化代码并仅调用自动查找环境文件。加载文件后,剩下的就是使用 检索各个变量。.

    # pip install python-dotenv
    import os
    from os.path import join, dirname
    from dotenv import load_dotenv
    
    dotenv_path = join(dirname(__file__), ".env")
    load_dotenv(dotenv_path)
    
    API_KEY = os.environ.get("API_KEY", "default")
    
    print(API_KEY)
    # a3491fb2-000f-4d9f-943e-127cfe29c39c
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    或者,如果您不想用应用程序变量和机密污染您的环境,您可以像这样直接加载它们:上述解决方案很好,但我们可以做得更好。我们可以改用系统的密钥环,而不是将密码存储在未受保护的文件中,这是一个可以将安全凭据存储在主目录的加密文件中的应用程序。默认情况下,此文件使用您的用户帐户登录密码进行加密,因此当您登录时它会自动解锁,因此您不必担心额外的密码。

    from dotenv import dotenv_values
    
    config = dotenv_values(".env")
    print(config)
    # OrderedDict([('API_KEY', 'a3491fb2-000f-4d9f-943e-127cfe29c39c')])
    
    • 1
    • 2
    • 3
    • 4
    • 5

    要在 Python 应用程序中使用密钥环凭据,我们可以使用 library called:在上面的代码中,我们首先检查密钥环配置文件的位置,如果需要,您可以在其中进行一些配置调整。然后,我们检查活动的密钥环并继续向其添加密码。每个条目都有 3 个属性 - 服务、用户名和密码,其中服务充当命名空间,在本例中为应用程序的名称。要创建和检索条目,我们可以分别使用和。除此之外,还可以使用 - 它返回一个凭据对象,该对象具有用户名和密码的属性。

    # pip install keyring
    import keyring
    import keyring.util.platform_ as keyring_platform
    
    print(keyring_platform.config_root())
    # /home/username/.config/python_keyring  # Might be different for you
    
    print(keyring.get_keyring())
    # keyring.backends.SecretService.Keyring (priority: 5)
    
    NAMESPACE = "my-app"
    ENTRY = "API_KEY"
    
    keyring.set_password(NAMESPACE, ENTRY, "a3491fb2-000f-4d9f-943e-127cfe29c39c")
    print(keyring.get_password(NAMESPACE, ENTRY))
    # a3491fb2-000f-4d9f-943e-127cfe29c39c
    
    cred = keyring.get_credential(NAMESPACE, ENTRY)
    print(f"Password for username {cred.username} in namespace {NAMESPACE} is {cred.password}")
    # Password for username API_KEY in namespace my-app is a3491fb2-000f-4d9f-943e-127cfe29c39c
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    结语

    即使您不是安全专家,您仍然负责您构建的应用程序的基本安全功能。这包括妥善保管用户的数据,尤其是密码,因此希望其中一些示例和食谱可以帮助您做到这一点。

    — END —

    读者福利:知道你对Python感兴趣,便准备了这套python学习资料,

    对于0基础小白入门:

    如果你是零基础小白,想快速入门Python是可以考虑的。

    一方面是学习时间相对较短,学习内容更全面更集中。
    二方面是可以找到适合自己的学习方案

    包括:Python web开发,Python爬虫,Python数据分析,人工智能、机器学习等教程。带你从零基础系统性的学好Python!

    零基础Python学习资源介绍

    👉Python学习路线汇总👈

    Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。(学习教程文末领取哈)

    👉Python必备开发工具👈

    温馨提示:篇幅有限,已打包文件夹,获取方式在:文末

    👉Python学习视频600合集👈

    观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

    👉实战案例👈

    光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

    👉100道Python练习题👈

    检查学习结果。

    👉面试刷题👈



    在这里插入图片描述

    资料领取

    这份完整版的Python全套学习资料已为大家备好,朋友们如果需要可以微信扫描下方二维码添加,输入"领取资料" 可免费领取全套资料【有什么需要协作的还可以随时联系我】朋友圈也会不定时的更新最前言python知识。
    在这里插入图片描述

    好文推荐

    了解python的前景: https://blog.csdn.net/weixin_49892805/article/details/127196159

    了解python的副业: https://blog.csdn.net/weixin_49892805/article/details/127214402

  • 相关阅读:
    STM32MP157A驱动开发 | 04 - Linux DRM显示驱动框架
    《Python编程:从入门到实战》(第2版)学习笔记 第6章 字典
    如何利用播放器节省20%点播成本
    C#开发——基础语法
    立晶半导体Cubic Lattice Inc 专攻音频ADC,音频DAC,音频CODEC,音频CLASS D等CL7016
    java与hadoop中正则表达式有什么区别
    mmap使用测试
    client-go controller-runtime kubebuilder
    CSS基本讲解与使用(详解)
    Spring的创建和使用
  • 原文地址:https://blog.csdn.net/weixin_49892805/article/details/128084142