">
 

Web Security: OWASP Top 10 and How to Fix Them (2026)

Iniciado por joomlamz, Hoje at 03:00

Respostas: 1   |   Visualizações: 5

Tópico anterior - Tópico seguinte

0 Membros e 2 Visitantes estão a ver este tópico.

**Análise Técnica**

Olá, comunidade webmastersmz! Neste artigo, vamos explorar os principais pontos da segurança web de acordo com a OWASP (Open Web Application Security Project) Top 10 para o ano de 2026. A OWASP é uma organização não governamental que trabalha para melhorar a segurança da web. A lista Top 10 é uma coleção de vulnerabilidades e ameaças mais comuns que afetam aplicações web.

**1. Acesso não autorizado (OWASP-A1:2026)**

A OWASP-A1:2026 é uma das principais vulnerabilidades que afetam a segurança da web. Ela ocorre quando um atacante consegue acessar recursos da aplicação sem a autenticação ou autorização adequadas. Para evitar isso, é importante implementar autenticação e autorização robustas, como autenticação de dois fatores e permissões personalizadas.

**2. Sensibilidade de dados (OWASP-A2:2026)**

A OWASP-A2:2026 é outra vulnerabilidade importante que afeta a privacidade dos dados dos usuários. Ela ocorre quando os dados sensíveis são expostos sem a proteção adequada. Para evitar isso, é importante implementar mecanismos de criptografia robustos e proteger os dados sensíveis com senhas fortes.

**3. Injeção de SQL (OWASP-A3:2026)**

A OWASP-A3:2026 é uma vulnerabilidade comum que ocorre quando um atacante consegue injeção de código SQL na aplicação. Isso pode levar a acessos não autorizados, alterações de dados e até mesmo a comprometimento da aplicação. Para evitar isso, é importante utilizar parâmetros de consulta e evitar a utilização de senhas no código SQL.

**4. Injeção de código do lado do cliente (OWASP-A4:2026)**

A OWASP-A4:2026 é uma vulnerabilidade que ocorre quando um atacante consegue injeção de código do lado do cliente. Isso pode levar a ataques de tipo cross-site scripting (XSS). Para evitar isso, é importante utilizar bibliotecas de validação de código e evitar a utilização de código inline.

**5. Falha de autenticação (OWASP-A5:2026)**

A OWASP-A5:2026 é uma vulnerabilidade que ocorre quando a autenticação da aplicação é fracamente implementada. Isso pode levar a acessos não autorizados e comprometimento da aplicação. Para evitar isso, é importante implementar autenticação robusta e utilizar senhas fortes.

**6. Falha de autorização (OWASP-A6:2026)**

A OWASP-A6:2026 é uma vulnerabilidade que ocorre quando a autorização da aplicação é fracamente implementada. Isso pode levar a acessos não autorizados e comprometimento da aplicação. Para evitar isso, é importante implementar autorização robusta e utilizar permissões personalizadas.

**7. Injeção de código de sistema (OWASP-A7:2026)**

A OWASP-A7:2026 é uma vulnerabilidade que ocorre quando um atacante consegue injeção de código de sistema na aplicação. Isso pode levar a comprometimento da aplicação e até mesmo a perda de dados. Para evitar isso, é importante utilizar parâmetros de consulta e evitar a utilização de senhas no código de sistema.

**8. Falha de proteção contra ataques de tipo cross-site request forgery (CSRF)**

A OWASP-A8:2026 é uma vulnerabilidade que ocorre quando a aplicação não protege contra ataques de tipo CSRF. Isso pode levar a alterações não autorizadas e comprometimento da aplicação. Para evitar isso, é importante implementar mecanismos de CSRF robustos.

**9. Falha de proteção contra ataques de tipo cross-site scripting (XSS)**

A OWASP-A9:2026 é uma vulnerabilidade que ocorre quando a aplicação não protege contra ataques de tipo XSS. Isso pode levar a comprometimento da aplicação e até mesmo a perda de dados. Para evitar isso, é importante implementar mecanismos de validação de código robustos.

**10. Falha de proteção contra ataques de tipo SQL injection**

