Entendendo Cross-Site Request Forgery (CSRF ou XSRF).

Privacidade e Segurança

Entendendo Cross-Site Request Forgery (CSRF ou XSRF)

Os passos que você precisa seguir para aumentar a segurança de seus servidores web.

Introdução

Conversa utilizando latas e barbante.
Conversa utilizando latas e barbante.
Conversa utilizando latas e barbante. Imagem: Wannapik.

Como o CSRF funciona

Diagrama exibindo o fluxo de informações em um ataque CSRF.
Diagrama exibindo o fluxo de informações em um ataque CSRF.
Imagem: Souza, 2009.

Exemplo #1: método HTTP POST

<html>
<body>
<form id="evil-form" action="http://my.trustful.bank/transfer?amount=123&account=stevie" method="POST">
<button type="submit">Click here</button>
</form>
</body>
</html>

Exemplo #2: Comportamento automático

<html>
<body onload="document.getElementById('evil-form').submit();">
<form id="evil-form" action="http://my.trustful.bank/transfer" method="POST">
<input type="hidden" name="account" value="stevie"></input>
<input type="hidden" name="amount" value="123"></input>
<button type="submit">Click here</button>
</form>
</body>
</html>

Exemplo #3: Sem web forms

<html>
<body>
<img src="http://my.trustful.bank/transfer?amount=123&to=stevie" />
</body>
</html>
Redirect 302 /a.jpg https://somebank.com/transferfunds.asp?amnt=1000000&acct=123456
GET /a.jpg HTTP/1.0
Host: ha.ckers.org
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3
Accept: image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Proxy-Connection: keep-alive
Referer: http://somebank.com/board.asp?id=692381
HTTP/1.1 302 Found
Date: Fri, 23 Mar 2007 18:22:07 GMT
Server: Apache
Location: https://somebank.com/transferfunds.asp?amnt=1000000&acct=123456
Content-Length: 251
Connection: close
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title></head><body>
<h1>Found</h1>
<p>The document has moved <a href="https://somebank.com/transferfunds.asp?amnt=1000000&amp;acct=123456">here</a>.</p>
</body></html>

Ataques CSRF e/ou XSS

Fragmento de um perfil na rede social MySpace, em 2005.
Fragmento de um perfil na rede social MySpace, em 2005.
Fragmento do perfil de Kamkar no MySpace, exibindo quantos amigos ele possuía após seu script, em 2005. Imagem: VICE.

Como prevenir ataques CSRF

1. Mantenha o navegador de internet atualizado

2. Verifique o HTTP Referrer header

3. Implemente o atributo SameSite

Set-Cookie: TOKEN=1bf3dea9fbe265e40d3f9595f2239103; Path=/; SameSite=lax

4. Adicione tokens randômicos

<html>
<body>
<form id="good-form" action="http://my.trustful.bank/transfer" method="POST">
<input type="hidden" name="token" value="1bf3dea9fbe265e40d3f9595f2239103"></input>
<input type="text" name="account" value="stevie"></input>
<input type="text" name="amount" value="123"></input>
<button type="submit">Submit</button>
</form>
</body>
</html>
<?php
$_SESSION['token'] = bin2hex(random_bytes(16)); // 1bf3dea9fbe265e40d3f9595f2239103
?>
var token = readCookie(TOKEN);                       // Obtém o HTTP Cookie que definimos previamente, identificado como "TOKEN"
httpRequest.setRequestHeader('X-CSRF-Token', token); // Então, o enviamos como uma informação de cabeçalho "X-CSRF-Token"

Próximos passos 🚶

Referências

Brasileiro. Desenvolvedor Full Stack. Escreve sobre Computação e Programação para iniciantes.

Brasileiro. Desenvolvedor Full Stack. Escreve sobre Computação e Programação para iniciantes.