OWASP Mobile

Что такое owasp mobile: определение, основные принципы, примеры и практические советы. Изучайте фундаментальной защите информации с подробными объяснениями для начинающих специалистов.

OWASP Mobile Top 10 - Топ-10 угроз мобильных приложений

Что такое OWASP Mobile Top 10?

OWASP Mobile Top 10 — это стандартизированный документ, который описывает 10 наиболее критических рисков безопасности для мобильных приложений. Основан на анализе реальных уязвимостей и лучших практиках обеспечения безопасности.

Цель документа

  • Образование разработчиков и тестировщиков
  • Стандартизация подходов к безопасности
  • Повышение осведомленности о рисках
  • Улучшение качества мобильных приложений

OWASP Mobile Top 10 (2023)

M1: Improper Platform Usage

Неправильное использование платформы

Описание

Неправильное использование возможностей платформы, включая небезопасное использование TouchID, Keychain, Android Intents, и других платформенных функций.

Примеры уязвимостей

  • TouchID/FaceID — неправильная реализация биометрической аутентификации
  • Keychain — небезопасное хранение данных в Keychain
  • Android Intents — неправильная обработка Intent’ов
  • Permissions — неправильное управление разрешениями

Примеры реализации

// Неправильное использование TouchID
class InsecureTouchID {
  // ❌ Неправильно: отсутствие проверки результата
  authenticateWithTouchID() {
    const touchID = new TouchID();
    touchID
      .authenticate("Authenticate with TouchID")
      .then(() => {
        // Пользователь аутентифицирован
        this.grantAccess();
      })
      .catch(() => {
        // Игнорирование ошибки аутентификации
        console.log("TouchID failed");
      });
  }

  // ❌ Неправильно: отсутствие fallback
  authenticateWithTouchID() {
    const touchID = new TouchID();
    touchID.authenticate("Authenticate with TouchID").then(() => {
      this.grantAccess();
    });
    // Нет обработки ошибок
  }
}

// Правильное использование TouchID
class SecureTouchID {
  // ✅ Правильно: проверка доступности и fallback
  async authenticateWithTouchID() {
    try {
      const touchID = new TouchID();

      // Проверка доступности TouchID
      const isAvailable = await touchID.isAvailable();
      if (!isAvailable) {
        throw new Error("TouchID not available");
      }

      // Аутентификация с обработкой ошибок
      const result = await touchID.authenticate("Authenticate with TouchID");

      if (result.success) {
        this.grantAccess();
      } else {
        this.handleAuthenticationFailure(result.error);
      }
    } catch (error) {
      // Fallback на пароль
      this.fallbackToPassword();
    }
  }

  // Fallback на пароль
  fallbackToPassword() {
    // Реализация аутентификации по паролю
    this.showPasswordDialog();
  }

  // Обработка ошибок аутентификации
  handleAuthenticationFailure(error) {
    switch (error.code) {
      case "AUTHENTICATION_FAILED":
        this.showError("Authentication failed. Please try again.");
        break;
      case "USER_CANCEL":
        this.showError("Authentication cancelled by user.");
        break;
      case "SYSTEM_CANCEL":
        this.showError("Authentication cancelled by system.");
        break;
      default:
        this.showError("Unknown authentication error.");
    }
  }
}

M2: Insecure Data Storage

Небезопасное хранение данных

Описание

Небезопасное хранение чувствительных данных в файловой системе, базах данных, SharedPreferences, или других местах хранения.

Примеры уязвимостей

  • Plaintext — хранение данных в открытом виде
  • Weak Encryption — слабое шифрование
  • Insecure Storage — небезопасные места хранения
  • Hardcoded Keys — захардкоженные ключи

Примеры реализации

// Неправильное хранение данных
class InsecureDataStorage {
  // ❌ Неправильно: хранение в открытом виде
  storeUserData(userData) {
    const data = JSON.stringify(userData);
    localStorage.setItem("userData", data);
  }