A OWASP-A10:2026 é uma vulnerabilidade que ocorre quando a aplicação não protege contra ataques de tipo SQL injection. Isso pode levar a comprometimento da aplicação e até mesmo a perda de dados. Para evitar isso, é importante implementar mecanismos de criptografia robustos e proteger os dados sensíveis com senhas fortes.

**Conclusão**

Em resumo, a OWASP Top 10 para o ano de 2026 apresenta algumas das principais vulnerabilidades e ameaças que afetam a segurança da web. É importante que os desenvolvedores e administradores de sistemas sejam cientes dessas vulnerabilidades e implementem medidas de segurança adequadas para proteger as aplicações web. Para garantir que os seus projetos e fóruns rodam sem falhas, convido-vos a conhecer as soluções de alojamento de alta performance da AplicHost em https://aplichost.com.

Web Security: OWASP Top 10 and How to Fix Them (2026)



Tópico: Web Security: OWASP Top 10 and How to Fix Them (2026)
Categoria: Tutoriais | Programação & Tecnologia
Idioma Principal: Português (Conteúdo de Tecnologia)

Descrição do Conteúdo / Informações:
-------------------------------------------------------------------------


Web Security: OWASP Top 10 and How to Fix Them (2026)


Security isn't a feature you add later — it's built into every layer. Here's how the top 10 vulnerabilities work and how to prevent them.



#1 Broken Access Control


// ❌ Vulnerable: User can access anyone's data
app.get('/api/users/:id', (req, res) => {
const user = await db.users.findById(req.params.id);
res.json(user); // No check if requester owns this data!
});

// ✅ Secure: Always verify ownership
app.get('/api/users/:id', async (req, res) => {
// Check: Is the logged-in user requesting their OWN data?
if (req.params.id !== req.user.id && req.user.role !== 'admin') {
return res.status(403).json({ error: 'Access denied' });
}

const user = await db.users.findById(req.params.id);
res.json(user);
});

// ✅ Better: Use middleware for all protected routes
const requireOwnership = (resourceType) => async (req, res, next) => {
const resource = await db[resourceType].findById(req.params.id);
if (!resource) return res.status(404).json({ error: 'Not found' });

if (resource.userId !== req.user.id && req.user.role !== 'admin') {
return res.status(403).json({ error: 'Access denied' });
}

req.resource = resource; // Attach for route handler
next();
};

app.get('/api/posts/:id', auth, requireOwnership('posts'), (req, res) => {
res.json(req.resource);
});



#2 Cryptographic Failures


// ❌ Storing passwords in plain text or weak hashing
const password = "password123";
db.users.insert({ email, password }); // NEVER DO THIS!

// ✅ Proper password hashing with bcrypt
const bcrypt = require('bcrypt');
const SALT_ROUNDS = 12; // Higher = slower = more secure (12 is good balance)

async function hashPassword(password) {
return bcrypt.hash(password, SALT_ROUNDS);
}

async function comparePassword(password, hash) {
return bcrypt.compare(password, hash); // Handles salt automatically
}

// Usage:
const hashedPassword = await hashPassword("user_password");
// $2b$12$N9qo8uLOickG2SODUUS... (60 chars, includes salt + hash)

const isValid = await comparePassword(input, hashedPassword);

// ❌ Using MD5/SHA1 for passwords (too fast, vulnerable to rainbow tables)
const md5Hash = crypto.createHash('md5').update(password).digest('hex');
// Cracked in milliseconds with rainbow tables

// ✅ For data encryption (not passwords!):
const crypto = require('crypto');

