Skip to main content

Secure Rest APIs with SHA-256 Cryptographic Hash Algorithm

Secure Rest APIs with SHA-256 Cryptographic Hash Algorithm

A cryptographic hash is an algorithm that takes required data to be encrypted and produces enciphered text called "hash". There are different algorithms available in which SHA-256 is way better because it produces a different hash every time even if the input is the same. SHA-256 is more secure and fast enough to be used to secure HTTP calls. So as an API owners, we always want to secure our API endpoints from being attacked. In this blog we will see how can a user securely call an API endpoint via adding a hash to the request header and how can an API owner verify that hash at his end. So let's start.

# Steps to secure an API request:

  • Generate your public and private key pair: Obtain your public/private key pair as an API user. Here we will use a private key to generate the hash value and sign the API request. A private key is shared only with the key creator and never be shared with anyone whereas the public key is sharable. Share this public key with the API gateway so that later on the gateway will use the User's public key to validate the hash.
  • Prepare the content to be hashed: Now we will collect a few properties of the API like HTTP method (GET/POST), HTTP URL, request time, and client id or API key of API gateway and then prepare the content to be hashed according to the syntax given below:
    {HTTP METHOD}+{HTTP URL}+{API REQUEST TIME}+{CLIENT ID}
  • Generate the hash using SHA256withRSA: After preparing the content that is to be hashed we will produce the actual hash using SHA256withRSA. Here I wrote a go function that is returning the hash value. 

  func CreateSignature(httpUrl string, httpMethod string, apiRequestTime string) string {
    //prepare rsa key
    PEMBlock, _ := pem.Decode([]byte(constants.PrivateKey))
    keyBytes, _ := x509.ParsePKCS8PrivateKey(PEMBlock.Bytes)
    privateKey, _ := keyBytes.(*rsa.PrivateKey)
    
    //prepare content to be hashed
    digestStr := httpMethod + ` ` + httpUrl + ` ` + apiRequestTime + ` ` + constants.ClientId
    contentToBeSigned := []byte(digestStr)

    //calculate the SHA256 checksum of the data
    digest := sha256.Sum256(contentToBeSigned)
    signature, _ := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, digest[:])
    encodedSignature := base64.StdEncoding.EncodeToString(signature)
    hash := url.QueryEscape(encodedSignature)
    
    //return final hash
    return hash
}
  • Add the hash to the request header: Now get the hash value returned from the above function and add it to the header of your request.
curl --location --request POST 'http://{api_url}' \
--header 'Signature: kMYkxXzFEX2zku7mkN8lSCR6yGuT1urXKGUU9NyxieSznkSsChAGo0n%2BqUQzYEcp9rnvEuz
0Y%2BHAl5X%2FSdhRa2mC%2FM%2BtrgmqJ8MEJCQPOXdag1xlV14kmhSbqfQOQx1evezzucbTLXI9BeIGWqPfw7o88xjbC
SKrhNEuDvtxvv0DXrRW%2B11My5%2BhSVm2P%2BqRIi9mF9WDhhtDnucY03cj%2BK4sUfeegh5z6x4ZTFw%2FqGJc4bfHO
%2F3iXN%2BUmb22bCIupDhejosrsi0%2BrrjKe9IR0eQ1D3VCoJNpJIwqdCyDHxNfShXyt5kEv8d7Bs4o0FDqlgJKmCyZs
xPJgzCAj1%2FgOg%3D%3D' \
--header 'Content-Type: application/json' \
--header 'Request-Time: 2022-03-16T07:39:55Z' \
--data-raw '{
    "user_name": "test",
}'

# Steps to validate a Hash:

  • Obtain the public key of the user: From the user who is using your API will provide his platform's public key which we will use further to. verify the hash present in the request header.
  • Prepare the content to be hashed: Now prepare the content that is being verified according to the syntax given below:
    {HTTP METHOD}+{HTTP URL}+{API REQUEST TIME}+{CLIENT ID}
  • Get the hash from the request header: Take out the hash string from the request header that is to be validated.           