  // ❌ Неправильно: слабое шифрование
  storePassword(password) {
    const encrypted = btoa(password); // Base64 - не шифрование!
    localStorage.setItem("password", encrypted);
  }

  // ❌ Неправильно: захардкоженный ключ
  encryptData(data) {
    const key = "mySecretKey123"; // Захардкоженный ключ
    return this.simpleEncrypt(data, key);
  }
}

// Правильное хранение данных
class SecureDataStorage {
  constructor() {
    this.crypto = new Crypto();
    this.keyManager = new KeyManager();
  }

  // ✅ Правильно: шифрование с безопасным ключом
  async storeUserData(userData) {
    try {
      // Генерация безопасного ключа
      const key = await this.keyManager.generateKey();

      // Шифрование данных
      const encryptedData = await this.crypto.encrypt(
        JSON.stringify(userData),
        key
      );

      // Безопасное хранение
      await this.secureStorage.setItem("userData", encryptedData);

      // Очистка памяти
      this.clearSensitiveData(userData);
    } catch (error) {
      console.error("Error storing user data:", error);
      throw new Error("Failed to store user data securely");
    }
  }

  // ✅ Правильно: безопасное хранение паролей
  async storePassword(password) {
    try {
      // Хеширование пароля
      const hashedPassword = await this.crypto.hashPassword(password);

      // Шифрование хеша
      const key = await this.keyManager.getEncryptionKey();
      const encryptedHash = await this.crypto.encrypt(hashedPassword, key);

      // Безопасное хранение
      await this.secureStorage.setItem("passwordHash", encryptedHash);

      // Очистка памяти
      this.clearSensitiveData(password);
    } catch (error) {
      console.error("Error storing password:", error);
      throw new Error("Failed to store password securely");
    }
  }

  // ✅ Правильно: безопасное хранение токенов
  async storeToken(token) {
    try {
      // Шифрование токена
      const key = await this.keyManager.getTokenKey();
      const encryptedToken = await this.crypto.encrypt(token, key);

      // Безопасное хранение с TTL
      await this.secureStorage.setItem("token", encryptedToken, {
        ttl: 3600000, // 1 час
        secure: true,
      });
    } catch (error) {
      console.error("Error storing token:", error);
      throw new Error("Failed to store token securely");
    }
  }

  // Очистка чувствительных данных из памяти
  clearSensitiveData(data) {
    if (typeof data === "string") {
      // Перезапись строки
      data = "0".repeat(data.length);
    } else if (typeof data === "object") {
      // Очистка объекта
      for (const key in data) {
        if (typeof data[key] === "string") {
          data[key] = "0".repeat(data[key].length);
        }
      }
    }
  }
}

// Менеджер ключей
class KeyManager {
  constructor() {
    this.crypto = new Crypto();
  }

  // Генерация ключа шифрования
  async generateKey() {
    return await this.crypto.generateKey(256);
  }

  // Получение ключа шифрования
  async getEncryptionKey() {
    let key = await this.secureStorage.getItem("encryptionKey");

    if (!key) {
      key = await this.generateKey();
      await this.secureStorage.setItem("encryptionKey", key);
    }

    return key;
  }

  // Получение ключа для токенов
  async getTokenKey() {
    let key = await this.secureStorage.getItem("tokenKey");

    if (!key) {
      key = await this.generateKey();
      await this.secureStorage.setItem("tokenKey", key);
    }

    return key;
  }
}

M3: Insecure Communication

Небезопасная коммуникация

Описание

Небезопасная передача данных между мобильным приложением и сервером, включая отсутствие SSL/TLS, неправильную валидацию сертификатов, и использование небезопасных протоколов.

Примеры уязвимостей

  • No SSL/TLS — отсутствие шифрования трафика
  • Weak SSL — слабые настройки SSL
  • Certificate Pinning — отсутствие привязки сертификатов
  • Mixed Content — смешанный контент

