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, затем внедрите соответствующие меры защиты в ваши приложения. Не забывайте о регулярном тестировании и обновлении мер безопасности!