Signature: kMYkxXzFEX2zku7mkN8lSCR6yGuT1urXKGUU9NyxieSznkSsChAGo0n%2BqUQzYEcp9rnvEuz
0Y%2BHAl5X%2FSdhRa2mC%2FM%2BtrgmqJ8MEJCQPOXdag1xlV14kmhSbqfQOQx1evezzucbTLXI9BeIGWqPfw7o88xjbC
SKrhNEuDvtxvv0DXrRW%2B11My5%2BhSVm2P%2BqRIi9mF9WDhhtDnucY03cj%2BK4sUfeegh5z6x4ZTFw%2FqGJc4bfHO
%2F3iXN%2BUmb22bCIupDhejosrsi0%2BrrjKe9IR0eQ1D3VCoJNpJIwqdCyDHxNfShXyt5kEv8d7Bs4o0FDqlgJKmCyZs
xPJgzCAj1%2FgOg%3D%3D 
  • Verify the hash:
func (validateSignature ValidateSignature) ValidateRequestSignature(headers map[string]string,
 httpUrl string, httpMethod string) (bool, error) {
    //prepare rsa key
    antVerifyKey := os.Getenv("PlatformPublicKey")
    antVerifyKey = strings.Replace(antVerifyKey, `\n`, "\n", 5)
    PEMBlock, _ := pem.Decode([]byte(antVerifyKey))
    keyBytes, _ := x509.ParsePKIXPublicKey(PEMBlock.Bytes)
    publicKey, _ := keyBytes.(*rsa.PublicKey)

    //decode hash
    urlDecodedHash, _ := url.QueryUnescape(headers["signature"])
    decodedHash, _ := base64.StdEncoding.DecodeString(urlDecodedHash)

    //create comparing string
    digestStr := httpMethod + ` ` + httpUrl + ` ` + headers["Request-Time"] + ` ` + constants.ClientId

    //calculate the SHA256 checksum of the data
    digest := sha256.Sum256([]byte(digestStr))

    //verify the hashed content
    verify := rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, digest[:], decodedHash)
    if verify != nil {
        return false, errors.InvalidSignature
    }
    return true, nil
}

Similarly, now as an API owner obtain your private/public keys and create a hash like we did for the request using the private key and add it to the response header of the API. When the user gets the response, he will again verify this hash with your public key.
That's it............. :)

Comments

Popular posts from this blog

How to Drag and drop canvas shapes with vue-konva | Interchange locations of two shapes by drag and drop

  Konva is a JavaScript library that supports animations, tweens, drawing many different shapes and designs, ready-to-use filters, node nesting, grouping, and bubbling on both desktop and mobile devices. It also supports native integration with web frameworks like React and Vue by exporting high-quality image data, image objects, and data URLs. In this blog, we will learn to draw different shapes using Konva and Nuxt.js and will make those shapes draggable and droppable. Installing VueKonva with npm: npm install vue-konva konva --save Import and use VueKonva: import Vue from 'vue'; import VueKonva from 'vue-konva' Vue.use(VueKonva) Create shapes with drag and drop: In the example below I tried to create a few shapes using Vue-Konva on konva stage. So initially we need to define the main template that will contain all HTML elements including the Konva Stage container. < template > < div > < button type = "button" class = ...

How OAuth 2.0 authorize mini-programs to access resources of native app

OAuth 2.0 is widely used in authentication and authorization that allows third-party applications to access resources that are hosted on other applications. OAuth 2.0 provides access to resources with some limitations to the client applications without sharing the actual credentials of the user. Here I will specify my own experience that how I implemented Oauth2 in our App. We implemented a few mini-programs in our app using a third-party mini-app container. Let's understand more about mini-programs and mini-app containers. Mini Programs: Mini programs are mini-apps or we can say independent child apps with limited features that run inside a parent app or bigger app. Mini programs can perform a variety of functions that can enhance native app features like food ordering, ticket booking, banking, chat, E-commerce, and promo codes and can take your small business app to the next level of growth. It allows 3rd parties to implement new features and services on your native app...