Примеры реализации

// Неправильная коммуникация
class InsecureCommunication {
  // ❌ Неправильно: HTTP вместо HTTPS
  async fetchUserData(userId) {
    const response = await fetch(`http://api.example.com/users/${userId}`);
    return await response.json();
  }

  // ❌ Неправильно: отсутствие проверки сертификата
  async login(credentials) {
    const response = await fetch("https://api.example.com/login", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(credentials),
    });

    return await response.json();
  }

  // ❌ Неправильно: небезопасные заголовки
  async sendSensitiveData(data) {
    const response = await fetch("https://api.example.com/data", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-API-Key": "hardcoded-key", // Захардкоженный ключ
      },
      body: JSON.stringify(data),
    });

    return await response.json();
  }
}

// Правильная коммуникация
class SecureCommunication {
  constructor() {
    this.certificatePinner = new CertificatePinner();
    this.sslConfig = new SSLConfig();
  }

  // ✅ Правильно: HTTPS с проверкой сертификата
  async fetchUserData(userId) {
    try {
      const response = await fetch(`https://api.example.com/users/${userId}`, {
        method: "GET",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${await this.getAuthToken()}`,
        },
        // Настройки SSL
        ssl: {
          verify: true,
          pinning: true,
        },
      });

      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      return await response.json();
    } catch (error) {
      console.error("Error fetching user data:", error);
      throw new Error("Failed to fetch user data securely");
    }
  }

  // ✅ Правильно: безопасная аутентификация
  async login(credentials) {
    try {
      // Шифрование учетных данных
      const encryptedCredentials = await this.encryptCredentials(credentials);

      const response = await fetch("https://api.example.com/login", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-Request-ID": this.generateRequestId(),
          "X-Timestamp": Date.now().toString(),
        },
        body: JSON.stringify(encryptedCredentials),
        // Настройки SSL
        ssl: {
          verify: true,
          pinning: true,
          minVersion: "TLSv1.2",
        },
      });

      if (!response.ok) {
        throw new Error(`Authentication failed: ${response.status}`);
      }

      const result = await response.json();

      // Безопасное хранение токена
      await this.storeAuthToken(result.token);

      return result;
    } catch (error) {
      console.error("Error during login:", error);
      throw new Error("Authentication failed");
    }
  }

  // ✅ Правильно: безопасная отправка данных
  async sendSensitiveData(data) {
    try {
      // Шифрование данных
      const encryptedData = await this.encryptData(data);

      // Подпись данных
      const signature = await this.signData(encryptedData);

      const response = await fetch("https://api.example.com/data", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${await this.getAuthToken()}`,
          "X-Signature": signature,
          "X-Request-ID": this.generateRequestId(),
        },
        body: JSON.stringify({
          data: encryptedData,
          signature: signature,
        }),
        // Настройки SSL
        ssl: {
          verify: true,
          pinning: true,
          minVersion: "TLSv1.2",
        },
      });

      if (!response.ok) {
        throw new Error(`Failed to send data: ${response.status}`);
      }

      return await response.json();
    } catch (error) {
      console.error("Error sending sensitive data:", error);
      throw new Error("Failed to send data securely");
    }
  }

  // Шифрование учетных данных
  async encryptCredentials(credentials) {
    const key = await this.getEncryptionKey();
    return await this.crypto.encrypt(JSON.stringify(credentials), key);
  }

  // Шифрование данных
  async encryptData(data) {
    const key = await this.getEncryptionKey();
    return await this.crypto.encrypt(JSON.stringify(data), key);
  }

  // Подпись данных
  async signData(data) {
    const key = await this.getSigningKey();
    return await this.crypto.sign(data, key);
  }

  // Получение ключа шифрования
  async getEncryptionKey() {
    // Реализация получения ключа шифрования
    return "encryption-key";
  }

  // Получение ключа подписи
  async getSigningKey() {
    // Реализация получения ключа подписи
    return "signing-key";
  }

  // Генерация ID запроса
  generateRequestId() {
    return Math.random().toString(36).substr(2, 9);
  }
}

