Static Analysis Tools

Static Analysis Tools

Static analysis tools examine source code, bytecode, or binary code to identify security vulnerabilities without executing the application.

Popular SAST Tools for Mobile:

// iOS - Integrating SwiftLint for security checks
// .swiftlint.yml configuration
let swiftlintConfig = """
included:
  - Sources
  - Tests

excluded:
  - Carthage
  - Pods

opt_in_rules:
  - force_unwrapping
  - implicitly_unwrapped_optional
  - weak_delegate
  - private_outlet
  - prohibited_super_call

custom_rules:
  hardcoded_secret:
    name: "Hardcoded Secret"
    regex: '(api_key|apikey|password|secret|token)\s*=\s*"[^"]+"'
    message: "Hardcoded secrets should not be committed"
    severity: error
    
  insecure_random:
    name: "Insecure Random"
    regex: 'arc4random\(\)|rand\(\)|random\(\)'
    message: "Use SecRandomCopyBytes for cryptographic randomness"
    severity: warning
    
  disabled_ats:
    name: "Disabled ATS"
    regex: 'NSAllowsArbitraryLoads\s*</key>\s*<true/>'
    message: "App Transport Security should not be disabled"
    severity: error
"""

// Custom security analyzer
class SecurityAnalyzer {
    
    func analyzeProject(at path: String) -> AnalysisReport {
        var vulnerabilities: [Vulnerability] = []
        
        // Analyze Info.plist for security issues
        vulnerabilities.append(contentsOf: analyzeInfoPlist(at: path))
        
        // Analyze source code
        vulnerabilities.append(contentsOf: analyzeSourceCode(at: path))
        
        // Analyze project configuration
        vulnerabilities.append(contentsOf: analyzeProjectConfig(at: path))
        
        return AnalysisReport(
            projectPath: path,
            vulnerabilities: vulnerabilities,
            timestamp: Date()
        )
    }
    
    private func analyzeInfoPlist(at path: String) -> [Vulnerability] {
        var vulnerabilities: [Vulnerability] = []
        
        let plistPath = "\(path)/Info.plist"
        guard let plistData = try? Data(contentsOf: URL(fileURLWithPath: plistPath)),
              let plist = try? PropertyListSerialization.propertyList(from: plistData, format: nil) as? [String: Any] else {
            return vulnerabilities
        }
        
        // Check ATS configuration
        if let ats = plist["NSAppTransportSecurity"] as? [String: Any] {
            if ats["NSAllowsArbitraryLoads"] as? Bool == true {
                vulnerabilities.append(Vulnerability(
                    type: .configuration,
                    severity: .high,
                    description: "App Transport Security is disabled",
                    file: plistPath,
                    recommendation: "Enable ATS and use exception domains for specific requirements"
                ))
            }
        }
        
        // Check privacy permissions
        let privacyKeys = [
            "NSCameraUsageDescription",
            "NSMicrophoneUsageDescription",
            "NSLocationWhenInUseUsageDescription"
        ]
        
        for key in privacyKeys {
            if plist[key] == nil {
                vulnerabilities.append(Vulnerability(
                    type: .configuration,
                    severity: .medium,
                    description: "Missing privacy usage description for \(key)",
                    file: plistPath,
                    recommendation: "Add appropriate usage description for \(key)"
                ))
            }
        }
        
        return vulnerabilities
    }
}

Android Static Analysis Integration:

// Android - Custom Lint checks for security
package com.example.security.lint

import com.android.tools.lint.detector.api.*
import com.intellij.psi.PsiMethod
import org.jetbrains.uast.UCallExpression

class SecurityLintRegistry : IssueRegistry() {
    override val issues = listOf(
        HardcodedSecretDetector.ISSUE,
        InsecureRandomDetector.ISSUE,
        WeakCryptoDetector.ISSUE,
        InsecureStorageDetector.ISSUE
    )
    
    override val api = CURRENT_API
}

class HardcodedSecretDetector : Detector(), SourceCodeScanner {
    
    companion object {
        val ISSUE = Issue.create(
            id = "HardcodedSecret",
            briefDescription = "Hardcoded secret detected",
            explanation = "Hardcoded secrets in source code can be extracted from the APK",
            category = Category.SECURITY,
            priority = 9,
            severity = Severity.ERROR,
            implementation = Implementation(
                HardcodedSecretDetector::class.java,
                Scope.JAVA_FILE_SCOPE
            )
        )
    }
    
    override fun getApplicableMethodNames() = listOf(
        "putString",
        "getString",
        "setText"
    )
    
    override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
        val arguments = node.valueArguments
        
        for (arg in arguments) {
            val value = arg.evaluate()?.toString() ?: continue
            
            if (looksLikeSecret(value)) {
                context.report(
                    ISSUE,
                    node,
                    context.getLocation(arg),
                    "Potential hardcoded secret: ${value.take(10)}..."
                )
            }
        }
    }
    
    private fun looksLikeSecret(value: String): Boolean {
        val patterns = listOf(
            Regex(".*[Kk]ey.*=.*"),
            Regex(".*[Pp]assword.*=.*"),
            Regex(".*[Tt]oken.*=.*"),
            Regex(".*[Ss]ecret.*=.*"),
            Regex("[a-zA-Z0-9]{32,}") // Long random strings
        )
        
        return patterns.any { it.matches(value) }
    }
}

// Gradle integration
class SecurityGradlePlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.dependencies {
            add("lintChecks", project(":security-lint"))
        }
        
        project.android {
            lintOptions {
                isAbortOnError = true
                isWarningsAsErrors = true
                enable("HardcodedSecret")
                enable("InsecureRandom")
                enable("WeakCrypto")
                
                // Custom lint report
                htmlOutput = File("${project.buildDir}/reports/lint-security.html")
            }
        }
        
        // Add security check task
        project.tasks.register("securityCheck") {
            dependsOn("lint")
            
            doLast {
                println("Running security checks...")
                runAdditionalSecurityChecks(project)
            }
        }
    }
}