Efectos de cambiar SECRET_KEY de Django

202

Cometí un error y comprometí mis proyectos de Django SECRET_KEYen un repositorio público.

Esta clave debería haberse mantenido en secreto de acuerdo con los documentos https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-SECRET_KEY

El proyecto Django está en vivo y se ha estado ejecutando durante un tiempo con algunos usuarios activos. ¿Cuáles son los efectos si cambio el SECRET_KEY? ¿Se verán afectados los usuarios existentes, cookies, sesiones, etc.? Obviamente, lo nuevo SECRET_KEYya no se almacenará en una ubicación pública.

Derek Kwok
fuente

Respuestas:

199

Editar: esta respuesta se basa en django 1.5

SECRET_KEY se usa en muchos lugares diferentes, primero señalaré lo que se ve afectado y luego intentaré repasar esa lista y dar una explicación precisa del impacto.

La lista de cosas usando SECRET_KEYdirecta o indirectamente:

En realidad, muchos de los elementos enumerados aquí usan a SECRET_KEYtravés del django.utils.crypt.get_random_string()cual se usa para sembrar el motor aleatorio. Esto no se verá afectado por un cambio en el valor de SECRET_KEY.

La experiencia del usuario directamente afectada por un cambio de valor son:

  • sesiones, la decodificación de datos se interrumpirá, eso es válido para cualquier backend de sesión (cookies, base de datos, archivo o caché).
  • el token de restablecimiento de contraseña ya enviado no funcionará, los usuarios deberán solicitar uno nuevo.
  • el formulario de comentarios (si se usa django.contrib.comments) no validará si se solicitó antes del cambio de valor y se envió después del cambio de valor. Creo que esto es muy pequeño, pero puede ser confuso para el usuario.
  • los mensajes (desde django.contrib.messages) no validarán el lado del servidor en las mismas condiciones de tiempo que para el formulario de comentarios.

ACTUALIZACIÓN : ahora trabajando en django 1.9.5, un vistazo rápido a la fuente me da casi las mismas respuestas. Podría hacer una inspección minuciosa más tarde.

sberder
fuente
1
Estoy cambiando SECRET_KEY en mi servidor de desarrollo local y eso no me cierra la sesión, por lo que parece que al menos las sesiones (caché) funcionan correctamente después del cambio. ¿Podrías dar más detalles sobre lo que quieres decir data decode will breaky tal vez señalar algún código (en django o proyecto de ejemplo) que se romperá? EDITAR: sigo usando django 1.4, ¿es ese el caso?
Kirill Zaitsev
@teferi No sé acerca de 1.4, es cuestión de echar un vistazo al código. Apunté a todas las fuentes para cada punto, puede echar un vistazo a "proteger los datos de la sesión y crear claves de sesión aleatorias". Es normal que todavía haya iniciado sesión, pero no podrá leer los datos contenidos en la sesión como SECRET_KEYse usa en salted_hmachash los datos de la sesión.
sberder
si se usa para sal de hash de contraseña, ¿eso no significa que las contraseñas en la base de datos deben restablecerse?
Henning
77
@Henning no lo creo. Las contraseñas se almacenan como <algorithm>$<iterations>$<salt>$<hash>en auth_user, por lo que la sal aleatoria se almacena junto con la contraseña en cada caso.
Denis Drescher
2
¿Sería la respuesta significativamente diferente en las versiones de Django> 1.5? (por ejemplo, el actual 1.9)
das-g
36

Desde que se hizo esta pregunta, la documentación de Django ha cambiado para incluir una respuesta.

La clave secreta se usa para:

  • Todas las sesiones si está utilizando cualquier otro back-end de sesión que no sea django.contrib.sessions.backends.cache, o está utilizando el predeterminado get_session_auth_hash().
  • Todos los mensajes si está utilizando CookieStorageo FallbackStorage.
  • Todas las PasswordResetViewfichas.
  • Cualquier uso de firma criptográfica, a menos que se proporcione una clave diferente.

Si gira su clave secreta, se invalidará todo lo anterior. Las claves secretas no se utilizan para las contraseñas de los usuarios y la rotación de claves no las afectará.

No estaba claro para mí exactamente cómo debía girar la clave secreta. Encontré una discusión sobre cómo Django genera una clave para un nuevo proyecto , así como un Gist que analiza otras opciones . Finalmente decidí que Django creara un nuevo proyecto, copie la nueva clave secreta en mi antiguo proyecto y luego borre el nuevo proyecto .

cd ~/junk # Go to some safe directory to create a new project.
django-admin startproject django_scratch
grep SECRET_KEY django_scratch/django_scratch/settings.py # copy to old project
rm -R django_scratch

Actualizar

Parece que Django agregó la get_random_secret_key()función en la versión 1.10. Podrías usar eso para generar una nueva clave secreta.

