Security Best Practices
Relevant source files
The following files were used as context for generating this wiki page:The security model for this ZaloPay integration is centered around ensuring the authenticity and integrity of data exchanged between the application and the ZaloPay payment gateway. This is achieved through a symmetric key cryptographic signature mechanism, specifically HMAC-SHA256. Every request sent to ZaloPay and every callback received must be properly signed and verified to prevent tampering and unauthorized actions.
The core principle is that both the application and ZaloPay share secret keys. These keys are used to generate a Message Authentication Code (MAC) for each transaction. By verifying this MAC, both parties can be certain that the message originated from the expected sender and has not been altered in transit.
Core Security Components
The security framework is built upon three key components: configuration management for secret keys, a dedicated HMAC generation module, and utility functions for creating unique transaction identifiers.
Configuration Management
All security-related configurations, including secret keys and API endpoints, are centralized in a single configuration object. This ensures that sensitive values are managed in one place and can be easily loaded from a secure source.
Sources: common/zalo_pay_config.py
The ZaloPayConfig dictionary holds the essential parameters for interacting with the ZaloPay API.
| Key | Description |
|---|---|
app_id | The application's unique identifier provided by ZaloPay. |
key1 | The secret key used for generating the HMAC signature for requests sent to ZaloPay. |
key2 | The secret key used for verifying the HMAC signature for callbacks received from ZaloPay. |
endpoint | The base URL for the ZaloPay API endpoint. |
It is critical that key1 and key2 are treated as highly sensitive secrets. They should never be hardcoded in source control and should instead be loaded from secure environment variables or a secret management system in a production environment.
Sources: common/zalo_pay_config.py:3-8
HMAC Signature Generation
The HMac class is responsible for generating the HMAC-SHA256 signature (mac) required for all API requests. It takes the secret key and the data to be signed as input and produces a hexadecimal digest.
Sources: common/hmac.py
The following diagram illustrates the signature generation process within the HMac.compute method.
This flowchart shows the steps taken by the HMac.compute method to create a signature for outgoing requests. Sources: common/hmac.py:6-9
The implementation uses Python's built-in hmac and hashlib libraries.
# common/hmac.py:6-9
class HMac:
def compute(self, data, key):
return hmac.new(key.encode(), data.encode(), hashlib.sha256).hexdigest()
Sources: common/hmac.py:6-9
Unique Transaction Identifiers
To prevent replay attacks, where an attacker could intercept and resend a valid request, each order creation request must have a unique transaction identifier. The get_app_trans_id utility function is used for this purpose. It generates an ID based on the current timestamp, ensuring a high degree of uniqueness for each transaction.
# common/utils.py:4-6
def get_app_trans_id():
now = datetime.now()
return now.strftime("%y%m%d") + "_" + str(round(now.timestamp() * 1000))
Sources: common/utils.py:4-6
Secure Transaction Flows
The core security components are utilized in every interaction with the ZaloPay API, such as creating an order or querying its status.
Order Creation Request
When creating a new payment order, the application gathers all required parameters, constructs a data string, and uses key1 to generate an HMAC signature. This signature is sent in the mac field of the request body.
Sources: services/order.py, common/hmac.py, common/zalo_pay_config.py
The sequence diagram below details the steps involved in creating a secure order.
This diagram shows the end-to-end flow for creating a ZaloPay order, including the crucial HMAC signing step. Sources: services/order.py:10-25
The data string for signing is a concatenation of specific fields separated by a | delimiter. The order of these fields is critical and must match the order expected by ZaloPay.
Sources: services/order.py:19
Order Status Query
A similar security process is followed when querying the status of an existing transaction. A data string is constructed using the app_id and app_trans_id, and it is signed using key1.
Sources: services/get_status_order.py
The data string for a status query is simpler but follows the same principle:
data = ZaloPayConfig["app_id"] + "|" + app_trans_id + "|" + ZaloPayConfig["key1"]
This request is then sent to the ZaloPay query endpoint to securely retrieve the transaction status.
Sources: services/get_status_order.py:10-17
Callback Verification
While the provided code primarily focuses on sending requests, the configuration explicitly includes key2 for verifying callbacks from ZaloPay. This is a critical security practice to ensure that notifications received from ZaloPay (e.g., confirming a successful payment) are authentic and have not been spoofed.
The comment in the configuration file clarifies its purpose: key2 để ZaloPay server callback.
Sources: common/zalo_pay_config.py:6
The following flowchart illustrates the recommended process for handling an incoming callback from ZaloPay.
This flowchart shows the necessary steps to securely verify an incoming webhook notification from ZaloPay using key2. Sources: common/zalo_pay_config.py:6
Summary
The security of the ZaloPay integration relies on the correct and consistent application of HMAC-SHA256 signatures. The effectiveness of this model is entirely dependent on developers adhering to several key practices:
- Secret Key Protection:
key1andkey2must be stored securely and never exposed in client-side code or committed to version control. - Signature on Outgoing Requests: All requests sent to the ZaloPay API must include a valid
macfield generated withkey1. - Verification of Incoming Callbacks: All callbacks received from ZaloPay must be verified by re-computing the signature with
key2and comparing it to the one provided. - Use of Unique Identifiers: Employ unique transaction IDs for each order to mitigate replay attacks.