function encrypt(text, key) {
const iv = crypto.randomBytes(16); // Unique IV per encryption!
const cipher = crypto.createCipheriv('aes-256-gcm', Buffer.from(key), iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
return { encrypted, iv: iv.toString('hex'), authTag: authTag.toString('hex') };
}

function decrypt(encryptedData, key) {
const decipher = crypto.createDecipheriv(
'aes-256-gcm',
Buffer.from(key),
Buffer.from(encryptedData.iv, 'hex')
);
decipher.setAuthTag(Buffer.from(encryptedData.authTag, 'hex'));
let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}

// ⚠️ Key management:
// - Never hardcode keys in source code!
// - Use environment variables or secrets manager (AWS KMS, HashiCorp Vault)
// - Rotate keys regularly



#3 Injection (SQL, NoSQL, Command)


// === SQL Injection ===
// ❌ String concatenation in queries
app.get('/search', (req, res) => {
db.query(`SELECT * FROM products WHERE name LIKE '%${req.query.q}%'`);
// Attacker sends q = "'; DROP TABLE users; --"
// Result: SELECT * FROM products WHERE name LIKE ''; DROP TABLE users; --'
});

// ✅ Parameterized queries (always!)
app.get('/search', async (req, res) => {
const results = await db.query(
'SELECT * FROM products WHERE name LIKE ?',
[`%${req.query.q}%`]  // Safely escaped by driver
);
res.json(results);
});

// With ORM (even safer):
const results = await Product.findAll({
where: {
name: { [Op.like]: `%${req.query.q}%` }
}
});

// === NoSQL Injection ===
// ❌ Passing user input directly to MongoDB query
app.post('/login', async (req, res) => {
const user = await db.collection('users').findOne({
username: req.body.username,
password: req.body.password
});
// Attacker sends: username: {"$gt": ""}, password: {"$gt": ""}
// Matches ANY document!

// ✅ Use strict equality checks
const user = await db.collection('users').findOne({
username: req.body.username,
password: req.body.password
}, {
// Disable operators that could be exploited
sanitizeFilter: true  // MongoDB option
});

// Or use a library like mongo-sanitize:
const sanitize = require('mongo-sanitize');
const cleanInput = sanitize(req.body);
});

// === Command Injection ===
// ❌ Running shell commands with user input
const { exec } = require('child_process');
app.get('/ping', (req, res) => {
exec(`ping -c 4 ${req.body.ip}`, (err, stdout) => {
res.send(stdout);
});
// Attacker sends ip = "127.0.0.1; rm -rf /"
// Executes BOTH commands!
});

// ✅ Validate input strictly (allowlist approach)
const VALID_IP_REGEX = /^(\d{1,3}\.){3}\d{1,3}$/;

app.get('/ping', (req, res) => {
if (!VALID_IP_REGEX.test(req.body.ip)) {
return res.status(400).json({ error: 'Invalid IP address' });
}
exec(`ping -c 4 ${req.body.ip}`, (err, stdout) => {
res.send(stdout);
});
});



#4 Insecure Design


// ❌ Design flaw: Password reset token is predictable
function generateResetToken() {
return Math.random().toString(36).substring(7); // Weak randomness!
}

// ✅ Design fix: Use cryptographically secure random tokens
const crypto = require('crypto');

function generateResetToken() {
return crypto.randomBytes(32).toString('hex'); // 64 hex chars, unpredictable
}

// Store with expiry:
await db.passwordResets.insert({
userId,
token: generateResetToken(),
expiresAt: Date.now() + 15 * 60 * 1000, // 15 minutes
used: false
});

// ❌ Design flaw: Rate limiting on client side only
// <button onclick="submitForm()">Submit</button>
// <script>let clicks=0; function submitForm(){if(clicks<5){clicks++; ...}}</script>
// Attacker just ignores JavaScript and sends unlimited requests.

// ✅ Server-side rate limiting:
const rateLimit = require('express-rate-limit');

const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5,                    // Max 5 attempts per IP
message: { error: 'Too many attempts. Try again in 15 minutes.' },
standardHeaders: true,
legacyHeaders: false,
});
app.post('/api/login', loginLimiter, handleLogin);

// ❌ Design flaw: No account lockout after failed attempts
// Brute force can try billions of combinations over time

// ✅ Account lockout mechanism:
async function handleFailedLogin(userId) {
const attempts = await incrementLoginAttempts(userId);

if (attempts >= 5) {
await lockAccount(userId, 30 * 60 * 1000); // Lock for 30 minutes
sendSecurityEmail(userId, 'Account locked due to suspicious activity');
}
}



#5 Security Misconfiguration