$ ./manage.py shell -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
s!)5@5s79sp=92a+!f4v!1g0d0+64ln3d$xm1f_7=749ht&-zi
$ ./manage.py shell -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
_)+%kymd=f^8o_fea1*yro7atz3w+5(t2/lm2cz70*e$2mn\g3
$
Don Kirkby
fuente
44
¿La generación de claves secretas depende de la clave secreta?
kdazzle
44
No, @kdazzle, si observa el código fuentestartproject , puede ver que solo genera una cadena aleatoria utilizando el cryptomódulo.
Don Kirkby el
12
Je, lo siento, @DonKirkby, broma mala
kdazzle
16

De acuerdo con esta página https://docs.djangoproject.com/en/dev/topics/signing/ , la SECRET_KEY se usa principalmente para cosas transitorias: la firma de datos enviados a través del cable para que pueda detectar la manipulación, por ejemplo. Parece que las cosas que PODRÍAN romperse son:

  • Cookies firmadas, por ejemplo, valores de tipo "recordar mi autenticación en esta computadora". En este caso, la cookie se invalidará, la firma no se podrá verificar y el usuario tendrá que volver a autenticarse.
  • Para los usuarios que hayan solicitado enlaces para restablecer la contraseña o descargar un archivo personalizado, esos enlaces ya no serán válidos. Los usuarios simplemente tendrían que volver a solicitar esos enlaces.

Alguien con experiencia Django más reciente y / o relevante que yo podría intervenir de otra manera, pero sospecho que a menos que esté haciendo algo explícitamente con la API de firma, esto solo debería crear un inconveniente leve para sus usuarios.

Tim Keating
fuente
66
Entonces, ¿por qué no generar una nueva clave en cada reinicio del servidor?
osa
44
Probablemente causaría un problema si está ejecutando el mismo servidor utilizando múltiples procesos.
dbn
1
@osa ¿Desea cerrar sesión en TODOS sus usuarios cada vez que presiona el código / reinicia su servidor?
EralpB
6

La cadena SECRET_KEY se usa principalmente para encriptar y / o hacer hash de datos de cookies. Muchos marcos (incluido Django) llegan a esto ya que las cookies de sesión predeterminadas tienen sus propios inconvenientes.

Imagine que tiene un formulario en django para editar artículos con un campo oculto. En este campo oculto se almacena la ID del artículo que está editando. Y si desea asegurarse de que nadie pueda enviarle ninguna otra identificación de artículo, agregará un campo oculto adicional con la identificación hash. Entonces, si alguien cambia la identificación, lo sabrás porque el hash no será el mismo.

Por supuesto, este es un ejemplo trivial, pero así es como se usa SECRET_KEY.

Django lo está utilizando internamente, por ejemplo, para {% csrf_token%} y algunas cosas más. Realmente no debería tener ningún impacto en su aplicación si la cambia, en función de su pregunta y de que no la está utilizando.

Lo único es que tal vez los valores de la sesión se eliminarán. Entonces, por ejemplo, los usuarios tendrán que iniciar sesión en admin nuevamente, porque django no podrá decodificar la sesión con una clave diferente.

sin oscuridad
fuente
1

Cometí este mismo error. La contraseña predeterminada tenía una longitud de 50, por lo que utilicé powershell para generar una cadena aleatoria de 50 y reemplacé la antigua SECRET_KEY con ella. Estaba conectado y después de reemplazar la SECRET_KEY mi sesión anterior había sido invalidada.

Con Powershell ( fuente ):

# Load the .net System.Web namespace which has the GeneratePassword function
[Reflection.Assembly]::LoadWithPartialName("System.Web")

#  GeneratePassword(int length, int numberOfNonAlphanumericCharacters)
[System.Web.Security.Membership]::GeneratePassword(50,5)

Con Bash ( fuente ):

# tr includes ABCabc123 and the characters from OWASP's "Password special characters list"
cat /dev/urandom | tr -dc 'A-Za-z0-9!"#$%&\''()*+,-./:;<=>?@[\]^_`{|}~' | head -c 100 ; echo

En este punto, pensé por qué no probar una clave más grande, así que lo intenté con una clave larga de 100 y 1000. Ambos trabajaron. Si entiendo el código fuente , el objeto devuelto por la función de firmante es un hash hmac en base64. RFC 2104 tiene esto que decir para la longitud requerida de una clave secreta HMAC.

Las aplicaciones que usan claves más largas que B bytes primero harán un hash de la clave usando H y luego usarán la cadena de bytes L resultante como la clave real para HMAC.

La clave para HMAC puede ser de cualquier longitud (las claves más largas que B bytes se codifican primero con H). Sin embargo, se desaconseja encarecidamente menos de L bytes ya que disminuiría la seguridad de la función. Las claves de más de L bytes son aceptables, pero la longitud adicional no aumentaría significativamente la fuerza de la función. (Una clave más larga puede ser aconsejable si la aleatoriedad de la clave se considera débil).

Para traducir al habla normal, el tamaño de la clave secreta debe ser del mismo tamaño que la salida. La clave también debe estar en bits. Cada dígito en base64 representa 6 bits. Entonces, si tuviera una contraseña de 50 caracteres, tendría una clave secreta de 50 x 6 = 300 bits. Si está utilizando SHA256, necesitaría una clave de 256 bits ( sha256 utiliza 256 bits por definición ). Por lo tanto, una contraseña larga de 50 debería funcionar a menos que planee usar un algoritmo de hash más grande que SHA256.

Pero dado que los bits adicionales de la clave se están procesando, su tamaño no disminuirá drásticamente el rendimiento. Pero le garantizaría que tiene suficientes bits para funciones hash más grandes. SHA-512 estaría cubierto por una SECRET_KEY de 100 largos ( 50 x 6 = 600 bits> 512 bits ).

Rex Linder
fuente