Как данные в приложении защитить от кражи?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Защита данных в Frontend приложении
Это критически важный вопрос. Безопасность frontend часто недооценивается. Вот как я это вижу в своей практике.
Главный принцип
Frontend это НЕНАДЁЖНАЯ среда. Всё что видит пользователь — может быть украдено или изменено. Реальная защита должна быть на backend.
Что можно защитить на Frontend
1. Защита от XSS (Cross-Site Scripting)
Это основная векторов атак на frontend.
// Плохо: User input может содержать скрипт
function renderComment(comment) {
return (
<div dangerouslySetInnerHTML={{ __html: comment.text }} />
);
}
// Если comment.text = '<img src=x onerror="stealToken()">'
// Скрипт выполнится!
// Хорошо: React автоматически экранирует
function renderComment(comment) {
return <div>{comment.text}</div>;
}
// React спасает от XSS
Правило: Никогда не используй dangerouslySetInnerHTML с user input.
// Если нужен HTML из user:
const DOMPurify = require('dompurify');
function renderUserContent(html) {
const cleanHtml = DOMPurify.sanitize(html);
return (
<div dangerouslySetInnerHTML={{ __html: cleanHtml }} />
);
}
2. Защита токенов доступа
Это самое важное. Украденный token = полный доступ к аккаунту.
// Плохо: localStorage
localStorage.setItem('token', accessToken);
// JavaScript может украсть: localStorage.getItem('token')
// Хорошо: HttpOnly cookies (устанавливает backend)
// Set-Cookie: token=xyz; HttpOnly; Secure; SameSite=Strict
// JavaScript НЕ МОЖЕТ получить доступ!
// Фронт не может ничего сделать с HttpOnly cookies,
// но браузер автоматически отправляет их с запросами
fetch('/api/protected', {
credentials: 'include' // Отправляем HttpOnly cookies
});
Если ВЫНУЖДЕН хранить в памяти:
let accessToken: string | null = null;
function setToken(token: string) {
accessToken = token;
}
function getToken(): string | null {
return accessToken;
}
// При refresh страницы token теряется (это ХОРОШО)
// Нужно запросить новый token у backend
3. Защита от CSRF (Cross-Site Request Forgery)
// Плохо: Backend принимает запрос от любого сайта
fetch('https://bank.com/transfer', {
method: 'POST',
body: JSON.stringify({ amount: 1000 })
});
// Если ты на злом сайте, можно отправить запрос от твоего имени!
// Хорошо: Backend требует CSRF token
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content;
fetch('https://bank.com/transfer', {
method: 'POST',
headers: {
'X-CSRF-Token': csrfToken
},
body: JSON.stringify({ amount: 1000 })
});
// Backend проверяет что X-CSRF-Token совпадает с cookie CSRF
// Если запрос со злого сайта — нет valid токена — отклоняем
4. Защита от Clickjacking
<!-- В HTML (или backend header) -->
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta http-equiv="Content-Security-Policy"
content="frame-ancestors 'none'">
<!-- Или backend header -->
X-Frame-Options: DENY
Это предотвращает embed приложения в iframe на злом сайте.
5. Content Security Policy (CSP)
<meta http-equiv="Content-Security-Policy"
content="
default-src 'self';
script-src 'self' https://cdn.example.com;
style-src 'self' 'unsafe-inline';
img-src 'self' https:;
connect-src 'self' https://api.example.com
">
Это ограничивает откуда может загружаться контент.
Что НЕЛЬЗЯ защитить на Frontend
Никогда не:
// 1. Хранить пароли
const password = 'secret123';
fetch('/api/login', { body: password });
// Пароль видна в памяти, истории, сетевых запросах!
// Правило: Отправляй пароль один раз, сразу забудь
// 2. Хранить API ключи
const apiKey = 'sk-1234567890';
fetch('https://api.openai.com/v1/chat', {
headers: { 'Authorization': `Bearer ${apiKey}` }
});
// Любой может украсть apiKey из DevTools!
// Правило: API ключи только на backend
// 3. Скрывать логику авторизации
const isAdmin = localStorage.getItem('isAdmin') === 'true';
if (isAdmin) {
return <AdminPanel />;
}
// Пользователь может просто изменить: localStorage.setItem('isAdmin', 'true')!
// Правило: Проверка прав ВСЕГДА на backend
// 4. Валидировать доступ на frontend
if (user.id === currentUserId) {
return <EditButton />; // Пользователь может обмануть!
}
// Правило: Backend должен проверить pravo при запросе
Правильная архитектура защиты
Frontend (НЕНАДЁЖНЫЙ):
1. Проверить input (UX, не безопасность)
2. Отправить на backend
3. Ждать ответа
Backend (НАДЁЖНЫЙ):
1. Проверить input (БЕЗОПАСНОСТЬ)
2. Проверить авторизацию (есть ли право?)
3. Проверить авторизацию (свой ли это ресурс?)
4. Выполнить операцию
5. Вернуть результат
Практический пример: защита при удалении
// Frontend
function DeleteButton({ questionId, ownerId }) {
const currentUserId = useAuthStore(s => s.userId);
const canDelete = currentUserId === ownerId; // Только для UX!
if (!canDelete) return null;
const handleDelete = async () => {
try {
const response = await fetch(`/api/questions/${questionId}`, {
method: 'DELETE',
credentials: 'include'
});
if (response.ok) {
// Успешно удалено
}
} catch (err) {
console.error('Delete failed:', err);
}
};
return <button onClick={handleDelete}>Delete</button>;
}
// Backend (Python/FastAPI пример)
@router.delete('/questions/{question_id}')
async def delete_question(
question_id: str,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
question = db.query(Question).get(question_id)
# САМОЕ ВАЖНОЕ: проверить что это questions автора
if question.owner_id != current_user.id:
raise HTTPException(status_code=403, detail='Not authorized')
db.delete(question)
db.commit()
return {'ok': True}
Чеклист безопасности
- HTTPOnly cookies для токенов (не localStorage)
- HTTPS только (Secure флаг на cookies)
- Sanitize user input (DOMPurify для HTML)
- Никогда не dangerouslySetInnerHTML с user data
- Проверка прав на backend (никогда не доверяй frontend)
- CSRF tokens для POST/PUT/DELETE
- Content-Security-Policy header
- X-Frame-Options: DENY (от clickjacking)
- Регулярно обновляй зависимости
- Логирование попыток несанкционированного доступа
Вывод
Фrontend может защитить от простых атак (XSS, CSRF), но真实的保护 должна быть на backend.
Думай так: Frontend это UI, Backend это сейф. Не жди что UI сохранит деньги — используй сейф.