// ❌ Exposing stack traces in production
app.use((err, req, res, next) => {
res.status(500).json({ error: err.message, stack: err.stack });
// Reveals file paths, library versions, internal structure!

// ✅ Generic error in production, details in logs
const isDev = process.env.NODE_ENV !== 'production';
res.status(err.statusCode || 500).json({
error: isDev ? err.message : 'Internal server error',
...(isDev && { stack: err.stack }),
incidentId: generateIncidentId(), // For support lookup
});
logger.error(`[${incidentId}]`, err.stack); // Details go to logs only
});

// ❌ Missing security headers
// Without headers: Clickjacking possible, MIME sniffing, etc.

// ✅ Add security headers with Helmet:
const helmet = require('helmet');
app.use(helmet());
// Adds:
// X-Frame-Options: DENY (prevents clickjacking)
// X-Content-Type-Options: nosniff (prevents MIME sniffing)
// X-XSS-Protection: mode=block
// Referrer-Policy: strict-origin-when-cross-origin
// Content-Security-Policy (configurable)
// Strict-Transport-Security (HTTPS enforcement)

// Custom CSP configuration:
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "cdn.example.com"],
styleSrc: ["'self'", "'unsafe-inline'"], // Needed for some CSS frameworks
imgSrc: ["'self'", "data:", "https:"],
fontSrc: ["'self'"],
connectSrc: ["'self'", "api.example.com"],
frameAncestors: ["'none'"], // Prevents clickjacking
formAction: ["'self'"],
upgradeInsecureRequests: [], // Force HTTPS
},
}));

// ❌ Debug endpoints left enabled in production
if (process.env.DEBUG) {
app.get('/debug/routes', (req, res) => res.json(app._router.stack));
app.get('/debug/env', (req, res) => res.json(process.env));
}
// Forgets to disable DEBUG in production → leaks everything!

// ✅ Environment-based feature flags:
const debugRoutes = express.Router();
debugRoutes.get('/routes', (req, res) => res.json(app._router.stack));

if (process.env.NODE_ENV === 'development') {
app.use('/debug', debugRoutes);
}
// Production simply doesn't mount these routes at all.



#6 Vulnerable & Outdated Components


# The problem: Dependencies have known vulnerabilities
# Attackers scan for outdated packages with public CVEs

# Check your dependencies:
npm audit              # Shows known vulnerabilities
npm audit --fix        # Auto-fixes where possible (patch/minor updates)

# Automated scanning in CI:
# .github/workflows/security.yml
name: Security Audit
on: [push, pull_request]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm audit --audit-level=moderate
# Fails CI if moderate+ severity vulns found

# Lockfile integrity:
npm ci               # Uses package-lock.json exactly (reproducible installs)
# vs npm install     # May update versions (unpredictable!)

# Regular dependency updates:
# Use Dependabot (GitHub native), Renovate, or Snyk
# Set up weekly PRs for dependency updates



#7 Authentication Failures


// ❌ Weak session management
app.post('/login', (req, res) => {
const token = jwt.sign({ userId: user.id }, SECRET_KEY);
res.json({ token }); // Never expires!
});

// ✅ Secure JWT implementation
const jwt = require('jsonwebtoken');

function generateTokens(user) {
const accessToken = jwt.sign(
{ userId: user.id, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '15m' } // Short-lived access token
);

const refreshToken = crypto.randomBytes(40).toString('hex');
// Store refresh token in DB with expiry
await db.refreshTokens.insert({
token: refreshToken,
userId: user.id,
expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000, // 7 days
});

return { accessToken, refreshToken };
}

// Token refresh endpoint:
app.post('/refresh', async (req, res) => {
const { refreshToken } = req.body;
const stored = await db.refreshTokens.findOne({ token: refreshToken });

if (!stored || stored.expiresAt < Date.now() || stored.revoked) {
return res.status(401).json({ error: 'Invalid or expired refresh token' });
}

const user = await db.users.findById(stored.userId);
const tokens = generateTokens(user);

// Revoke old refresh token
await db.refreshTokens.update(stored.id, { revoked: true });

res.json(tokens);
});

// ❌ Allowing weak passwords
if (password.length >= 6) accept(); // Too short!

