Endurecimento de segurança de API em 2026: guia de implementação OWASP Top 10
APIs são a superfície de ataque de 2026. Implementar o OWASP API Security Top 10 não é mais opcional—é higiene de negócio.
Resumo executivo
APIs são a superfície de ataque de 2026. Implementar o OWASP API Security Top 10 não é mais opcional—é higiene de negócio.
Ultima atualizacao: 20/03/2026
Resumo executivo
Em 2026, APIs representam a maior superfície de ataque para a maioria das organizações. À medida que aplicações se decompõem em microsserviços, adotam arquiteturas event-driven e expõem funcionalidade através de APIs, o perímetro de segurança tradicional se dissolveu. Segurança de API não é mais um complemento—é um requisito fundamental para sistemas de produção.
O OWASP API Security Top 10 fornece um framework para proteger APIs contra as vulnerabilidades mais críticas. Este guia traduz esses riscos em padrões de implementação acionáveis, exemplos de código e práticas operacionais para APIs de produção.
API1:2023 – Quebra de autorização em nível de objeto
A vulnerabilidade
APIs tendem a expor endpoints que manipulam identificadores de objeto (UUIDs, IDs auto-incrementais). Sem verificações de autorização adequadas, atacantes podem manipular esses identificadores para acessar recursos pertencentes a outros usuários.
Padrão de implementação
typescript// RUIM: Sem verificação de autorização
app.get('/api/users/:id', async (req, res) => {
const user = await db.users.findById(req.params.id);
res.json(user);
});
// BOM: Verificação de autorização explícita
app.get('/api/users/:id', async (req, res) => {
const requestingUserId = req.user.id; // Do JWT/sessão
const requestedUserId = req.params.id;
// Verificação de autorização: usuários só podem acessar seus próprios dados
if (requestingUserId !== requestedUserId) {
return res.status(403).json({
error: 'Forbidden',
message: 'Você não tem permissão para acessar este recurso'
});
}
const user = await db.users.findById(requestedUserId);
res.json(user);
});
// MELHOR: Abstração de autorização
interface AuthorizationPolicy {
canAccess(userId: string, resource: any): boolean;
}
class OwnResourceOnlyPolicy implements AuthorizationPolicy {
canAccess(userId: string, resource: any): boolean {
return resource.userId === userId;
}
}
class AdminOrOwnResourcePolicy implements AuthorizationPolicy {
canAccess(userId: string, resource: any): boolean {
const user = resource;
return user.isAdmin || user.userId === userId;
}
}
// Uso com middleware
function authorizeResource(policy: AuthorizationPolicy) {
return async (req: Request, res: Response, next: NextFunction) => {
const userId = req.user.id;
const resource = await getResourceFromRequest(req);
if (!policy.canAccess(userId, resource)) {
return res.status(403).json({
error: 'Forbidden',
message: 'Você não tem permissão para acessar este recurso'
});
}
req.resource = resource;
next();
};
}
app.get('/api/users/:id',
authenticate,
authorizeResource(new OwnResourceOnlyPolicy()),
(req, res) => {
res.json(req.resource);
}
);Melhores práticas para prevenir BOLA
| Prática | Implementação |
|---|---|
| Usar UUIDs em vez de IDs sequenciais | Previne ataques de enumeração |
| Implementar verificações de controle de acesso | Verificar cada requisição contra permissões |
| Escopar tokens de API | Limitar tokens a recursos/operações específicas |
| Auditar padrões de acesso | Monitorar padrões de acesso incomuns |
API2:2023 – Quebra de autenticação
A vulnerabilidade
Mecanismos de autenticação frequentemente têm falhas de implementação que permitem que atacantes comprometam tokens de autenticação, senhas ou identificadores de sessão.
Padrão de implementação
typescript// Autenticação baseada em JWT com melhores práticas de segurança
import jwt from 'jsonwebtoken';
import bcrypt from 'bcrypt';
import crypto from 'crypto';
interface AuthConfig {
jwtSecret: string;
jwtExpiresIn: string;
refreshTokenExpiresIn: number; // dias
bcryptRounds: number;
maxFailedAttempts: number;
lockoutDuration: number; // minutos
}
class AuthenticationService {
private failedAttempts: Map<string, { count: number; lockUntil: Date }> = new Map();
constructor(private config: AuthConfig) {}
async hashPassword(password: string): Promise<string> {
return bcrypt.hash(password, this.config.bcryptRounds);
}
async verifyPassword(password: string, hash: string): Promise<boolean> {
// Verificar se conta está bloqueada
const attempt = this.failedAttempts.get(password);
if (attempt && attempt.lockUntil > new Date()) {
throw new Error('Conta temporariamente bloqueada');
}
const isValid = await bcrypt.compare(password, hash);
if (!isValid) {
await this.recordFailedAttempt(password);
throw new Error('Credenciais inválidas');
}
// Resetar tentativas falhadas no login bem-sucedido
this.failedAttempts.delete(password);
return true;
}
private async recordFailedAttempt(identifier: string): Promise<void> {
const attempt = this.failedAttempts.get(identifier) || { count: 0, lockUntil: new Date(0) };
attempt.count++;
if (attempt.count >= this.config.maxFailedAttempts) {
attempt.lockUntil = new Date(Date.now() + this.config.lockoutDuration * 60 * 1000);
}
this.failedAttempts.set(identifier, attempt);
}
generateTokens(userId: string, userRole: string): { accessToken: string; refreshToken: string } {
const accessToken = jwt.sign(
{ userId, role: userRole },
this.config.jwtSecret,
{ expiresIn: this.config.jwtExpiresIn }
);
const refreshToken = crypto.randomBytes(32).toString('hex');
return { accessToken, refreshToken };
}
verifyAccessToken(token: string): any {
try {
return jwt.verify(token, this.config.jwtSecret);
} catch (error) {
throw new Error('Token inválido ou expirado');
}
}
}
// Rotação de refresh token
class RefreshTokenService {
private tokens = new Map<string, { userId: string; expires: Date; previousToken?: string }>();
async createRefreshToken(userId: string): Promise<string> {
const token = crypto.randomBytes(32).toString('hex');
const expires = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000); // 7 dias
this.tokens.set(token, { userId, expires });
return token;
}
async rotateRefreshToken(oldToken: string): Promise<string> {
const tokenData = this.tokens.get(oldToken);
if (!tokenData || tokenData.expires < new Date()) {
throw new Error('Refresh token inválido ou expirado');
}
// Invalidar token antigo
this.tokens.delete(oldToken);
// Criar novo token
return this.createRefreshToken(tokenData.userId);
}
async revokeToken(token: string): Promise<void> {
this.tokens.delete(token);
}
}Melhores práticas para prevenir Broken Authentication
| Prática | Implementação |
|---|---|
| Implementar rate limiting em endpoints de autenticação | Prevenir ataques de força bruta |
| Usar hashing de senha seguro | bcrypt com fator de trabalho apropriado |
| Implementar bloqueio de conta | Bloqueio temporário após tentativas falhadas |
| Rotacionar refresh tokens | Tokens de refresh de uso único |
| Implementar revogação de token | Capacidade de revogar tokens comprometidos |
API3:2023 – Quebra de autorização em nível de propriedade de objeto
A vulnerabilidade
APIs que incluem automaticamente todas as propriedades de objeto em respostas podem vazar dados sensíveis ou permitir modificações não autorizadas.
Padrão de implementação
typescript// Padrão DTO (Data Transfer Object) para filtragem de resposta
interface UserDTO {
id: string;
email: string;
name: string;
createdAt: Date;
}
interface SensitiveUserDTO extends UserDTO {
phoneNumber: string;
address: string;
lastLogin: Date;
}
class UserResponseFactory {
toPublicDTO(user: User): UserDTO {
return {
id: user.id,
email: user.email,
name: user.name,
createdAt: user.createdAt
};
}
toSensitiveDTO(user: User, requester: User): SensitiveUserDTO | UserDTO {
// Incluir campos sensíveis apenas para administradores ou o próprio usuário
if (requester.isAdmin || requester.id === user.id) {
return {
...this.toPublicDTO(user),
phoneNumber: user.phoneNumber,
address: user.address,
lastLogin: user.lastLogin
};
}
return this.toPublicDTO(user);
}
}API4:2023 – Consumo de recursos irrestrito
A vulnerabilidade
APIs que não limitam o consumo de recursos (requisições, tamanho de dados, computação) são vulneráveis a ataques DoS e exploração de custos.
Padrão de implementação
typescript// Implementação de rate limiting
import rateLimit from 'express-rate-limit';
import RedisStore from 'rate-limit-redis';
// Configuração de rate limiter
interface RateLimitConfig {
windowMs: number;
maxRequests: number;
keyPrefix: string;
}
function createRateLimiter(config: RateLimitConfig, redis?: any) {
const store = redis ? new RedisStore({
client: redis,
prefix: config.keyPrefix
}) : undefined;
return rateLimit({
store,
windowMs: config.windowMs,
max: config.maxRequests,
standardHeaders: true,
legacyHeaders: false,
handler: (req, res) => {
res.status(429).json({
error: 'Too Many Requests',
message: 'Limite de taxa excedido',
retryAfter: Math.ceil(config.windowMs / 1000)
});
}
});
}
// Diferentes limites de taxa para diferentes endpoints
const apiLimiter = createRateLimiter({
windowMs: 60 * 1000, // 1 minuto
maxRequests: 100,
keyPrefix: 'api_limit'
});
const authLimiter = createRateLimiter({
windowMs: 15 * 60 * 1000, // 15 minutos
maxRequests: 5,
keyPrefix: 'auth_limit'
});
// Aplicar rate limiters
app.use('/api/', apiLimiter);
app.use('/api/auth/', authLimiter);
// Limitação de tamanho de requisição
app.use(express.json({
limit: '1mb' // Limitar tamanho do corpo da requisição
}));API5:2023 – Quebra de autorização em nível de função
A vulnerabilidade
APIs que escondem funções administrativas atrás de obscuridade em vez de autorização adequada permitem que atacantes acessem funcionalidades privilegiadas.
Padrão de implementação
typescript// Controle de acesso baseado em função (RBAC)
enum Role {
USER = 'user',
MODERATOR = 'moderator',
ADMIN = 'admin'
}
interface Permission {
resource: string;
action: string;
}
interface RolePermissions {
role: Role;
permissions: Permission[];
}
class AuthorizationService {
private rolePermissions: Map<Role, Permission[]> = new Map();
constructor() {
this.initializePermissions();
}
private initializePermissions(): void {
this.rolePermissions.set(Role.USER, [
{ resource: 'users', action: 'read' },
{ resource: 'posts', action: 'create' },
{ resource: 'posts', action: 'read' }
]);
this.rolePermissions.set(Role.ADMIN, [
{ resource: 'users', action: 'read' },
{ resource: 'users', action: 'update' },
{ resource: 'users', action: 'delete' },
{ resource: 'settings', action: 'update' }
]);
}
hasPermission(role: Role, resource: string, action: string): boolean {
const permissions = this.rolePermissions.get(role);
if (!permissions) {
return false;
}
return permissions.some(
permission => permission.resource === resource && permission.action === action
);
}
}
// Middleware de autorização
function requirePermission(authService: AuthorizationService, resource: string, action: string) {
return (req: Request, res: Response, next: NextFunction) => {
const userRole = req.user.role as Role;
if (!authService.hasPermission(userRole, resource, action)) {
return res.status(403).json({
error: 'Forbidden',
message: 'Você não tem permissão para realizar esta ação'
});
}
next();
};
}Monitoramento e resposta a incidentes
Implementação de monitoramento de segurança
typescriptclass SecurityEventLogger {
async logSecurityEvent(event: {
type: string;
severity: 'low' | 'medium' | 'high' | 'critical';
userId?: string;
ipAddress: string;
details: any;
}): Promise<void> {
// Registrar em sistema de monitoramento de segurança
await fetch(`${process.env.SECURITY_MONITORING_URL}/events`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
...event,
timestamp: new Date().toISOString(),
environment: process.env.NODE_ENV
})
});
// Para eventos críticos, também alertar imediatamente
if (event.severity === 'critical') {
await this.alertTeam(event);
}
}
private async alertTeam(event: any): Promise<void> {
// Enviar para PagerDuty, Slack, etc.
await fetch(`${process.env.ALERT_WEBHOOK_URL}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: `EVENTO CRÍTICO DE SEGURANÇA: ${event.type}`,
details: event.details
})
});
}
}
// Uso no fluxo de autenticação
const securityLogger = new SecurityEventLogger();
app.post('/api/auth/login',
authLimiter,
async (req, res) => {
try {
const { email, password } = req.body;
const user = await authService.authenticate(email, password);
res.json({ token: user.token });
} catch (error) {
await securityLogger.logSecurityEvent({
type: 'AUTHENTICATION_FAILURE',
severity: 'medium',
ipAddress: req.ip,
details: {
email: req.body.email,
userAgent: req.headers['user-agent']
}
});
res.status(401).json({
error: 'Falha na autenticação'
});
}
}
);Conclusão
Segurança de API em 2026 requer defesa em profundidade: múltiplas camadas de proteção que abordam o OWASP API Security Top 10 de forma abrangente. Os padrões neste guia fornecem uma fundação, mas segurança é um processo contínuo de monitoramento, atualização e melhoria baseado em ameaças emergentes.
Pergunta estratégica para sua equipe: Qual é seu nível de maturidade em segurança de API, e qual é a lacuna entre seu estado atual e práticas de segurança prontas para produção?
Precisa endurecer sua postura de segurança de API e implementar proteções OWASP Top 10? Fale com a Imperialis sobre avaliação de segurança de API, implementação e operações de segurança contínuas.
Fontes
- OWASP API Security Top 10 — Projeto oficial OWASP API Security
- OWASP API Security Top 10 Explicado — Explicações e exemplos detalhados
- Diretrizes de Segurança de API da NIST — Diretrizes da NIST sobre segurança de API