Client-Side Security Monitoring
Client-Side Security Monitoring
Mobile applications must implement client-side monitoring carefully to balance security visibility with performance and privacy.
iOS Security Monitoring Implementation:
// iOS - Comprehensive security monitoring
import Foundation
import os.log
import CryptoKit
class SecurityMonitoringService {
static let shared = SecurityMonitoringService()
private let securityLog = OSLog(subsystem: "com.app.security", category: "monitoring")
private let eventQueue = DispatchQueue(label: "security.monitoring", qos: .utility)
private var eventBuffer: [SecurityEvent] = []
private let bufferLimit = 100
// Security event types
enum SecurityEventType: String, CaseIterable {
case authenticationFailure = "auth_failure"
case authenticationSuccess = "auth_success"
case suspiciousActivity = "suspicious_activity"
case jailbreakDetected = "jailbreak_detected"
case debuggerAttached = "debugger_attached"
case certificatePinningFailure = "cert_pinning_failure"
case tamperingDetected = "tampering_detected"
case dataExfiltrationAttempt = "data_exfiltration"
case maliciousPayload = "malicious_payload"
case privilegeEscalation = "privilege_escalation"
}
// Monitor authentication events
func monitorAuthentication() {
NotificationCenter.default.addObserver(
self,
selector: #selector(handleAuthEvent),
name: .authenticationStatusChanged,
object: nil
)
// Monitor biometric authentication
BiometricAuthObserver.shared.onAuthAttempt = { [weak self] result in
self?.logSecurityEvent(
type: result.success ? .authenticationSuccess : .authenticationFailure,
details: [
"method": "biometric",
"error": result.error?.localizedDescription ?? ""
],
severity: result.success ? .info : .warning
)
}
}
// Runtime security monitoring
func startRuntimeMonitoring() {
// Jailbreak detection
Timer.scheduledTimer(withTimeInterval: 300, repeats: true) { [weak self] _ in
if JailbreakDetector.isJailbroken() {
self?.handleSecurityThreat(.jailbreakDetected)
}
}
// Debugger detection
DispatchQueue.global().async { [weak self] in
while true {
if DebuggerDetector.isDebuggerAttached() {
self?.handleSecurityThreat(.debuggerAttached)
}
Thread.sleep(forTimeInterval: 5)
}
}
// Hook detection
startHookDetection()
}
// Network security monitoring
class NetworkSecurityMonitor: URLProtocol {
override class func canInit(with request: URLRequest) -> Bool {
return true
}
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
// Monitor for suspicious requests
SecurityMonitoringService.shared.analyzeRequest(request)
return request
}
override func startLoading() {
// Monitor actual network traffic
let task = URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
guard let self = self else { return }
// Analyze response
if let httpResponse = response as? HTTPURLResponse {
SecurityMonitoringService.shared.analyzeResponse(
httpResponse,
data: data,
error: error
)
}
// Forward response
if let data = data {
self.client?.urlProtocol(self, didLoad: data)
}
if let response = response {
self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
}
if let error = error {
self.client?.urlProtocol(self, didFailWithError: error)
} else {
self.client?.urlProtocolDidFinishLoading(self)
}
}
task.resume()
}
override func stopLoading() {
// Clean up
}
}
// Behavioral analysis
class BehaviorAnalyzer {
private var userBehaviorProfile = UserBehaviorProfile()
private let anomalyDetector = AnomalyDetector()
func analyzeUserBehavior(event: UserEvent) {
// Update behavior profile
userBehaviorProfile.addEvent(event)
// Check for anomalies
if let anomaly = anomalyDetector.detectAnomaly(
event: event,
profile: userBehaviorProfile
) {
SecurityMonitoringService.shared.logSecurityEvent(
type: .suspiciousActivity,
details: [
"anomaly_type": anomaly.type.rawValue,
"confidence": anomaly.confidence,
"description": anomaly.description
],
severity: anomaly.severity
)
}
}
// Machine learning-based anomaly detection
func trainAnomalyDetectionModel() {
let trainingData = collectTrainingData()
// Use Core ML for on-device anomaly detection
let model = try? UserBehaviorAnomalyDetector(
configuration: MLModelConfiguration()
)
anomalyDetector.updateModel(model)
}
}
// Security event logging
func logSecurityEvent(
type: SecurityEventType,
details: [String: Any],
severity: SecuritySeverity
) {
let event = SecurityEvent(
id: UUID().uuidString,
timestamp: Date(),
type: type,
details: details,
severity: severity,
deviceInfo: collectDeviceInfo(),
appInfo: collectAppInfo()
)
eventQueue.async { [weak self] in
self?.processSecurityEvent(event)
}
}
private func processSecurityEvent(_ event: SecurityEvent) {
// Add to buffer
eventBuffer.append(event)
// Local logging
os_log(
"%{public}@: %{public}@",
log: securityLog,
type: event.severity.osLogType,
event.type.rawValue,
event.details.description
)
// Check if immediate reporting needed
if event.severity == .critical || eventBuffer.count >= bufferLimit {
reportSecurityEvents()
}
}
// Secure event transmission
private func reportSecurityEvents() {
guard !eventBuffer.isEmpty else { return }
let events = eventBuffer
eventBuffer.removeAll()
// Encrypt events
let encryptedPayload = encryptEvents(events)
// Send to security backend
SecurityAPIClient.shared.reportEvents(encryptedPayload) { [weak self] result in
switch result {
case .success:
// Successfully reported
break
case .failure(let error):
// Re-queue events for retry
self?.eventQueue.async {
self?.eventBuffer.insert(contentsOf: events, at: 0)
}
os_log("Failed to report security events: %{public}@",
log: self?.securityLog ?? .default,
type: .error,
error.localizedDescription)
}
}
}
private func encryptEvents(_ events: [SecurityEvent]) -> Data {
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
guard let jsonData = try? encoder.encode(events) else {
return Data()
}
// Encrypt with app-specific key
let key = getSecurityReportingKey()
guard let sealedBox = try? AES.GCM.seal(jsonData, using: key) else {
return Data()
}
return sealedBox.combined ?? Data()
}
}
// Security event structure
struct SecurityEvent: Codable {
let id: String
let timestamp: Date
let type: SecurityMonitoringService.SecurityEventType
let details: [String: Any]
let severity: SecuritySeverity
let deviceInfo: DeviceInfo
let appInfo: AppInfo
struct DeviceInfo: Codable {
let deviceId: String
let model: String
let osVersion: String
let isJailbroken: Bool
let isVPNActive: Bool
}
struct AppInfo: Codable {
let version: String
let buildNumber: String
let installDate: Date
let lastUpdateDate: Date
}
}
enum SecuritySeverity: String, Codable {
case info, warning, error, critical
var osLogType: OSLogType {
switch self {
case .info: return .info
case .warning: return .default
case .error: return .error
case .critical: return .fault
}
}
}
Android Security Monitoring Implementation:
// Android - Production security monitoring
class SecurityMonitoringService(private val context: Context) {
companion object {
private const val TAG = "SecurityMonitoring"
private const val BUFFER_SIZE = 100
private const val REPORT_INTERVAL = 5 * 60 * 1000L // 5 minutes
}
private val securityEventBuffer = Collections.synchronizedList(
mutableListOf<SecurityEvent>()
)
private val analyticsEngine = SecurityAnalyticsEngine(context)
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
init {
startMonitoring()
}
private fun startMonitoring() {
// Start all monitoring components
startAuthenticationMonitoring()
startNetworkMonitoring()
startAppIntegrityMonitoring()
startBehaviorMonitoring()
startPeriodicReporting()
}
// Authentication monitoring
private fun startAuthenticationMonitoring() {
AuthenticationManager.getInstance().addAuthListener { event ->
when (event) {
is AuthEvent.LoginAttempt -> {
logSecurityEvent(
SecurityEvent(
type = if (event.success) EventType.AUTH_SUCCESS else EventType.AUTH_FAILURE,
timestamp = System.currentTimeMillis(),
details = mapOf(
"method" to event.method,
"user_id" to event.userId.hashCode().toString(),
"ip_address" to event.ipAddress
),
severity = if (event.success) Severity.INFO else Severity.WARNING
)
)
// Check for brute force attempts
if (detectBruteForce(event.userId)) {
handleSecurityIncident(
SecurityIncident(
type = IncidentType.BRUTE_FORCE,
severity = Severity.HIGH,
userId = event.userId
)
)
}
}
is AuthEvent.SessionExpired -> {
logSecurityEvent(
SecurityEvent(
type = EventType.SESSION_EXPIRED,
timestamp = System.currentTimeMillis(),
severity = Severity.INFO
)
)
}
}
}
}
// Network security monitoring
private fun startNetworkMonitoring() {
// OkHttp interceptor for monitoring
val networkMonitorInterceptor = object : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val startTime = System.currentTimeMillis()
// Pre-request analysis
analyzeOutgoingRequest(request)
return try {
val response = chain.proceed(request)
val duration = System.currentTimeMillis() - startTime
// Post-response analysis
analyzeResponse(request, response, duration)
response
} catch (e: Exception) {
// Network failure analysis
analyzeNetworkFailure(request, e)
throw e
}
}
}
// Certificate pinning monitor
CertificatePinningMonitor.setListener { host, error ->
logSecurityEvent(
SecurityEvent(
type = EventType.CERT_PINNING_FAILURE,
timestamp = System.currentTimeMillis(),
details = mapOf(
"host" to host,
"error" to error.message
),
severity = Severity.CRITICAL
)
)
// Potential MITM attack
handleSecurityIncident(
SecurityIncident(
type = IncidentType.POTENTIAL_MITM,
severity = Severity.CRITICAL,
details = mapOf("host" to host)
)
)
}
}
// App integrity monitoring
private fun startAppIntegrityMonitoring() {
scope.launch {
while (isActive) {
// Check app signature
if (!verifyAppSignature()) {
handleSecurityIncident(
SecurityIncident(
type = IncidentType.APP_TAMPERING,
severity = Severity.CRITICAL
)
)
}
// Check for root
if (RootDetector.isDeviceRooted()) {
logSecurityEvent(
SecurityEvent(
type = EventType.ROOT_DETECTED,
timestamp = System.currentTimeMillis(),
severity = Severity.HIGH
)
)
}
// Check for debugging
if (Debug.isDebuggerConnected()) {
handleSecurityIncident(
SecurityIncident(
type = IncidentType.DEBUGGER_ATTACHED,
severity = Severity.HIGH
)
)
}
// Check for hooks
if (detectRuntimeHooks()) {
handleSecurityIncident(
SecurityIncident(
type = IncidentType.RUNTIME_MANIPULATION,
severity = Severity.CRITICAL
)
)
}
delay(60000) // Check every minute
}
}
}
// Behavioral monitoring
private fun startBehaviorMonitoring() {
val behaviorAnalyzer = UserBehaviorAnalyzer(context)
// Monitor app usage patterns
ActivityLifecycleMonitor.getInstance().addLifecycleCallback { activity, stage ->
behaviorAnalyzer.recordActivity(
UserActivity(
activityName = activity.javaClass.simpleName,
stage = stage,
timestamp = System.currentTimeMillis()
)
)
}
// Monitor data access patterns
DataAccessMonitor.setListener { dataType, amount ->
if (behaviorAnalyzer.isAnomalousDataAccess(dataType, amount)) {
logSecurityEvent(
SecurityEvent(
type = EventType.ANOMALOUS_DATA_ACCESS,
timestamp = System.currentTimeMillis(),
details = mapOf(
"data_type" to dataType,
"amount" to amount.toString()
),
severity = Severity.HIGH
)
)
}
}
// Monitor permission usage
PermissionMonitor.trackPermissionUsage { permission, frequency ->
if (behaviorAnalyzer.isAnomalousPermissionUsage(permission, frequency)) {
logSecurityEvent(
SecurityEvent(
type = EventType.SUSPICIOUS_PERMISSION_USE,
timestamp = System.currentTimeMillis(),
details = mapOf(
"permission" to permission,
"frequency" to frequency.toString()
),
severity = Severity.MEDIUM
)
)
}
}
}
// Real-time threat detection
inner class ThreatDetectionEngine {
private val threatPatterns = loadThreatPatterns()
private val mlModel = loadMLModel()
fun analyzeForThreats(event: SecurityEvent): ThreatAssessment {
// Rule-based detection
val ruleBasedThreats = threatPatterns
.filter { pattern -> pattern.matches(event) }
.map { pattern ->
Threat(
type = pattern.threatType,
confidence = pattern.confidence,
description = pattern.description
)
}
// ML-based detection
val mlThreats = mlModel.predict(event.toFeatureVector())
.filter { prediction -> prediction.confidence > 0.7 }
.map { prediction ->
Threat(
type = prediction.threatType,
confidence = prediction.confidence,
description = "ML-detected: ${prediction.threatType}"
)
}
// Combine and deduplicate
val allThreats = (ruleBasedThreats + mlThreats)
.distinctBy { it.type }
.sortedByDescending { it.confidence }
return ThreatAssessment(
threats = allThreats,
overallRisk = calculateOverallRisk(allThreats),
recommendedActions = determineActions(allThreats)
)
}
}
// Incident response
private fun handleSecurityIncident(incident: SecurityIncident) {
scope.launch {
// Immediate response
when (incident.type) {
IncidentType.BRUTE_FORCE -> {
// Lock account
AccountManager.lockAccount(incident.userId)
}
IncidentType.APP_TAMPERING -> {
// Disable sensitive features
FeatureManager.disableSensitiveFeatures()
// Alert user
showSecurityAlert("Security Warning",
"App integrity compromised. Please reinstall from official store.")
}
IncidentType.POTENTIAL_MITM -> {
// Terminate all network connections
NetworkManager.terminateAllConnections()
// Force re-authentication
AuthenticationManager.forceReauthentication()
}
IncidentType.DATA_EXFILTRATION -> {
// Block data access
DataAccessManager.blockAllAccess()
// Wipe sensitive data
SecureStorage.wipeAll()
}
}
// Report incident
reportSecurityIncident(incident)
// Update threat model
ThreatModelManager.updateModel(incident)
}
}
// Secure reporting
private suspend fun reportSecurityEvents() {
if (securityEventBuffer.isEmpty()) return
val events = securityEventBuffer.toList()
securityEventBuffer.clear()
try {
// Prepare secure payload
val payload = SecurityPayload(
events = events,
deviceFingerprint = generateDeviceFingerprint(),
timestamp = System.currentTimeMillis(),
signature = signPayload(events)
)
// Encrypt payload
val encryptedPayload = SecurityEncryption.encrypt(payload)
// Send to security backend
val response = SecurityAPI.reportEvents(encryptedPayload)
if (response.isSuccessful) {
// Process server instructions
response.body()?.let { instructions ->
processServerInstructions(instructions)
}
} else {
// Re-queue events
securityEventBuffer.addAll(events)
}
} catch (e: Exception) {
Log.e(TAG, "Failed to report security events", e)
// Re-queue events
securityEventBuffer.addAll(events)
}
}
data class SecurityEvent(
val type: EventType,
val timestamp: Long,
val details: Map<String, String> = emptyMap(),
val severity: Severity
)
enum class EventType {
AUTH_SUCCESS,
AUTH_FAILURE,
SESSION_EXPIRED,
CERT_PINNING_FAILURE,
ROOT_DETECTED,
ANOMALOUS_DATA_ACCESS,
SUSPICIOUS_PERMISSION_USE,
NETWORK_ANOMALY
}
}