type - Campo de contraseña en el modelo Django
password field django (5)
Lamentablemente, no hay una respuesta fácil a esta pregunta porque depende de las aplicaciones a las que intenta autenticarse y también depende de cuán seguros sean los campos de contraseña.
Si su aplicación Django utilizará la contraseña para autenticarse contra otra aplicación que requiere el envío de una contraseña de texto simple, sus opciones son:
- Almacene la contraseña en texto plano en su modelo Django (su pregunta implica que no desea hacer esto)
- Capture una contraseña maestra del usuario antes de que pueda desbloquear su contraseña almacenada para otras aplicaciones
- Ofuscar la contraseña en el modelo para que cualquier persona con permisos de almacén de datos sin formato pueda acceder a ella, pero no es obvio para los espectadores casuales humanos
Puede usar la contraseña de usuario de Django como contraseña maestra si está utilizando el modelo de usuario integrado de Django. Esto significa que deberá conservar esa contraseña maestra en la memoria, lo que puede dificultar algunas operaciones, como reiniciar el servidor o ejecutar servidores redundantes de carga equilibrada.
Alternativa para almacenar contraseñas
Afortunadamente, muchas aplicaciones modernas soportan esto de otra manera utilizando un sistema de token de acceso basado en claves en lugar de basado en contraseñas. Los usuarios son guiados a través del proceso de configuración de un enlace entre las dos aplicaciones y, detrás de escena, las aplicaciones generan claves para autenticarse mutuamente de forma permanente o con una fecha de vencimiento definida.
Facebook, por ejemplo, es compatible con este modelo y tienen una amplia documentación sobre cómo funciona:
Desarrolladores de Facebook: Fichas de acceso y tipos
Una vez que haya logrado vincularse con Facebook utilizando [OAuth 2.0] (http://tools.ietf.org/html/draft-ietf-oauth-v2- 12) probablemente le resulte más fácil agregar enlaces a otras aplicaciones que usen ese mismo protocolo.
Intento crear un modelo donde pueda almacenar nombres de usuario y contraseñas para otras aplicaciones. ¿Cómo puedo establecer un campo de contraseña en Django para que no esté en texto plano en el administrador? Gracias por adelantado.
No creo que puedas descifrar una contraseña cifrada que se almacenó de manera similar a las contraseñas de usuario de django normales. Parte de la seguridad es que no se pueden manipular.
Si necesita un campo de contraseña reversible, podría usar algo como esto:
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())]
La parte de cifrado se basa en el fragmento en https://djangosnippets.org/snippets/1330/ , lo convertí en un modelo de campo, agregué soporte para utf-8 y agregué un prefijo como una solución para el uso tonto de Django de to_python ( )
Tu mejor apuesta (estoy al tanto) es profundizar en el código en el código django, y ver cómo se hace allí. Según recuerdo, generan un hash salado para que los valores de texto plano nunca se almacenen en ningún lugar, sino que son el hash y la sal.
Si vas a la instalación de django y buscas palabras como hash y sal, deberías encontrarlo bastante rápido. Perdón por la respuesta vaga, pero tal vez te ponga en el camino correcto.
Como @mlissner suggested el modelo auth.User
es un buen lugar para buscar. Si comprueba el código fuente , verá que el campo de password
es un CharField
.
password = models.CharField(_(''password''), max_length=128, help_text=_("Use
''[algo]$[salt]$[hexdigest]'' or use the <a href=/"password//">change password form</a>."))
El modelo de User
también tiene un método 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)
Puede tomar algunas pistas de este método para crear la contraseña y guardarla.