← Назад к вопросам

Как данные в приложении защитить от кражи?

1.6 Junior🔥 101 комментариев
#Браузер и сетевые технологии

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Защита данных в 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}

Чеклист безопасности

  1. HTTPOnly cookies для токенов (не localStorage)
  2. HTTPS только (Secure флаг на cookies)
  3. Sanitize user input (DOMPurify для HTML)
  4. Никогда не dangerouslySetInnerHTML с user data
  5. Проверка прав на backend (никогда не доверяй frontend)
  6. CSRF tokens для POST/PUT/DELETE
  7. Content-Security-Policy header
  8. X-Frame-Options: DENY (от clickjacking)
  9. Регулярно обновляй зависимости
  10. Логирование попыток несанкционированного доступа

Вывод

Фrontend может защитить от простых атак (XSS, CSRF), но真实的保护 должна быть на backend.

Думай так: Frontend это UI, Backend это сейф. Не жди что UI сохранит деньги — используй сейф.