M4: Insecure Authentication

Небезопасная аутентификация

Описание

Слабые или отсутствующие механизмы аутентификации, включая простые пароли, отсутствие многофакторной аутентификации, и небезопасное хранение учетных данных.

Примеры уязвимостей

  • Weak Passwords — слабые пароли
  • No MFA — отсутствие MFA
  • Session Management — небезопасное управление сессиями
  • Credential Storage — небезопасное хранение учетных данных

Примеры реализации

// Неправильная аутентификация
class InsecureAuthentication {
  // ❌ Неправильно: слабая проверка пароля
  validatePassword(password) {
    return password.length >= 6; // Слишком слабо
  }

  // ❌ Неправильно: отсутствие MFA
  async login(username, password) {
    const user = await this.findUser(username);
    if (user && user.password === password) {
      return { success: true, token: "simple-token" };
    }
    return { success: false };
  }

  // ❌ Неправильно: небезопасное хранение сессии
  createSession(userId) {
    const sessionId = Math.random().toString(36);
    localStorage.setItem("sessionId", sessionId);
    return sessionId;
  }
}

// Правильная аутентификация
class SecureAuthentication {
  constructor() {
    this.passwordPolicy = new PasswordPolicy();
    this.mfaManager = new MFAManager();
    this.sessionManager = new SessionManager();
  }

  // ✅ Правильно: строгая проверка пароля
  validatePassword(password) {
    const policy = {
      minLength: 12,
      requireUppercase: true,
      requireLowercase: true,
      requireNumbers: true,
      requireSpecialChars: true,
      maxLength: 128,
      noCommonPasswords: true,
    };

    return this.passwordPolicy.validate(password, policy);
  }

  // ✅ Правильно: безопасная аутентификация с MFA
  async login(username, password) {
    try {
      // Валидация входных данных
      if (!this.validateInput(username) || !this.validateInput(password)) {
        throw new Error("Invalid input");
      }

      // Поиск пользователя
      const user = await this.findUser(username);
      if (!user) {
        throw new Error("User not found");
      }

      // Проверка пароля
      const isPasswordValid = await this.verifyPassword(
        password,
        user.passwordHash
      );
      if (!isPasswordValid) {
        throw new Error("Invalid password");
      }

      // Проверка блокировки аккаунта
      if (user.isLocked) {
        throw new Error("Account is locked");
      }

      // Проверка MFA
      if (user.mfaEnabled) {
        const mfaResult = await this.mfaManager.verifyMFA(user.id);
        if (!mfaResult.success) {
          throw new Error("MFA verification failed");
        }
      }

      // Создание безопасной сессии
      const session = await this.sessionManager.createSession(user.id);

      // Логирование успешной аутентификации
      await this.logAuthentication(user.id, "SUCCESS");

      return {
        success: true,
        token: session.token,
        expiresAt: session.expiresAt,
        mfaRequired: user.mfaEnabled,
      };
    } catch (error) {
      // Логирование неудачной аутентификации
      await this.logAuthentication(username, "FAILURE", error.message);

      throw error;
    }
  }

  // ✅ Правильно: безопасное управление сессиями
  async createSession(userId) {
    const session = {
      id: this.generateSessionId(),
      userId: userId,
      token: await this.generateSecureToken(),
      expiresAt: new Date(Date.now() + 3600000), // 1 час
      createdAt: new Date(),
      lastActivity: new Date(),
      ipAddress: await this.getClientIP(),
      userAgent: await this.getUserAgent(),
    };

    // Безопасное хранение сессии
    await this.sessionManager.storeSession(session);

    return session;
  }

