Efeitos da alteração SECRET_KEY do Django

202

Cometi um erro e comprometi meu projeto Django SECRET_KEYem um repositório público.

Essa chave deve ter sido mantida em segredo de acordo com os documentos https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-SECRET_KEY

O projeto Django está ativo e está em execução há algum tempo com alguns usuários ativos. Quais são os efeitos se eu mudar o SECRET_KEY? Algum usuário existente, cookies, sessões, etc. serão afetados? Obviamente, o novo SECRET_KEYnão será mais armazenado em um local público.

Derek Kwok
fonte

Respostas:

199

Edit: Esta resposta é baseada no django 1.5

SECRET_KEY é usado em vários lugares, vou apontar primeiro o que é impactado por ela e depois tentar revisar a lista e fornecer explicações precisas do impacto.

A lista de itens usando SECRET_KEYdireta ou indiretamente:

Na realidade, muitos dos itens listados aqui são usados SECRET_KEYatravés dos django.utils.crypt.get_random_string()quais são usados ​​para propagar o mecanismo aleatório. Isso não será afetado por uma alteração no valor de SECRET_KEY.

A experiência do usuário diretamente impactada por uma mudança de valor é:

  • sessões, a decodificação de dados será interrompida, válida para qualquer back-end de sessão (cookies, banco de dados, arquivo ou cache).
  • o token de redefinição de senha já enviado não funcionará, os usuários terão que solicitar um novo.
  • o formulário de comentários (se estiver usando django.contrib.comments) não validará se foi solicitado antes da alteração do valor e enviado após a alteração do valor. Eu acho que isso é muito pequeno, mas pode ser confuso para o usuário.
  • as mensagens (de django.contrib.messages) não validarão o servidor nas mesmas condições de tempo do formulário de comentários.

ATUALIZAÇÃO : agora trabalhando no django 1.9.5, uma rápida olhada na fonte me dá praticamente as mesmas respostas. Pode fazer uma inspeção completa mais tarde.

sberder
fonte
1
Estou mudando SECRET_KEY no meu servidor dev local e isso não me desconecta, portanto parece que pelo menos as sessões (cache) funcionam corretamente após a alteração. Você poderia, por favor, aprofundar o que você quer dizer data decode will breake talvez apontar algum código (no django ou no exemplo de projeto) que será quebrado? EDIT: ainda usando o django 1.4 - é esse o caso?
21413 Kirill Zaitsev
@teferi Eu não sei sobre 1.4, é uma questão de dar uma olhada no código. Eu apontei para todas as fontes de cada ponto, você pode dar uma olhada em "proteger os dados da sessão e criar chaves de sessão aleatórias". É normal que você ainda esteja logado, mas não poderá ler os dados contidos na sessão, como SECRET_KEYé usado no salted_hmachash dos dados da sessão.
sberder
se for usado para o hash de senha, isso não significa que as senhas no banco de dados precisam ser redefinidas?
Henning
7
@ Henning, acho que não. As senhas são armazenadas como <algorithm>$<iterations>$<salt>$<hash>em auth_user, portanto, o salt aleatório é armazenado ao lado da senha em cada caso.
Denis Drescher
2
A resposta seria significativamente diferente nas versões do Django> 1.5? (por exemplo, o atual 1,9)
das-g
36

Desde que esta pergunta foi feita, a documentação do Django foi alterada para incluir uma resposta.

A chave secreta é usada para:

  • Todas as sessões se você estiver usando qualquer outro backend de sessão que não django.contrib.sessions.backends.cacheseja o padrão get_session_auth_hash().
  • Todas as mensagens se você estiver usando CookieStorageou FallbackStorage.
  • Todos os PasswordResetViewtokens.
  • Qualquer uso de assinatura criptográfica, a menos que uma chave diferente seja fornecida.

Se você girar sua chave secreta, todos os itens acima serão invalidados. Chaves secretas não são usadas para senhas de usuários e a rotação de chaves não as afetará.

Não estava claro para mim exatamente como eu deveria girar a chave secreta. Eu encontrei uma discussão sobre como o Django gera uma chave para um novo projeto , bem como um Gist que discute outras opções . Finalmente decidi pedir ao Django para criar um novo projeto, copiar a nova chave secreta no meu projeto antigo e depois apagar o novo projeto .

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

Atualizar

Parece que o Django adicionou a get_random_secret_key()função na versão 1.10. Você pode usar isso para gerar uma nova chave 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
fonte
4
A geração de chave secreta depende da chave secreta?
Kdazzle #
4
Não, @kdazzle, se você olhar para o código-fontestartproject , poderá ver que ele apenas gera uma sequência aleatória usando o cryptomódulo.
Don Kirkby
12
Heh, desculpe, @DonKirkby, piada de mau gosto
kdazzle
16

