Я пытаюсь создать модель, в которой я могу хранить имена пользователей и пароли для других приложений. Как я могу установить поле пароля в Django, чтобы оно не было в виде простого текста в админке? Заранее спасибо.
Поле пароля в модели Django
- Спасибо всем за ваши ответы. Я придерживаюсь предложения Млисснера и Маноджа, хотя особое внимание уделяется ребусу, поскольку его подход подходит для простых приложений, где вам просто нужна простая функциональность без особой безопасности. 16.09.2010
- Это может сделать то, что вы хотите. djangosnippets.org/snippets/1330 03.12.2012
- Пинг - Вы реализовали это? Я смотрю на реализацию подобной вещи, но я не уверен, с чего начать, не могли бы вы указать мне правильное направление? 27.11.2013
- Джек - есть, но я сделал немного по-другому. Я использую set_password, как Маной указал в своем ответе, оттуда я могу проверить хэш пароля, введенного пользователем для входа в систему, либо путем разделения строки algo/salt/hash, оставив только хеш для сравнения, либо используя статическую соль и сравните их вообще. 28.11.2013
Ответы:
Как @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)
Вы можете извлечь некоторые подсказки из этого метода о создании пароля и его сохранении.
Я не думаю, что вы когда-нибудь сможете расшифровать зашифрованный пароль, который был сохранен способом, аналогичным обычным паролям пользователя django. Частью безопасности является то, что они не дехэшируются.
К сожалению, на этот вопрос нет простого ответа, потому что это зависит от приложений, в которых вы пытаетесь пройти аутентификацию, а также от того, насколько безопасными должны быть поля пароля.
Если ваше приложение Django будет использовать пароль для аутентификации в другом приложении, которое требует отправки открытого пароля, то ваши варианты:
- Сохраните пароль в виде обычного текста в вашей модели Django (ваш вопрос подразумевает, что вы не хотите этого делать)
- Захват мастер-пароля от пользователя, прежде чем он сможет разблокировать сохраненный пароль для других приложений
- Замаскируйте пароль в модели, чтобы к нему мог получить доступ любой, у кого есть права доступа к необработанному хранилищу данных, но он просто не очевиден для случайных зрителей.
Вы можете использовать пароль пользователя Django в качестве главного пароля, если используете встроенную пользовательскую модель Django. Это означает, что вам нужно будет хранить этот мастер-пароль в памяти, что может затруднить некоторые операции, такие как перезапуск сервера или запуск резервных серверов с балансировкой нагрузки.
Альтернатива хранению паролей
К счастью, многие современные приложения поддерживают это по-другому, используя систему токенов доступа, основанную на ключе, а не на пароле. Пользователей сопровождают в процессе установки связи между двумя приложениями, а за кулисами приложения генерируют ключи для аутентификации друг друга либо на постоянной основе, либо с определенной датой истечения срока действия.
Facebook, например, поддерживает эту модель, и у них есть обширная документация о том, как она работает:
Разработчики Facebook: токены и типы доступа
После того, как вам удалось установить связь с Facebook с помощью [OAuth 2.0] (http://tools.ietf.org/html/draft-ietf-oauth-v2-12), вам, вероятно, будет проще добавлять ссылки на другие приложения с помощью этого тот же протокол.
Лучше всего (я знаю) покопаться в коде в коде django и посмотреть, как это делается там. Насколько я помню, они генерируют хэш с солью, так что простые текстовые значения никогда и нигде не хранятся, а хранятся хеш и соль.
Если вы зайдете в установку django и поищите такие слова, как хеш и соль, вы должны найти это довольно быстро. Извините за расплывчатый ответ, но, возможно, он направит вас на правильный путь.
Если вам нужно обратимое поле пароля, вы можете использовать что-то вроде этого:
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()
pip install pycrypto
, а не pip install Crypto
. Кроме того, теперь в pypi доступен пакет со многими полями, который называется django-encrypted-fields
(или для python 3, django-encrypted-fields-python3
). 17.02.2018
AbstractBaseUser
и проверки паролей находятся вdjango.contrib.auth.hashers
. Опять же, хотя проза этого ответа в целом верна, код устарел. Ответ мог бы сделать с некоторым тщательным переписыванием. 13.12.2016