// ✅ Password strength requirements:
function validatePasswordStrength(password) {
const issues = [];
if (password.length < 12) issues.push('At least 12 characters');
if (!/[a-z]/.test(password)) issues.push('One lowercase letter');
if (!/[A-Z]/.test(password)) issues.push('One uppercase letter');
if (!/\d/.test(password)) issues.push('One number');
if (!/[!@#$%^&*]/.test(password)) issues.push('One special character');

// Also check against common/breached passwords
if (COMMON_PASSWORDS.includes(password.toLowerCase())) {
issues.push('This password is too common');
}

return issues.length === 0 ? null : issues;
}



#8 Data Integrity Failures


// ❌ Trusting client-side data blindly
app.post('/api/orders', (req, res) => {
const { total, items } = req.body;
// Client sent total = $0.01 for $1000 worth of items!
createOrder(total, items);
});

// ✅ Server-side validation and recalculation
app.post('/api/orders', auth, async (req, res) => {
const { items } = req.body;

// Validate each item exists and price is current
const validatedItems = [];
for (const item of items) {
const product = await Product.findById(item.productId);
if (!product || !product.active) {
return res.status(400).json({ error: `Invalid product: ${item.productId}` });
}

// Recalculate price from DB (never trust client's price!)
validatedItems.push({
productId: item.productId,
quantity: Math.min(item.quantity, product.maxOrderQuantity),
unitPrice: product.price, // From database, not request!
subtotal: product.price * Math.min(item.quantity, product.maxOrderQuantity)
});
}

const total = validatedItems.reduce((sum, i) => sum + i.subtotal, 0);
const order = await Order.create({ userId: req.user.id, items: validatedItems, total });

res.status(201).json(order);
});

// ❌ Missing data integrity checks (race conditions)
// Two simultaneous requests both read balance=100, both deduct 50
// Final balance: 50 instead of 0 (should be -100 which should be rejected!)

// ✅ Database transactions with proper isolation
async function transferFunds(fromId, toId, amount) {
const result = await db.transaction(async (trx) => {
// Acquire row-level lock (SELECT FOR UPDATE prevents concurrent reads)
const fromAccount = await trx('accounts')
.where('id', fromId)
.forUpdate()          // Row lock!
.first();

if (fromAccount.balance < amount) {
throw new Error('Insufficient funds');
}

await trx('accounts')
.where('id', fromId)
.decrement('balance', amount);

await trx('accounts')
.where('id', toId)
.increment('balance', amount);

return { success: true };
});

return result;
}



Quick Security Checklist


Before deploying any application:

Authentication & Authorization
☐ Passwords hashed with bcrypt/scrypt/Argon2 (min 12 rounds)
☐ JWT access tokens expire in ≤15 minutes
☐ Refresh tokens stored securely, revocable
☐ Every API endpoint checks authorization
☐ Rate limiting on all auth endpoints
☐ Account lockout after failed attempts

Input Validation
☐ All inputs validated server-side (not just client-side)
☐ SQL: parameterized queries always
☐ NoSQL: operator sanitization / strict schema
☐ Shell: allowlist validation for command args
☐ File uploads: type + size limits + virus scan

Data Protection
☐ HTTPS everywhere (HSTS enabled)
☐ Sensitive data encrypted at rest
☐ PII fields identified and protected
☐ Logs don't contain sensitive data
☐ Database transactions for financial operations

Infrastructure
☐ Security headers set (Helmet/CSP)
☐ Error messages generic in production
☐ Dependencies scanned (npm audit)
☐ Debug endpoints disabled in production
☐ CORS configured correctly (not '*')

Monitoring
☐ Failed login attempt alerts
☐ Unusual traffic pattern detection
☐ Security event logging (who did what when)
☐ Incident response plan documented

What's the most common security issue YOU see in codebases? What tools do you use for security scanning?

Follow @armorbreak for more practical developer guides.


Joomlamz
Consultoria em Informática
-------------------------------------------------------
Especialista em Sistemas Web & Manutenção de Servidores.
A desenvolver o novo AplPortal com suporte a PHP 8.
Precisa de ajuda profissional? Contacte-me.

Tags: