Protecting Against API Abuse

Protecting Against API Abuse

Mobile APIs are vulnerable to various forms of abuse that must be mitigated.

// Android - API abuse prevention
class APIProtectionManager {
    
    // Implement request signing to prevent tampering
    class RequestSigner(private val apiSecret: String) {
        
        fun signRequest(request: Request): Request {
            val timestamp = System.currentTimeMillis()
            val nonce = UUID.randomUUID().toString()
            
            // Create canonical request string
            val canonicalRequest = buildCanonicalRequest(request, timestamp, nonce)
            
            // Generate signature
            val signature = generateSignature(canonicalRequest)
            
            // Add headers to request
            return request.newBuilder()
                .header("X-Timestamp", timestamp.toString())
                .header("X-Nonce", nonce)
                .header("X-Signature", signature)
                .build()
        }
        
        private fun buildCanonicalRequest(
            request: Request,
            timestamp: Long,
            nonce: String
        ): String {
            val method = request.method
            val path = request.url.encodedPath
            val query = request.url.encodedQuery ?: ""
            
            // Include body hash if present
            val bodyHash = request.body?.let { body ->
                val buffer = Buffer()
                body.writeTo(buffer)
                val bytes = buffer.readByteArray()
                
                MessageDigest.getInstance("SHA-256")
                    .digest(bytes)
                    .joinToString("") { "%02x".format(it) }
            } ?: ""
            
            return "$method\n$path\n$query\n$timestamp\n$nonce\n$bodyHash"
        }
        
        private fun generateSignature(canonicalRequest: String): String {
            val hmac = Mac.getInstance("HmacSHA256")
            val secretKey = SecretKeySpec(apiSecret.toByteArray(), "HmacSHA256")
            hmac.init(secretKey)
            
            val hash = hmac.doFinal(canonicalRequest.toByteArray())
            return Base64.encodeToString(hash, Base64.NO_WRAP)
        }
    }
    
    // Device attestation for API access
    class DeviceAttestationManager(private val context: Context) {
        
        fun generateAttestationToken(): String? {
            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                try {
                    // Use SafetyNet Attestation API
                    val nonce = generateNonce()
                    val client = SafetyNet.getClient(context)
                    
                    val task = client.attest(nonce, BuildConfig.SAFETY_NET_API_KEY)
                    val result = Tasks.await(task)
                    
                    // Send JWS result to server for verification
                    result.jwsResult
                } catch (e: Exception) {
                    null
                }
            } else {
                // Fallback for older devices
                generateBasicDeviceFingerprint()
            }
        }
        
        private fun generateNonce(): ByteArray {
            val nonce = ByteArray(32)
            SecureRandom().nextBytes(nonce)
            return nonce
        }
        
        private fun generateBasicDeviceFingerprint(): String {
            val fingerprint = StringBuilder()
            
            fingerprint.append(Build.MANUFACTURER).append("|")
            fingerprint.append(Build.MODEL).append("|")
            fingerprint.append(Build.VERSION.RELEASE).append("|")
            fingerprint.append(getAppSignature())
            
            return Base64.encodeToString(
                fingerprint.toString().toByteArray(),
                Base64.NO_WRAP
            )
        }
    }
}