De acordo com esta página https://docs.djangoproject.com/en/dev/topics/signing/ , o SECRET_KEY é usado principalmente para itens transitórios - assinando dados enviados por fio, para que você possa detectar violações, por exemplo. Parece que as coisas que poderiam quebrar são:

  • Cookies assinados, por exemplo, "lembre-se da minha autenticação neste computador". Nesse caso, o cookie será invalidado, a assinatura falhará na verificação e o usuário precisará se autenticar novamente.
  • Para qualquer usuário que tenha solicitado links para redefinição de senha ou download de arquivo personalizado, esses links não serão mais válidos. Os usuários precisariam simplesmente solicitar novamente esses links.

Alguém com uma experiência Django mais recente e / ou mais destacada do que eu pode gritar de outra forma, mas suspeito que, a menos que você esteja explicitamente fazendo algo com a API de assinatura, isso deve criar apenas um pequeno inconveniente para seus usuários.

Tim Keating
fonte
6
Por que não gerar uma nova chave em cada reinicialização do servidor?
Osa
4
Provavelmente, isso causaria um problema se você estivesse executando o mesmo servidor usando vários processos.
dbn
1
@osa você gostaria de desconectar TODOS os seus usuários sempre que pressionar o código / reiniciar o servidor?
EralpB
6

A cadeia SECRET_KEY é usada principalmente para criptografar e / ou hash de dados de cookies. Muitas estruturas (incluindo o Django) chegam a isso, já que os cookies de sessão padrão têm suas próprias desvantagens.

Imagine que você tenha um formulário no django para editar artigos com um campo oculto. Nesse campo oculto, está armazenado o ID do artigo que você está editando. E se você quiser ter certeza de que ninguém pode enviar outra identificação de artigo, você adicionará um campo oculto extra com a identificação de hash. Portanto, se alguém alterar o ID, você saberá porque o hash não será o mesmo.

Claro que este é um exemplo trivial, mas é assim que o SECRET_KEY é usado.

O Django está usando-o internamente, por exemplo, para {% csrf_token%} e mais algumas coisas. Realmente não deve ter nenhum impacto no seu aplicativo se você o alterar, com base na sua pergunta e se não o estiver usando.

A única coisa é que talvez os valores da sessão sejam descartados. Por exemplo, os usuários terão que entrar no admin novamente, porque o django não poderá decodificar a sessão com uma chave diferente.

escuro
fonte
1

Eu cometi esse mesmo erro. A senha padrão era 50, então usei o powershell para gerar uma sequência aleatória de 50 e substitui a antiga SECRET_KEY por ela. Eu estava conectado e, após substituir o SECRET_KEY, minha sessão anterior foi invalidada.

Com o Powershell ( fonte ):

# 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)

Com o Bash ( fonte ):

# 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

Nesse ponto, pensei em por que não tentar uma chave maior, então tentei com uma chave longa de 100 e 1000. Ambos funcionaram. Se eu entendo o código fonte , o objeto retornado pela função signatário é um hash hmac em base64. A RFC 2104 tem isso a dizer para o comprimento necessário de uma chave secreta do HMAC.

Os aplicativos que usam chaves com mais de B bytes primeiro hash a chave usando H e, em seguida, usam a sequência de bytes L resultante como a chave real do HMAC.

A chave para o HMAC pode ter qualquer comprimento (chaves maiores que B bytes são primeiro divididas por hash usando H). No entanto, menos de L bytes é fortemente desencorajado, pois diminuiria a força de segurança da função. Chaves maiores que L bytes são aceitáveis, mas o comprimento extra não aumentaria significativamente a força da função. (Uma chave mais longa pode ser aconselhável se a aleatoriedade da chave for considerada fraca.)

Para traduzir para a fala normal, o tamanho da chave secreta precisa ter o mesmo tamanho da saída. A chave também precisa estar em bits. Cada dígito em base64 representa 6 bits. Portanto, se você tivesse uma senha de 50 caracteres, teria uma chave secreta de 50 x 6 = 300 bits. Se você estiver usando o SHA256, precisará de uma chave de 256 bits ( sha256 usa 256 bits por definição ). Portanto, uma senha longa de 50 deve funcionar, a menos que você planeje usar um algoritmo de hash maior que o SHA256.

Mas, como qualquer bit extra na chave está sendo hash, seu tamanho não diminui drasticamente o desempenho. Mas isso garantiria que você tenha bits suficientes para funções hash maiores. O SHA-512 seria coberto por um SECRET_KEY de 100 comprimentos ( 50 x 6 = 600 bits> 512 bits ).

Rex Linder
fonte