代码之家  ›  专栏  ›  技术社区  ›  Ruben Quinones

Django模型中的密码字段

  •  24
  • Ruben Quinones  · 技术社区  · 14 年前

    5 回复  |  直到 14 年前
        1
  •  29
  •   Community Muhammed Neswine    7 年前

    suggested 这个 auth.User 模特儿是个好去处。如果你检查一下 source code 你会看到 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)
    

    您可以从这个方法中获得一些关于创建密码和保存密码的线索。

        2
  •  6
  •   Marc    13 年前

    我不认为你将永远能够去散列一个加密的密码,是存储在一个类似于普通的django用户密码的方式。安全性的一部分是它们是不可散列的。

        3
  •  5
  •   jwal    12 年前

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

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

    • 在用户为其他应用程序解锁存储的密码之前,从用户处获取主密码
    • 对模型中的密码进行模糊处理,以便任何拥有原始数据存储权限的人都可以访问它,但对普通用户来说并不明显

    存储密码的替代方法

    幸运的是,许多现代应用程序使用基于密钥而不是基于密码的访问令牌系统以另一种方式支持这一点。用户将被引导完成在两个应用程序之间建立链接的过程,在后台,应用程序将生成密钥,以便永久地或使用定义的过期日期对彼此进行身份验证。

    Facebook Developers: Access Tokens and Types

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

        4
  •  4
  •   mlissner    14 年前

    如果您进入django安装程序,四处寻找诸如hash和salt之类的词,您应该很快就会找到它。很抱歉你的回答含糊不清,但也许这会使你走上正确的道路。

        5
  •  3
  •   hlongmore    6 年前

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

    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('$'))
            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's silly use of to_python()