  // Проверка входных данных
  validateInput(input) {
    if (!input || typeof input !== "string") {
      return false;
    }

    // Проверка на XSS
    if (this.containsXSS(input)) {
      return false;
    }

    // Проверка на SQL инъекцию
    if (this.containsSQLInjection(input)) {
      return false;
    }

    return true;
  }

  // Проверка пароля
  async verifyPassword(password, hash) {
    return await this.crypto.verifyPassword(password, hash);
  }

  // Генерация безопасного токена
  async generateSecureToken() {
    return await this.crypto.generateSecureToken(32);
  }

  // Генерация ID сессии
  generateSessionId() {
    return this.crypto.generateUUID();
  }

  // Проверка на XSS
  containsXSS(input) {
    const xssPatterns = [/<script/i, /javascript:/i, /on\w+\s*=/i];

    return xssPatterns.some((pattern) => pattern.test(input));
  }

  // Проверка на SQL инъекцию
  containsSQLInjection(input) {
    const sqlPatterns = [
      /union\s+select/i,
      /drop\s+table/i,
      /insert\s+into/i,
      /delete\s+from/i,
      /update\s+set/i,
      /or\s+1=1/i,
      /and\s+1=1/i,
    ];

    return sqlPatterns.some((pattern) => pattern.test(input));
  }
}

M5: Insufficient Cryptography

Недостаточное шифрование

Описание

Использование слабых алгоритмов шифрования, неправильная реализация криптографических функций, или отсутствие шифрования для чувствительных данных.

Примеры уязвимостей

  • Weak Algorithms — слабые алгоритмы шифрования
  • Poor Implementation — неправильная реализация
  • Hardcoded Keys — захардкоженные ключи
  • No Encryption — отсутствие шифрования

Примеры реализации

// Неправильное шифрование
class InsecureCryptography {
  // ❌ Неправильно: слабый алгоритм
  encryptData(data) {
    const key = "mySecretKey";
    return btoa(data + key); // Base64 - не шифрование!
  }

  // ❌ Неправильно: захардкоженный ключ
  encryptPassword(password) {
    const key = "hardcodedKey123";
    return this.simpleXOR(password, key);
  }

  // ❌ Неправильно: слабая реализация XOR
  simpleXOR(data, key) {
    let result = ";
    for (let i = 0; i < data.length; i++) {
      result += String.fromCharCode(
        data.charCodeAt(i) ^ key.charCodeAt(i % key.length)
      );
    }
    return result;
  }
}

// Правильное шифрование
class SecureCryptography {
  constructor() {
    this.crypto = new Crypto();
    this.keyManager = new KeyManager();
  }

  // ✅ Правильно: сильное шифрование
  async encryptData(data, key) {
    try {
      // Использование AES-256-GCM
      const algorithm = "AES-GCM";
      const iv = await this.crypto.generateIV(12);
      const keyMaterial = await this.crypto.importKey(key, algorithm);

      const encrypted = await this.crypto.encrypt(
        algorithm,
        keyMaterial,
        data,
        iv
      );

      return {
        encrypted: encrypted,
        iv: iv,
        algorithm: algorithm,
      };
    } catch (error) {
      console.error("Error encrypting data:", error);
      throw new Error("Encryption failed");
    }
  }

  // ✅ Правильно: безопасное хеширование паролей
  async hashPassword(password) {
    try {
      // Использование Argon2 или bcrypt
      const salt = await this.crypto.generateSalt(16);
      const hash = await this.crypto.hashPassword(password, salt, {
        algorithm: "argon2id",
        memory: 65536,
        iterations: 3,
        parallelism: 4,
      });

      return {
        hash: hash,
        salt: salt,
        algorithm: "argon2id",
      };
    } catch (error) {
      console.error("Error hashing password:", error);
      throw new Error("Password hashing failed");
    }
  }

  // ✅ Правильно: безопасная генерация ключей
  async generateKey(length = 256) {
    try {
      const key = await this.crypto.generateKey(length);
      return key;
    } catch (error) {
      console.error("Error generating key:", error);
      throw new Error("Key generation failed");
    }
  }

