fix: полное ревью системы — 15 исправлений безопасности и надёжности
Безопасность: - tests/🆔 скрыть is_correct и explanation для студентов (P0) - SQL injection: limit/offset через placeholder вместо template literal - Stored XSS: stripTags для lesson comments, flashcards, redBook sightings - profile.html: escape e.message в showMsg (XSS через server error) - attachment_url: валидация только /uploads/* путей - requestId: генерировать UUID сервером, не доверять клиенту - register: скрыть token_version из ответа Надёжность: - register: обработка UNIQUE constraint race condition - pet buyBg: re-check баланса внутри транзакции - DB errors: скрыть e.message в testController/questionController/courseController - preferences: лимит 50KB на размер JSON UX: - board.html: debounce 250ms на search input Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
const db = require('../db/db');
|
||||
const { awardXP, checkRedBookAchievements } = require('./gamificationController');
|
||||
const { stripTags } = require('../utils/sanitize');
|
||||
|
||||
/* ── helpers ─────────────────────────────────────────────────────────── */
|
||||
const stmts = {
|
||||
@@ -86,7 +87,8 @@ function buildSpeciesList(filter = {}) {
|
||||
sql += ' ORDER BY s.category, s.name_ru';
|
||||
const limit = Math.min(parseInt(filter.limit) || 50, 100);
|
||||
const offset = parseInt(filter.offset) || 0;
|
||||
sql += ` LIMIT ${limit} OFFSET ${offset}`;
|
||||
sql += ' LIMIT ? OFFSET ?';
|
||||
params.push(limit, offset);
|
||||
return db.prepare(sql).all(...params);
|
||||
}
|
||||
|
||||
@@ -303,7 +305,8 @@ exports.getSightings = (req, res) => {
|
||||
exports.addSighting = (req, res) => {
|
||||
const { species_id, region_code, description } = req.body || {};
|
||||
if (!species_id) return res.status(400).json({ error: 'species_id обязателен' });
|
||||
const id = stmts.addSighting.run(req.user.id, species_id, region_code || '', description || '').lastInsertRowid;
|
||||
const safeDesc = stripTags((description || '').slice(0, 2000));
|
||||
const id = stmts.addSighting.run(req.user.id, species_id, region_code || '', safeDesc).lastInsertRowid;
|
||||
try { checkRedBookAchievements(req.user.id); } catch {}
|
||||
res.json({ id });
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user