Django 模型中的密码字段

发布于 2024-09-19 07:20:40 字数 76 浏览 8 评论 0 原文

我正在尝试创建一个模型,可以在其中存储其他应用程序的用户名和密码。如何在 Django 中设置密码字段,使其在管理中不是纯文本?提前致谢。

I'm trying to create a model where I can store usernames and passwords for other applications. How can I set a password field in Django so that it is not in plain text in admin? Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

世俗缘 2024-09-26 07:20:41

你最好的选择(我知道)是深入研究 django 代码中的代码,看看它是如何完成的。我记得,它们生成一个加盐哈希,以便纯文本值永远不会存储在任何地方,而是哈希和盐。

如果你进入 django 安装,并查找像 hash 和 salt 这样的词,你应该很快就能找到它。很抱歉回答含糊不清,但也许它会让您走上正确的道路。

Your best bet (I'm aware of) is to dig into the code in the django code, and see how it's done there. As I recall, they generate a salted hash so that the plain text values are never stored anywhere, but rather the hash and salt are.

If you go into the django installation, and poke around for words like hash and salt, you should find it pretty quickly. Sorry for the vague answer, but perhaps it will set you on the right path.

大海や 2024-09-26 07:20:41

不幸的是,这个问题没有一个简单的答案,因为它取决于您尝试对其进行身份验证的应用程序,并且还取决于您希望密码字段的安全程度。

如果您的 Django 应用程序将使用密码对另一个需要发送明文密码的应用程序进行身份验证,那么您的选项是:

  • 将密码以纯文本形式存储在您的 Django 模型中(您的问题意味着您不想这样做)
  • 在用户为其他应用程序解锁其存储的密码之前捕获用户的主密码
  • 混淆模型中的密码,以便具有原始数据存储权限的任何人都可以访问该密码,但对于临时查看者来说并不明显

您可以使用如果您使用 Django 的内置用户模型,则 Django 用户密码作为主密码。这意味着您需要将主密码保留在内存中,这可能会使您的某些操作变得困难,例如重新启动服务器或运行负载平衡的冗余服务器。

存储密码的替代方案

幸运的是,许多现代应用程序使用基于密钥而不是基于密码的访问令牌系统以另一种方式支持这一点。用户将被引导完成在两个应用程序之间建立链接的过程,并且在幕后,应用程序生成密钥以永久或在定义的到期日期内相互验证。

例如,Facebook 支持此模型,并且他们有关于其工作原理的大量文档:

Facebook 开发人员:访问令牌和类型

一旦您成功使用 [OAuth 2.0](http://tools.ietf.org/html/draft-ietf-oauth-v2-12) 与 Facebook 链接)您可能会发现使用相同协议添加到其他应用程序的链接更容易。

Unfortunately there isn't an easy answer to this question because it depends on the applications you are trying to authenticate against and it also depends on how secure you want the password fields to be.

If your Django application will be using the password to authenticate against another application that requires a plaintext password to be sent, then your options are:

  • Store the password in plain text in your Django model (your question implies you don't want to do this)
  • Capture a master password from the user before they can unlock their stored password for other applications
  • Obfuscate the password in the model so that it can be accessed by anyone with raw datastore permissions but just isn't obvious to human casual viewers

You could use the Django user password as the master password if you are using Django's builtin user model. This means that you will need to keep that master password in memory which may make some operations difficult for you, such as restarting the server or running load-balanced redundant servers.

Alternative to storing passwords

Luckily many modern applications support this in another way using an access token system which is key based rather than password based. Users are guided through the process of setting up a link between the two applications and, behind the scenes, the applications generate keys to authenticate each other either permanently or with a defined expiration date.

Facebook, for example, supports this model and they have extensive documentation about how it works:

Facebook Developers: Access Tokens and Types

Once you have managed to link with Facebook using [OAuth 2.0](http://tools.ietf.org/html/draft-ietf-oauth-v2- 12) you will probably find it easier to add links to other applications using that same protocol.

流绪微梦 2024-09-26 07:20:41

如果您需要可逆的密码字段,您可以使用如下内容:

from django.db import models
from django.core.exceptions import ValidationError
from django.conf import settings

from os import urandom
from base64 import b64encode, b64decode
from Crypto.Cipher import ARC4
from django import forms



PREFIX = u'\u2620'


class EncryptedCharField(models.CharField): 
    __metaclass__ = models.SubfieldBase

    SALT_SIZE = 8

    def __init__(self, *args, **kwargs):
        self.widget = forms.TextInput       
        super(EncryptedCharField, self).__init__(*args, **kwargs)

    def get_internal_type(self):
        return 'TextField'    

    def to_python(self, value):
        if not value:
            return None
        if isinstance(value, basestring):
            if value.startswith(PREFIX):
                return self.decrypt(value)
            else:
                return value
        else:
            raise ValidationError(u'Failed to encrypt %s.' % value)

    def get_db_prep_value(self, value, connection, prepared=False):
        return self.encrypt(value)        

    def value_to_string(self, instance):
        encriptado = getattr(instance, self.name)
        return self.decrypt(encriptado) if encriptado else None

    @staticmethod
    def encrypt(plaintext):
        plaintext = unicode(plaintext)
        salt = urandom(EncryptedCharField.SALT_SIZE)
        arc4 = ARC4.new(salt + settings.SECRET_KEY)
        plaintext = u"%3d%s%s" % (len(plaintext), plaintext, b64encode(urandom(256-len(plaintext))))
        return PREFIX + u"%s$%s" % (b64encode(salt), b64encode(arc4.encrypt(plaintext.encode('utf-8-sig'))))

    @staticmethod
    def decrypt(ciphertext):
        salt, ciphertext = map(b64decode, ciphertext[1:].split('

加密部分基于 https 上的片段://djangosnippets.org/snippets/1330/,我刚刚将其转换为字段模型,添加了 utf-8 支持并添加了前缀作为 Django 对 to_python() 的愚蠢使用

)) arc4 = ARC4.new(salt + settings.SECRET_KEY) plaintext = arc4.decrypt(ciphertext).decode('utf-8-sig') return plaintext[3:3+int(plaintext[:3].strip())]

加密部分基于 https 上的片段://djangosnippets.org/snippets/1330/,我刚刚将其转换为字段模型,添加了 utf-8 支持并添加了前缀作为 Django 对 to_python() 的愚蠢使用

If you need a reversible password field, you could use something like this:

from django.db import models
from django.core.exceptions import ValidationError
from django.conf import settings

from os import urandom
from base64 import b64encode, b64decode
from Crypto.Cipher import ARC4
from django import forms



PREFIX = u'\u2620'


class EncryptedCharField(models.CharField): 
    __metaclass__ = models.SubfieldBase

    SALT_SIZE = 8

    def __init__(self, *args, **kwargs):
        self.widget = forms.TextInput       
        super(EncryptedCharField, self).__init__(*args, **kwargs)

    def get_internal_type(self):
        return 'TextField'    

    def to_python(self, value):
        if not value:
            return None
        if isinstance(value, basestring):
            if value.startswith(PREFIX):
                return self.decrypt(value)
            else:
                return value
        else:
            raise ValidationError(u'Failed to encrypt %s.' % value)

    def get_db_prep_value(self, value, connection, prepared=False):
        return self.encrypt(value)        

    def value_to_string(self, instance):
        encriptado = getattr(instance, self.name)
        return self.decrypt(encriptado) if encriptado else None

    @staticmethod
    def encrypt(plaintext):
        plaintext = unicode(plaintext)
        salt = urandom(EncryptedCharField.SALT_SIZE)
        arc4 = ARC4.new(salt + settings.SECRET_KEY)
        plaintext = u"%3d%s%s" % (len(plaintext), plaintext, b64encode(urandom(256-len(plaintext))))
        return PREFIX + u"%s$%s" % (b64encode(salt), b64encode(arc4.encrypt(plaintext.encode('utf-8-sig'))))

    @staticmethod
    def decrypt(ciphertext):
        salt, ciphertext = map(b64decode, ciphertext[1:].split('

The encryption part is based on the snippet on https://djangosnippets.org/snippets/1330/, I just turned it into a field model, added utf-8 support and added a prefix as a workaround for Django's silly use of to_python()

)) arc4 = ARC4.new(salt + settings.SECRET_KEY) plaintext = arc4.decrypt(ciphertext).decode('utf-8-sig') return plaintext[3:3+int(plaintext[:3].strip())]

The encryption part is based on the snippet on https://djangosnippets.org/snippets/1330/, I just turned it into a field model, added utf-8 support and added a prefix as a workaround for Django's silly use of to_python()

季末如歌 2024-09-26 07:20:40

正如 @mlissner 建议 auth.User 模型是一个观察的好地方。如果您检查源代码,您将看到 password 字段是一个 CharField

password = models.CharField(_('password'), max_length=128, help_text=_("Use 
'[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."))

User 模型还有一个 set_password 方法。

def set_password(self, raw_password):
    import random
    algo = 'sha1'
    salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
    hsh = get_hexdigest(algo, salt, raw_password)
    self.password = '%s$%s$%s' % (algo, salt, hsh)

您可以从此方法中获取一些有关创建密码并保存密码的线索。

As @mlissner suggested the auth.User model is a good place to look. If you check the source code you'll see that the password field is a CharField.

password = models.CharField(_('password'), max_length=128, help_text=_("Use 
'[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>."))

The User model also has a set_password method.

def set_password(self, raw_password):
    import random
    algo = 'sha1'
    salt = get_hexdigest(algo, str(random.random()), str(random.random()))[:5]
    hsh = get_hexdigest(algo, salt, raw_password)
    self.password = '%s$%s$%s' % (algo, salt, hsh)

You can take some clues from this method about creating the password and saving it.

花间憩 2024-09-26 07:20:40

我不认为你能够对以类似于普通 django 用户密码的方式存储的加密密码进行反哈希处理。部分安全性在于它们是不可解散列的。

I don't think you are ever going to be able to de-hash an encrypted password that was stored in a manner similar to the normal django User passwords. Part of the security is that they are un-de-hashable.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文