Intermediário Aplicação e Código

Code review focado em segurança — o que procurar, checklists, pull request

SAST e DAST automatizam parte da análise, mas não substituem revisão humana. Um revisor experiente percebe falhas de lógica de negócio que nenhuma ferramenta detecta: verificações de autorização incorretas, fluxos de estado exploráveis, decisões arquiteturais inseguras.

Mentalidade do Revisor de Segurança

Ao revisar código, pergunte-se:

  • De onde vêm esses dados? Quem controla essa entrada?
  • O que acontece se esse valor for inesperado (null, vazio, muito grande, malformado)?
  • Quem tem permissão para executar essa ação? Está sendo verificado?
  • O que este código expõe — dados, erros, estado interno?
  • Existe algum segredo ou credencial visível?

O Que Procurar por Categoria

Autenticação e Autorização

# Ruim — verifica apenas autenticação, não autorização
@app.route("/api/orders/<order_id>")
@login_required
def get_order(order_id):
    return Order.get(order_id)  # qualquer usuário logado vê pedido alheio

# Bom — verifica se o recurso pertence ao usuário atual
@app.route("/api/orders/<order_id>")
@login_required
def get_order(order_id):
    order = Order.get(order_id)
    if order.user_id != current_user.id:
        abort(403)
    return order.to_dict()

Injeção (SQL, Shell, LDAP)

# Ruim — interpolação de string em query
cursor.execute(f"SELECT * FROM users WHERE email = '{email}'")

# Ruim — shell injection
os.system(f"convert {filename} output.pdf")

# Bom — parametrizado
cursor.execute("SELECT * FROM users WHERE email = %s", (email,))

# Bom — lista de argumentos, sem shell
subprocess.run(["convert", filename, "output.pdf"], check=True)

Gerenciamento de Sessão e Tokens

  • Tokens JWT verificam assinatura antes de usar payload?
  • Sessão é invalidada no logout?
  • Cookies têm flags HttpOnly, Secure, SameSite?
  • Tokens de reset de senha expiram?

Criptografia

  • MD5 e SHA1 são usados para hashing de senha? (errado — use bcrypt/argon2)
  • Chaves criptográficas estão hardcoded?
  • TLS está configurado corretamente (sem versões antigas, sem cipher suites fracas)?

Upload de Arquivos

# Ruim — aceita qualquer extensão
filename = request.files["file"].filename
file.save(f"/uploads/{filename}")

# Bom — whitelist de extensões + nome gerado pelo servidor
ALLOWED = {".jpg", ".png", ".pdf"}
ext = Path(filename).suffix.lower()
if ext not in ALLOWED:
    abort(400)
safe_name = str(uuid.uuid4()) + ext
file.save(f"/uploads/{safe_name}")

Checklist para PR de Segurança

Entrada de Dados

  • Todo input externo é validado antes do uso
  • Não há concatenação de input em queries, comandos ou templates
  • Uploads validam tipo real (magic bytes), não só extensão

Controle de Acesso

  • Toda rota protegida verifica autenticação E autorização
  • Referências a recursos verificam propriedade (IDOR prevention)
  • Funções administrativas têm verificação de papel (role)

Dados Sensíveis

  • Nenhum segredo ou credencial no diff
  • PII não aparece em logs
  • Dados sensíveis em trânsito usam TLS

Tratamento de Erros

  • Exceções capturadas e logadas — sem stack trace para o cliente
  • Comportamento de falha nega acesso por padrão

Dependências

  • Nenhuma dependência nova com CVE conhecido
  • Lock file atualizado

Como Dar Feedback no Pull Request

Seja específico e objetivo:

# Ruim
"Esse código tem problema de segurança."

# Bom
"Linha 47: a query usa interpolação de string com `user_id`.
Se `user_id` vier da query string sem validação (linha 12),
isso abre SQL Injection. Use prepared statement:
  cursor.execute('SELECT * FROM orders WHERE user_id = %s', (user_id,))
Ref: OWASP SQL Injection Prevention."

Aponte: a linha, o risco concreto, e a solução. Sem julgamento de pessoa — foco no código.

Ferramentas de Apoio à Revisão

  • Semgrep — rode localmente no diff antes de abrir o PR.
  • CodeClimate / SonarCloud — análise automática integrada ao GitHub.
  • GitHub Code Scanning — executa SARIF findings diretamente no PR.

Code review de segurança não é auditoria formal. É a última linha de defesa humana antes do merge. Faça parte da cultura do time, não exceção.