Securing Your API: Leveraging HMAC to Ensure API Call Integrity using Java

In the rapidly evolving landscape of digital communication, securing APIs has become paramount to maintaining the integrity and security of data exchanges. APIs are the backbone of modern web services, enabling seamless interaction between different software components. However, their ubiquitous nature makes them prime targets for cyberattacks, particularly Man-in-the-Middle (MITM) attacks. These attacks can compromise the confidentiality, integrity, and availability of sensitive information, posing significant risks to organizations. Leveraging Hash-based Message Authentication Code (HMAC) for API security offers a robust solution.

Benefits of HMAC in API Security

Understanding HMAC for API Authentication

HMAC is a cryptographic mechanism that ensures data integrity and authenticity by generating a unique hash using a shared secret key. This method verifies that the request originates from a trusted source and ensures that the data has not been tampered with during transit. By implementing HMAC, organizations can fortify their APIs against MITM attacks, thus maintaining the fundamental cybersecurity principles of integrity and security.

Secure Your API Today! Request a Free Security Consultation

Preventing Man-in-the-Middle Attacks with HMAC

 Preventing Man-in-the-Middle Attacks with HMAC - MITM Attack Scenario

MITM Attack Scenario

Rahul, a dedicated mobile banking customer, relies on an app on his iPhone to manage his finances. Unfortunately, a cybercriminal has developed an iOS malware disguised as a popular game. Without suspecting anything, Rahul downloads the game, unknowingly allowing the malware to operate in the background, monitoring his banking app’s network activity.

During Rahul’s next interaction with his banking app, the malware intercepts and downgrades the SSL-encrypted connection. This breach enables the hacker to tamper with bill payments and transfer details, rerouting funds to his accounts without Rahul’s awareness. To cover his tracks, the hacker deletes any confirmation alerts to avoid raising suspicion. Through this deceitful mobile MITM attack, the hacker successfully siphons money from Rahul’s account.

HMAC-Enabled Communication: Securing API Calls

HMAC-Enabled Communication: Securing API Calls - HMAC Enabled Communication Scenario

HMAC Enabled Communication Scenario

By implementing HMAC-enabled API communication flow, we can ensure the integrity of API calls and effectively counter the aforementioned attack. Let’s delve deeper into the API communication process within an HMAC-enabled flow.

Implementing HMAC for Secure API Communication

In this section, we will explore the logic flow and provide sample code for generating HMAC.

1. Secret Key  

Create a robust shared “secret key” for both the client and server, ensuring secure storage and transmission. The client and server securely store the shared secret key, which is later used for HMAC encryption.

2. HMAC Signature Calculation

During each API call to the server, the client generates an HMAC signature of the payload (e.g., URL, request body, timestamp, configurable client type (web/ios/android), method type (POST, PUT, GET, DELETE)) using the shared secret key and a cryptographic hash function like SHA-256 or SHA-512. Include this HMAC signature in the request headers or as a separate parameter.

Visual Explanation for calculating HMAC for an API request

Visual Explanation for calculating HMAC for an API request

Notes on HMAC Calculation:

  1. When using the GET and DELETE methods, omit the MD5 hash of the request body from the payload before computing the HMAC for the rest of the payload.  
  1. Stringify (i.e., convert JSON to string) your request body before calculating its MD5 hash.

3. Server-Side HMAC Verification

At the server end, write an interceptor to verify the HMAC of every API request.

a. Intercept the request and extract the client’s HMAC signature, client type, and timestamp from the request headers.  

b. To create a payload for calculating the HMAC signature on the server end, use the following parameters:  

i. Client type (from request header)

ii. Timestamp (from request header)

iii. Request URL

iv. HTTP method type

v. MD5 hash of the request body if there is one (remember to stringify the request body on the server end before computing its MD5 hash, as done on the client’s end).

c. Calculate the SHA-512 hash for the created payload using the shared secret key and encode the hash into Base-64 format. 

d. Match the server and client’s HMAC signature to verify the integrity of the API request. If the signatures match, the request’s integrity is confirmed. If they do not match, the integrity of the API request is compromised.

4. Client-Side HMAC Verification  

During client-to-server communication, follow the steps to generate HMAC on the client’s end and verify it on server requests. For server-to-client communication, the process is reversed. In this case, the server creates an HMAC signature with each response, and the client then validates it.

 Best Practices for HMAC Implementation

5. Additional Steps to Enhance HMAC Protection  

a. Establish a timestamp expiry duration on both the client and server ends to safeguard against relay attacks. This involves extracting the timestamp from the response and request headers to validate whether it exceeds the permitted time limit.  

b. If there are any performance constraints, use SHA-256 instead of SHA-512 to calculate the hash. For example, SHA-256 is faster than SHA-512 in 32-bit systems. 32-bit implementations of SHA-512 are much slower than their 64-bit counterparts.  

c. The shared secret key is crucial in this process, serving as its lifeblood. Utilize appropriate key management systems to maintain its security. Regularly update these keys to enhance security measures.

Here Is An Example Of Java Code to Generate HMAC Using SHA-512

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class HmacGenerator {

    public static void main(String[] args) throws Exception {
        String requestBody = "{\"data\":\"value\"}";
        String clientType = "WEB";
        String methodType = "POST";
        String timestamp = "1720336959";
        String url = "https://api.example.com/endpoint";
        String secretKey = "Test_Secret_Key";

        String hmacSignature = generateHmacSignature(requestBody, clientType, methodType, timestamp, url, secretKey);
        System.out.println("HMAC Signature: " + hmacSignature);
    }

    public static String generateHmacSignature(String requestBody, String clientType, String methodType, String timestamp, String url, String secretKey) throws Exception {
        // Generate MD5 hash for requestBody
        String md5Hash = generateMD5Hash(requestBody);

        // Generate payload
        String payload = methodType + ";" + clientType + ";" + url + ";" + timestamp + ";" + md5Hash;

        // Generate HMAC signature
        return generateHMACSHA512Signature(payload, secretKey);
    }

    private static String generateMD5Hash(String data) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] digest = md.digest(data.getBytes(StandardCharsets.UTF_8));
        return bytesToHex(digest);
    }

    private static String generateHMACSHA512Signature(String data, String secretKey) throws Exception {
        Mac sha512Hmac = Mac.getInstance("HmacSHA512");
        SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA512");
        sha512Hmac.init(keySpec);
        byte[] hmacData = sha512Hmac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(hmacData);
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
}Code language: JavaScript (javascript)
Explore Our VAPT Services

Author's Bio

Swapnil Gawande
Swapnil Gawande

With over 2.5 years of industry experience, specializing in Java and the Spring Boot framework. He has worked extensively in the Transportation and SaaS domains, demonstrating strong logic-based problem-solving skills. Swapnil has successfully implemented numerous features from scratch across multiple projects. Additionally, he has hands-on experience in frontend web development and has contributed to open-source projects, further enhancing his well-rounded technical skill set.