Поле пароля в модели Django - PullRequest
24 голосов
/ 15 сентября 2010

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

Ответы [ 5 ]

27 голосов
/ 15 сентября 2010

Как подсказал @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)

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

5 голосов
/ 27 декабря 2011

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

4 голосов
/ 16 ноября 2012

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

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

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

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

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

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

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

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

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

3 голосов
/ 15 сентября 2010

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

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

2 голосов
/ 22 мая 2014

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

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

...