  // ✅ Правильно: безопасное хранение ключей
  async storeKey(keyId, key) {
    try {
      // Шифрование ключа мастер-ключом
      const masterKey = await this.keyManager.getMasterKey();
      const encryptedKey = await this.encryptData(key, masterKey);

      // Безопасное хранение
      await this.secureStorage.setItem(`key_${keyId}`, encryptedKey);
    } catch (error) {
      console.error("Error storing key:", error);
      throw new Error("Key storage failed");
    }
  }

  // ✅ Правильно: безопасное извлечение ключей
  async retrieveKey(keyId) {
    try {
      // Получение зашифрованного ключа
      const encryptedKey = await this.secureStorage.getItem(`key_${keyId}`);
      if (!encryptedKey) {
        throw new Error("Key not found");
      }

      // Расшифровка ключа
      const masterKey = await this.keyManager.getMasterKey();
      const key = await this.decryptData(encryptedKey, masterKey);

      return key;
    } catch (error) {
      console.error("Error retrieving key:", error);
      throw new Error("Key retrieval failed");
    }
  }

  // Расшифровка данных
  async decryptData(encryptedData, key) {
    try {
      const algorithm = encryptedData.algorithm;
      const iv = encryptedData.iv;
      const encrypted = encryptedData.encrypted;

      const keyMaterial = await this.crypto.importKey(key, algorithm);
      const decrypted = await this.crypto.decrypt(
        algorithm,
        keyMaterial,
        encrypted,
        iv
      );

      return decrypted;
    } catch (error) {
      console.error("Error decrypting data:", error);
      throw new Error("Decryption failed");
    }
  }
}

Остальные угрозы (M6-M10)

M6: Insecure Authorization

Небезопасная авторизация

  • Неправильная проверка прав доступа
  • Отсутствие проверки разрешений
  • Небезопасное управление ролями

M7: Client Code Quality

Качество клиентского кода

  • Отсутствие валидации входных данных
  • Неправильная обработка ошибок
  • Уязвимости в коде

M8: Code Tampering

Модификация кода

  • Отсутствие защиты от модификации
  • Небезопасное хранение кода
  • Отсутствие проверки целостности

M9: Reverse Engineering

Обратная инженерия

  • Отсутствие обфускации кода
  • Небезопасное хранение секретов
  • Отсутствие защиты от анализа

M10: Extraneous Functionality

Избыточная функциональность

  • Наличие скрытых функций
  • Отладочный код в продакшене
  • Неиспользуемые функции

Best Practices

1. Разработка

  • Secure Coding — безопасное программирование
  • Input Validation — валидация входных данных
  • Error Handling — правильная обработка ошибок
  • Code Review — проверка кода

2. Тестирование

  • Security Testing — тестирование безопасности
  • Penetration Testing — тестирование на проникновение
  • Vulnerability Scanning — сканирование уязвимостей
  • Code Analysis — анализ кода

3. Развертывание

  • Secure Configuration — безопасная конфигурация
  • Certificate Management — управление сертификатами
  • Key Management — управление ключами
  • Monitoring — мониторинг

Заключение

OWASP Mobile Top 10 — это важный документ, который помогает разработчикам и тестировщикам понимать основные угрозы безопасности мобильных приложений. Следование рекомендациям:

  • Снижает риски безопасности
  • Улучшает качество приложений
  • Повышает доверие пользователей
  • Соответствует стандартам безопасности

Помните: безопасность мобильных приложений — это не разовое мероприятие, а постоянный процесс. Регулярно обновляйте знания, используйте современные инструменты и следуйте лучшим практикам.


Совет: Начните с изучения OWASP Mobile Top 10, затем внедрите соответствующие меры защиты в ваши приложения. Не забывайте о регулярном тестировании и обновлении мер безопасности!