Token CSRF / XSRF do Go: Propósito, Proteção de Formulários e Validade Padrão do Token do Pacote Padrão
Olá, sou o Incompetente.
Eu tenho um armazenamento online que criei e uso pessoalmente:
GitHub - haturatu/puremania: No security, very fast, web UI self-hosted online storage
No entanto, se eu quisesse adicionar autenticação na frente, então tentei criar um proxy de autenticação:
GitHub - haturatu/auth-proxy: An authentication proxy server and frontend for a website without built-in authentication. JavaScript is supported, but it can also work without JS if using PHP-FPM. The backend is written in Go.
Na verdade, é quase tudo graças ao Gemini-kun...
Ele faz proxy apenas para o que passa na autenticação.
O usuário Admin pode emitir um token Bearer para o endpoint da API e usar esse token para que as requisições passem. No entanto, neste caso, existem endpoints de API que também precisam ser acessíveis a partir de sessões de frontend, então, na prática, tanto cookies quanto tokens Bearer se tornam válidos.
Se você quiser proteger apenas os endpoints da API, isolando o frontend, como o login da web, em uma rede privada e expondo apenas os endpoints da API, a criação de usuários pode ser feita a partir da rede privada, e a emissão de tokens de API e o proxy de API são praticamente possíveis usando esses usuários. (Por favor, não diga 'por que não usar um OSS de API Gateway?')
Na prática, isso tornaria possível um ataque de força bruta dupla com cookies e tokens, mas, bem...
Então, sobre a segurança do formulário para a segurança do frontend web durante o login.
Se o carregamento de JS fosse obrigatório, a maioria dos problemas poderia ser resolvida, mas não é chato depender apenas de JS? Então, decidi aumentar a segurança do formulário com métodos que não dependem de JS.
Token CSRF / XSRF
Este é o foco principal desta vez, mas o que é isso, para começar?
Simplificando, é um mecanismo que verifica se a requisição do lado do servidor e do lado do cliente foi acessada e emitida corretamente do meu lado, e se o token está dentro do período de validade, então é permitido.
Por exemplo,
<input type="hidden" name="xsrf_token" value="BeftikzaR8Oe6npnqXYC7WtBhuo:1760376550660">
Um token como este é incorporado no lado do HTML do frontend. Este value é assinado pela chave secreta do servidor. Assim, o servidor sabe que foi emitido pelo meu lado do servidor!1760376550660 é apenas uma sequência de caracteres em tempo UNIX, mas para que é necessário o tempo atual?
xsrftoken package - golang.org/x/net/xsrftoken - Go Packages
func ValidFor(token, key, userID, actionID string, timeout time.Duration) bool
É usado para a configuração de validade acima.
Na prática, com o pacote time incluído, fica assim:
if !xsrftoken.ValidFor(clientToken, string(xsrfSecret), sessionID, r.URL.Path, 15*time.Minute) {
O padrão se este argumento não for fornecido é de 24 horas, o que é bastante flexível, mas, nesse caso, acredito que a forma como o XSRF Token deveria ser fornecido é apenas para realizar a verificação de que o token foi emitido pelo servidor.
Qual é a diferença entre CSRF e XSRF?!
Na verdade, não parece haver muita diferença.
O objetivo é prevenir ataques cross-site.
No caso de CSRF
GitHub - gorilla/csrf: Package gorilla/csrf provides Cross Site Request Forgery (CSRF) prevention middleware for Go web applications & services 🔒
Havia esta biblioteca, e por acaso encontrei isto aqui.
Demonstração de vulnerabilidade CSRF do gorilla/csrf
Uma maneira de melhorar a implementação do gorilla/csrf é substituir o valor aleatório usado nos formulários por um token criptografado vinculado ao ID do usuário. Isso impede que um atacante substitua seu próprio token CSRF e valor de cookie pelos da vítima. Isso ocorre porque o token CSRF do atacante corresponderia a um ID diferente. Na verdade, este método é implementado em uma biblioteca que usa x/net/xsrftokenHMAC para autenticar o ID do usuário, uma ação de formulário opcional e um tempo de expiração.
Então, pensando que existe na biblioteca padrão,
xsrftoken/xsrf.go
fiquei surpreso ao ver o código-fonte: apenas 100 linhas, incluindo comentários! Estou um pouco preocupado que ainda use SHA1, mas talvez seja atualizado em algum momento.
Bem, se a biblioteca padrão é tão simples, então isso é suficiente para o que se pretende, e se você for realizar a validação de SameSite, talvez deva usar gorilla/csrf.
Pontos de Atenção da Biblioteca Padrão
Como mencionei anteriormente, a validade padrão do token é de 24H.
Em uma operação real, há uma possibilidade de abuso com este prazo de token, então pode ser melhor torná-lo mais curto. Assumindo que este token é para enviar uma requisição até o preenchimento do formulário, 24H permitiria que a mesma requisição passasse várias vezes se nenhuma outra medida de segurança fosse implementada com o mesmo token, então não é impossível realizar um ataque de força bruta enviando requisições ao formulário repetidamente com o mesmo token usando curl infinitamente.