Подтвердить что ты не робот

Поле пароля в модели Django

Я пытаюсь создать модель, где я могу хранить имена пользователей и пароли для других приложений. Как установить поле пароля в Django, чтобы оно не было в текстовом редакторе admin? Спасибо заранее.

4b9b3361

Ответ 1

Поскольку @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)

Вы можете получить некоторые подсказки от этого метода о создании пароля и его сохранении.

Ответ 2

К сожалению, на этот вопрос нелегко ответить, потому что он зависит от приложений, которые вы пытаетесь выполнить проверку подлинности, а также зависит от того, насколько безопасны вы должны иметь поля пароля.

Если ваше приложение Django будет использовать пароль для аутентификации против другого приложения, для которого требуется отправить пароль открытого текста, ваши варианты:

  • Сохраните пароль в текстовом формате в вашей модели Django (ваш вопрос подразумевает, что вы не хотите этого делать)
  • Захватите главный пароль пользователя, прежде чем они смогут разблокировать сохраненный пароль для других приложений.
  • Обфускайте пароль в модели, чтобы доступ к нему мог получить любой, у кого были необработанные разрешения хранилища данных, но это просто не очевидно для случайных людей.

Вы можете использовать пароль пользователя Django в качестве основного пароля, если используете пользовательскую модель Django. Это означает, что вам необходимо сохранить этот главный пароль в памяти, что может сделать некоторые операции сложными для вас, например, перезапустить сервер или запустить резервные серверы с балансировкой нагрузки.

Альтернатива хранению паролей

К счастью, многие современные приложения поддерживают это по-другому, используя систему токенов доступа, основанную на ключах, а не на пароле. Пользователи руководствуются процессом настройки связи между двумя приложениями, и за кулисами приложения генерируют ключи для аутентификации друг друга либо на постоянной основе, либо с определенной датой истечения срока действия.

Facebook, например, поддерживает эту модель, и у них есть обширная документация о том, как она работает:

Разработчики Facebook: токены и типы доступа

Как только вам удастся связаться с Facebook с помощью [OAuth 2.0] (http://tools.ietf.org/html/draft-ietf-oauth-v2- 12), вам, вероятно, будет проще добавлять ссылки на другие приложений, использующих тот же протокол.

Ответ 3

Ваш лучший выбор (я знаю) - это выкопать код в коде django и посмотреть, как он там работает. Как я помню, они генерируют соленый хэш, так что значения обычного текста никогда не хранятся нигде, а скорее хеш и соль.

Если вы войдете в установку django и солотесь для слов, таких как хэш и соль, вы должны найти его довольно быстро. Извините за неопределенный ответ, но, возможно, он установит вас на правильный путь.

Ответ 4

Я не думаю, что вы когда-нибудь сможете дешифровать зашифрованный пароль, который был сохранен так же, как обычные пользовательские пароли django. Часть безопасности заключается в том, что они не дешифруются.

Ответ 5

Если вам нужно обратимое поле пароля, вы можете использовать что-то вроде этого:

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(PREFIXO_CRYPTO):
                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 глупое использование to_python()