Android SAST
Что такое android sast: определение, основные принципы, примеры и практические советы. Изучайте фундаментальной защите информации с подробными объяснениями для начинающих специалистов.
Android SAST - Статический анализ приложений Android
Что такое Android SAST?
Android SAST (Static Application Security Testing) — это процесс анализа безопасности Android приложений на уровне исходного кода без их выполнения. Включает анализ Java/Kotlin кода, манифестов, ресурсов и конфигураций для выявления потенциальных уязвимостей безопасности.
Основные принципы
- Source Code Analysis — анализ исходного кода
- Manifest Analysis — анализ манифестов
- Resource Analysis — анализ ресурсов
- Configuration Analysis — анализ конфигураций
- Vulnerability Detection — обнаружение уязвимостей
Архитектура Android SAST
1. Code Analysis
// Система анализа кода Android приложений
class AndroidCodeAnalyzer {
constructor() {
this.vulnerabilities = new Map();
this.patterns = new Map();
this.rules = new Map();
this.issues = new Map();
}
// Анализ Java кода
analyzeJavaCode(codeData) {
const analysis = {
id: this.generateAnalysisId(),
fileType: 'JAVA',
timeRange: new Date(),
vulnerabilities: [],
issues: [],
patterns: [],
summary: {
totalVulnerabilities: 0,
criticalVulnerabilities: 0,
highVulnerabilities: 0,
mediumVulnerabilities: 0,
lowVulnerabilities: 0
}
};
// Парсинг Java кода
const parsedCode = this.parseJavaCode(codeData.content);
analysis.code = parsedCode;
// Анализ уязвимостей
const vulnerabilities = this.findVulnerabilities(parsedCode);
analysis.vulnerabilities = vulnerabilities;
// Анализ проблем
const issues = this.findIssues(parsedCode);
analysis.issues = issues;
// Анализ паттернов
const patterns = this.findPatterns(parsedCode);
analysis.patterns = patterns;
// Расчет сводки
this.calculateCodeSummary(analysis);
return analysis;
}
// Парсинг Java кода
parseJavaCode(content) {
const code = {
classes: [],
methods: [],
variables: [],
imports: [],
annotations: []
};
// Упрощенный парсинг Java кода
const lines = content.split('\n');
let currentClass = null;
let currentMethod = null;
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
// Анализ импортов
if (line.startsWith('import ')) {
code.imports.push({
statement: line,
package: line.replace('import ', '').replace(';', ''),
line: i + 1
});
}
// Анализ классов
if (line.includes('class ') && line.includes('{')) {
const className = this.extractClassName(line);
currentClass = {
name: className,
line: i + 1,
methods: [],
variables: []
};
code.classes.push(currentClass);
}
// Анализ методов
if (line.includes('(') && line.includes(')') && !line.includes('class')) {
const method = this.extractMethod(line, i + 1);
if (method) {
currentMethod = method;
if (currentClass) {
currentClass.methods.push(method);
}
code.methods.push(method);
}
}
// Анализ переменных
if (line.includes('=') && !line.includes('(')) {
const variable = this.extractVariable(line, i + 1);
if (variable) {
if (currentClass) {
currentClass.variables.push(variable);
}
code.variables.push(variable);
}
}
}
return code;
}
// Извлечение имени класса
extractClassName(line) {
const parts = line.split(' ');
const classIndex = parts.indexOf('class');
if (classIndex !== -1 && classIndex + 1 < parts.length) {
return parts[classIndex + 1].split('{')[0];
}
return 'Unknown';
}
// Извлечение метода
extractMethod(line, lineNumber) {
const parts = line.split('(');
if (parts.length >= 2) {
const methodPart = parts[0].trim();
const methodName = methodPart.split(' ').pop();
const returnType = methodPart.replace(methodName, '').trim();
return {
name: methodName,
returnType: returnType,
line: lineNumber,
parameters: this.extractParameters(parts[1])
};
}
return null;
}
// Извлечение параметров
extractParameters(paramString) {
const params = paramString.split(')')[0].split(',');
return params.map(p => p.trim()).filter(p => p.length > 0);
}
// Извлечение переменной
extractVariable(line, lineNumber) {
const parts = line.split('=');
if (parts.length >= 2) {
const varPart = parts[0].trim();
const varName = varPart.split(' ').pop();
const varType = varPart.replace(varName, '').trim();
return {
name: varName,
type: varType,
line: lineNumber,
value: parts[1].trim()
};
}
return null;
}
// Поиск уязвимостей
findVulnerabilities(parsedCode) {
const vulnerabilities = [];
// Уязвимости в методах
const methodVulnerabilities = this.findMethodVulnerabilities(parsedCode.methods);
vulnerabilities.push(...methodVulnerabilities);
// Уязвимости в переменных
const variableVulnerabilities = this.findVariableVulnerabilities(parsedCode.variables);
vulnerabilities.push(...variableVulnerabilities);
// Уязвимости в импортах
const importVulnerabilities = this.findImportVulnerabilities(parsedCode.imports);
vulnerabilities.push(...importVulnerabilities);
return vulnerabilities;
}
// Поиск уязвимостей в методах
findMethodVulnerabilities(methods) {
const vulnerabilities = [];
for (const method of methods) {
// Проверка на небезопасные методы
const unsafeMethods = [
'getSharedPreferences',
'getExternalStorageDirectory',
'getExternalFilesDir',
'openFileOutput',
'openFileInput'
];
for (const unsafeMethod of unsafeMethods) {
if (method.name.includes(unsafeMethod)) {
vulnerabilities.push({
type: 'UNSAFE_METHOD',
method: method,
severity: 'HIGH',
description: `Unsafe method detected: ${method.name}`
});
}
}
// Проверка на отсутствие проверки разрешений
if (method.name.includes('read') || method.name.includes('write')) {
vulnerabilities.push({
type: 'MISSING_PERMISSION_CHECK',
method: method,
severity: 'MEDIUM',
description: `Missing permission check in method: ${method.name}`
});
}
}
return vulnerabilities;
}
// Поиск уязвимостей в переменных
findVariableVulnerabilities(variables) {
const vulnerabilities = [];
for (const variable of variables) {
// Проверка на небезопасные переменные
if (variable.name.includes('password') || variable.name.includes('secret')) {
vulnerabilities.push({
type: 'SENSITIVE_VARIABLE',
variable: variable,
severity: 'HIGH',
description: `Sensitive variable detected: ${variable.name}`
});
}
// Проверка на хардкод значений
if (variable.value.includes('http://') || variable.value.includes('https://')) {
vulnerabilities.push({
type: 'HARDCODED_URL',
variable: variable,
severity: 'MEDIUM',
description: `Hardcoded URL detected: ${variable.value}`
});
}
}
return vulnerabilities;
}
// Поиск уязвимостей в импортах
findImportVulnerabilities(imports) {
const vulnerabilities = [];
for (const import of imports) {
// Проверка на небезопасные импорты
const unsafePackages = [
'android.webkit.WebView',
'android.webkit.WebSettings',
'android.webkit.WebViewClient',
'android.webkit.WebChromeClient'
];
for (const unsafePackage of unsafePackages) {
if (import.package.includes(unsafePackage)) {
vulnerabilities.push({
type: 'UNSAFE_IMPORT',
import: import,
severity: 'MEDIUM',
description: `Unsafe import detected: ${import.package}`
});
}
}
}
return vulnerabilities;
}
// Генерация ID анализа
generateAnalysisId() {
return 'ANDROID-CODE-ANALYSIS-' + Date.now() + '-' + Math.random().toString(36).substr(2, 4);
}
}
2. Manifest Analysis
// Система анализа манифестов Android
class AndroidManifestAnalyzer {
constructor() {
this.permissions = new Map();
this.activities = new Map();
this.services = new Map();
this.receivers = new Map();
this.providers = new Map();
}
// Анализ манифеста
analyzeManifest(manifestData) {
const analysis = {
id: this.generateAnalysisId(),
timeRange: new Date(),
permissions: [],
activities: [],
services: [],
receivers: [],
providers: [],
vulnerabilities: [],
summary: {
totalPermissions: 0,
dangerousPermissions: 0,
totalActivities: 0,
exportedActivities: 0,
totalServices: 0,
exportedServices: 0,
},
};
// Парсинг манифеста
const parsedManifest = this.parseManifest(manifestData.content);
analysis.manifest = parsedManifest;
// Анализ разрешений
const permissions = this.analyzePermissions(parsedManifest.permissions);
analysis.permissions = permissions;
// Анализ активностей
const activities = this.analyzeActivities(parsedManifest.activities);
analysis.activities = activities;
// Анализ сервисов
const services = this.analyzeServices(parsedManifest.services);
analysis.services = services;
// Анализ ресиверов
const receivers = this.analyzeReceivers(parsedManifest.receivers);
analysis.receivers = receivers;
// Анализ провайдеров
const providers = this.analyzeProviders(parsedManifest.providers);
analysis.providers = providers;
// Поиск уязвимостей
const vulnerabilities = this.findManifestVulnerabilities(analysis);
analysis.vulnerabilities = vulnerabilities;
// Расчет сводки
this.calculateManifestSummary(analysis);
return analysis;
}
// Парсинг манифеста
parseManifest(content) {
const manifest = {
permissions: [],
activities: [],
services: [],
receivers: [],
providers: [],
};
// Упрощенный парсинг XML манифеста
const lines = content.split("\n");
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
// Анализ разрешений
if (line.includes("<uses-permission")) {
const permission = this.extractPermission(line);
if (permission) {
manifest.permissions.push(permission);
}
}
// Анализ активностей
if (line.includes("<activity")) {
const activity = this.extractActivity(line, lines, i);
if (activity) {
manifest.activities.push(activity);
}
}
// Анализ сервисов
if (line.includes("<service")) {
const service = this.extractService(line, lines, i);
if (service) {
manifest.services.push(service);
}
}
// Анализ ресиверов
if (line.includes("<receiver")) {
const receiver = this.extractReceiver(line, lines, i);
if (receiver) {
manifest.receivers.push(receiver);
}
}
// Анализ провайдеров
if (line.includes("<provider")) {
const provider = this.extractProvider(line, lines, i);
if (provider) {
manifest.providers.push(provider);
}
}
}
return manifest;
}
// Извлечение разрешения
extractPermission(line) {
const nameMatch = line.match(/android:name="([^"]+)"/);
if (nameMatch) {
return {
name: nameMatch[1],
type: this.classifyPermission(nameMatch[1]),
line: line,
};
}
return null;
}
// Классификация разрешения
classifyPermission(permission) {
const dangerousPermissions = [
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE",
"android.permission.CAMERA",
"android.permission.RECORD_AUDIO",
"android.permission.ACCESS_FINE_LOCATION",
"android.permission.ACCESS_COARSE_LOCATION",
"android.permission.READ_CONTACTS",
"android.permission.WRITE_CONTACTS",
"android.permission.READ_CALL_LOG",
"android.permission.WRITE_CALL_LOG",
"android.permission.READ_SMS",
"android.permission.SEND_SMS",
"android.permission.RECEIVE_SMS",
];
if (dangerousPermissions.includes(permission)) {
return "DANGEROUS";
} else if (
permission.includes("INTERNET") ||
permission.includes("NETWORK")
) {
return "NETWORK";
} else {
return "NORMAL";
}
}
// Извлечение активности
extractActivity(line, lines, lineIndex) {
const nameMatch = line.match(/android:name="([^"]+)"/);
const exportedMatch = line.match(/android:exported="([^"]+)"/);
if (nameMatch) {
return {
name: nameMatch[1],
exported: exportedMatch ? exportedMatch[1] === "true" : false,
line: lineIndex + 1,
};
}
return null;
}
// Извлечение сервиса
extractService(line, lines, lineIndex) {
const nameMatch = line.match(/android:name="([^"]+)"/);
const exportedMatch = line.match(/android:exported="([^"]+)"/);
if (nameMatch) {
return {
name: nameMatch[1],
exported: exportedMatch ? exportedMatch[1] === "true" : false,
line: lineIndex + 1,
};
}
return null;
}
// Извлечение ресивера
extractReceiver(line, lines, lineIndex) {
const nameMatch = line.match(/android:name="([^"]+)"/);
const exportedMatch = line.match(/android:exported="([^"]+)"/);
if (nameMatch) {
return {
name: nameMatch[1],
exported: exportedMatch ? exportedMatch[1] === "true" : false,
line: lineIndex + 1,
};
}
return null;
}
// Извлечение провайдера
extractProvider(line, lines, lineIndex) {
const nameMatch = line.match(/android:name="([^"]+)"/);
const exportedMatch = line.match(/android:exported="([^"]+)"/);
const authoritiesMatch = line.match(/android:authorities="([^"]+)"/);
if (nameMatch) {
return {
name: nameMatch[1],
exported: exportedMatch ? exportedMatch[1] === "true" : false,
authorities: authoritiesMatch ? authoritiesMatch[1] : null,
line: lineIndex + 1,
};
}
return null;
}
// Поиск уязвимостей манифеста
findManifestVulnerabilities(analysis) {
const vulnerabilities = [];
// Проверка на опасные разрешения
const dangerousPermissions = analysis.permissions.filter(
(p) => p.type === "DANGEROUS"
);
if (dangerousPermissions.length > 0) {
vulnerabilities.push({
type: "DANGEROUS_PERMISSIONS",
count: dangerousPermissions.length,
severity: "HIGH",
description: `Found ${dangerousPermissions.length} dangerous permissions`,
});
}
// Проверка на экспортированные компоненты
const exportedActivities = analysis.activities.filter((a) => a.exported);
if (exportedActivities.length > 0) {
vulnerabilities.push({
type: "EXPORTED_ACTIVITIES",
count: exportedActivities.length,
severity: "MEDIUM",
description: `Found ${exportedActivities.length} exported activities`,
});
}
const exportedServices = analysis.services.filter((s) => s.exported);
if (exportedServices.length > 0) {
vulnerabilities.push({
type: "EXPORTED_SERVICES",
count: exportedServices.length,
severity: "MEDIUM",
description: `Found ${exportedServices.length} exported services`,
});
}
return vulnerabilities;
}
// Генерация ID анализа
generateAnalysisId() {
return (
"ANDROID-MANIFEST-ANALYSIS-" +
Date.now() +
"-" +
Math.random().toString(36).substr(2, 4)
);
}
}
Основные компоненты Android SAST
1. Code Analysis
- Java/Kotlin Analysis — анализ Java/Kotlin кода
- Method Analysis — анализ методов
- Variable Analysis — анализ переменных
- Import Analysis — анализ импортов
2. Manifest Analysis
- Permission Analysis — анализ разрешений
- Component Analysis — анализ компонентов
- Intent Analysis — анализ интентов
- Configuration Analysis — анализ конфигураций
3. Resource Analysis
- String Analysis — анализ строк
- Layout Analysis — анализ макетов
- Drawable Analysis — анализ изображений
- Value Analysis — анализ значений
Best Practices
1. Analysis Process
- Systematic Approach — системный подход
- Rule-based Analysis — анализ на основе правил
- Pattern Recognition — распознавание паттернов
- Vulnerability Classification — классификация уязвимостей
2. Tools and Techniques
- Static Analysis Tools — инструменты статического анализа
- Code Review — обзор кода
- Automated Scanning — автоматическое сканирование
- Manual Analysis — ручной анализ
3. Security Guidelines
- OWASP Mobile Top 10 — топ-10 мобильных угроз OWASP
- Android Security Guidelines — руководящие принципы безопасности Android
- Secure Coding Practices — практики безопасного программирования
- Vulnerability Management — управление уязвимостями
Заключение
Android SAST — это критически важная область мобильной безопасности, которая требует:
- Глубокого понимания — платформы Android
- Специализированных навыков — в области анализа кода
- Правильных инструментов — для статического анализа
- Системного подхода — к выявлению уязвимостей
Помните: Android SAST — это не разовое мероприятие, а постоянный процесс. Регулярно обновляйте инструменты, следите за новыми угрозами и адаптируйте методы анализа.
💡 Совет: Начните с анализа манифеста, затем переходите к анализу кода. Не забывайте о проверке разрешений и экспортированных компонентов!