Веб коопсуздугу: OWASP Top 10 - реалдуу чабуулдар жана коргоо
OWASP Top 10 - веб тиркемелердин коопсуздугун баалоонун дүйнөлүк стандарты. Ар бир пункт - миңдеген тиркемелерди бузуу үчүн колдонулган конкреттүү ыкма. Бул - практикалык колдонмо, Node.js разработчиктери үчүн.
A01: Сынган мүмкүндүктү башкаруу
Эң кеңири таралган аялуулук. Колдонуучу башкалардын маалыматына мүмкүндүк алат.
IDOR чабуулу:
GET /api/orders/my-order-id ← менин заказым
GET /api/orders/victim-order-id ← башкасынын заказы (эгер текшерүү жок болсо!)
// ❌ Авторизацияны гана текшерет, ресурска ким ээлигин - жок
router.get('/api/orders/:orderId', authenticate, async (req, res) => {
const order = await db.order.findUnique({ where: { id: req.params.orderId } });
res.json(order); // каалаган авторизацияланган колдонуучу каалаган заказды алат
});
// ✅ Учурдагы колдонуучуга гана чектөөбүз
router.get('/api/orders/:orderId', authenticate, async (req, res) => {
const order = await db.order.findUnique({
where: {
id: req.params.orderId,
userId: req.user.id, // колдонуучу өзүнүн заказдарын гана көрөт
},
});
if (!order) return res.status(404).json({ error: 'Табылган жок' });
res.json(order);
});
Admin эндпоинттери үчүн - роль текшерүү:
function requireRole(role: string) {
return (req: Request, res: Response, next: NextFunction) => {
if (!req.user?.roles.includes(role)) {
return res.status(403).json({ error: 'Уруксат жок' });
}
next();
};
}
router.delete('/api/admin/users/:id', authenticate, requireRole('admin'), deleteUser);
A02: Криптографиялык каталар
Сырсөздөрдү туура эмес сактоо - эң кеңири таралган катанын бири.
// ❌ MD5 - сырсөз хэштөө алгоритми эмес
const hash = crypto.createHash('md5').update(password).digest('hex');
// ✅ bcrypt - атайылап жай иштеген алгоритм
import bcrypt from 'bcrypt';
async function hashPassword(password: string): Promise<string> {
return bcrypt.hash(password, 12); // cost factor 12 ≈ 250мс
}
async function verifyPassword(password: string, hash: string): Promise<boolean> {
return bcrypt.compare(password, hash);
}
// ✅ Сырсөзду калыбына келтирүү үчүн коопсуз токен
import crypto from 'crypto';
async function createResetToken(userId: string): Promise<string> {
const token = crypto.randomBytes(32).toString('hex');
const hash = crypto.createHash('sha256').update(token).digest('hex');
await db.passwordReset.create({
data: {
userId,
tokenHash: hash,
expiresAt: new Date(Date.now() + 15 * 60 * 1000), // 15 мүнөт
},
});
return token; // колдонуучуга жиберебиз, хэшти гана сактайбыз
}
A03: Инъекциялар (SQL, NoSQL)
// ❌ SQL инъекция - классикалык аялуулук
const users = await db.query(
`SELECT * FROM users WHERE email = '${req.body.email}'`
);
// Чабуул: email = "admin'--" → сырсөзсүз системага кирет
// ✅ Параметрлештирилген суроо
const users = await db.query(
'SELECT * FROM users WHERE email = $1',
[req.body.email]
);
// ✅ ORM - автоматтык параметрлештирүү
const user = await prisma.user.findUnique({
where: { email: req.body.email },
});
NoSQL (MongoDB) инъекциясы:
// ❌ Аялуу
// Чабуул: { "email": {"$gt": ""}, "password": {"$gt": ""} } → авторизацияны айланып өтөт
const user = await User.findOne({ email: req.body.email });
// ✅ Zod менен валидация
import { z } from 'zod';
const LoginSchema = z.object({
email: z.string().email(),
password: z.string().min(1),
});
const { email, password } = LoginSchema.parse(req.body);
// email милдетте string - инъекция мүмкүн эмес
A05: Туура эмес конфигурация
Коопсуздук headers - ар кандай веб тиркеме үчүн милдеттүү:
import helmet from 'helmet';
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", 'data:', 'https:'],
},
},
hsts: {
maxAge: 63072000, // 2 жыл
includeSubDomains: true,
},
}));
// Production'до stack trace жок
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
logger.error({ err, url: req.url });
res.status(500).json(
process.env.NODE_ENV === 'production'
? { error: 'Ички ката' }
: { error: err.message, stack: err.stack }
);
});
A07: Аутентификациянын бузулушу
Brute-force коргоо - rate limiting:
import rateLimit from 'express-rate-limit';
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 мүнөт
max: 10, // бир IP'дан 10 аракет
handler: (req, res) => {
res.status(429).json({ error: '15 мүнөттөн кийин кайра аракет кылыңыз' });
},
});
app.post('/api/auth/login', loginLimiter, loginHandler);
// Email'дин базада бар-жогун ачпаңыз
// ❌ Колдонуучу аттарды чогултууга жардам берет
if (!user) return res.status(404).json({ error: 'Колдонуучу табылган жок' });
// ✅ Бирдей жооп
if (!user || !await bcrypt.compare(password, user.passwordHash)) {
return res.status(401).json({ error: 'Туура эмес email же сырсөз' });
}
A10: SSRF - сервердик суроолорду жасалмалоо
// ❌ Аялуу - ички сервистерге суроо жибере алат
app.post('/api/preview', async (req, res) => {
const response = await fetch(req.body.url);
// Чабуул: url = 'http://169.254.169.254/' → AWS credentials агылуусу
});
// ✅ Жеке IP диапазондорду блокторбуз
import dns from 'dns/promises';
import ipRangeCheck from 'ip-range-check';
const BLOCKED = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', '127.0.0.0/8', '169.254.0.0/16'];
async function isSafeUrl(urlString: string): Promise<boolean> {
try {
const url = new URL(urlString);
if (!['http:', 'https:'].includes(url.protocol)) return false;
const ips = await dns.resolve4(url.hostname);
return ips.every(ip => !ipRangeCheck(ip, BLOCKED));
} catch { return false; }
}
Минималдуу коопсуздук чеклисти
[ ] Бардык колдонуучу ввод валидацияланат (Zod)
[ ] SQL: параметрлештирилген суроолор гана
[ ] Сырсөздөр: bcrypt cost factor 10+
[ ] Security headers: Helmet
[ ] Rate limiting: /login жана /register
[ ] JWT: 15 мүнөт жашоо + refresh token
[ ] npm audit CI/CD'да
[ ] Production'до stack trace жок
[ ] Ар бир суроо ресурсун ийелигин текшерет
[ ] HTTPS + HSTS
Aunimeda Кыргызстан бизнеси үчүн коопсуз веб тиркемелерди иштеп чыгат.
Ошондой эле: Telegram Bot webhook жана FSM, Git продвинутый workflow