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 — это не разовое мероприятие, а постоянный процесс. Регулярно обновляйте инструменты, следите за новыми угрозами и адаптируйте методы анализа.

💡 Совет: Начните с анализа манифеста, затем переходите к анализу кода. Не забывайте о проверке разрешений и экспортированных компонентов!