V3 architecture Encryption Mode
Encryption Mode adds a server-side layer of protection to your CAPTCHA integration. Instead of passing the sceneId directly to the frontend, your server encrypts it into a short-lived token (EncryptedSceneId) that the CAPTCHA service validates on every request. This prevents abuse from a leaked sceneId.
Encryption Mode applies to CAPTCHA V3 architecture only. V2 architecture does not require it because verification is initiated server-side.
How it works
Server encrypts the scene ID. Your server uses the Encrypt Key (ekey) from the console to produce a time-limited encrypted string (
EncryptedSceneId). The plaintext encodes thesceneId, the current timestamp, and a validity period.Frontend passes the token. The frontend fetches
EncryptedSceneIdfrom your server and passes it toinitAliyunCaptcha.CAPTCHA service validates the token. After Encryption Mode is enabled in the console, the CAPTCHA server decrypts and checks every request that includes
EncryptedSceneId. Requests that fail any check are rejected.
Prerequisites
Before you begin, ensure that you have:
Completed basic CAPTCHA integration (frontend and backend)
Access to the Alibaba Cloud Captcha console
The
sceneIdfor the target CAPTCHA scenario
Step 1: Generate an encrypted string on the server
Get the Encrypt Key (ekey)
Log in to the Alibaba Cloud Captcha console. In the upper-right area of the Overview page, copy the Encrypt Key (ekey).
Construct and encrypt the plaintext
1. Build the plaintext string.
Concatenate the three fields with & as the delimiter:
sceneId×tamp&expireTime| Field | Type | Description |
|---|---|---|
sceneId | String | Unique identifier for the CAPTCHA scenario. Formerly known as CaptchaAppid. |
timestamp | Long | Current UNIX timestamp in seconds. Must not be later than the time the server receives the request. |
expireTime | Int | Validity period in seconds. Accepted range: 1–86400 (1 second to 24 hours). |
Example plaintext:
sdewfwe&1712345678&36002. Encrypt with AES-256-CBC.
Apply AES encryption to the plaintext string using the following parameters:
| Parameter | Value |
|---|---|
| Algorithm | AES (Advanced Encryption Standard)-256 |
| Mode | CBC (Cipher Block Chaining) |
| Padding | PKCS7Padding |
| Key | The Encrypt Key (ekey) from the console |
| Initialization Vector (IV) | A randomly generated 16-byte array |
The output is an encrypted byte array (CaptchaSceneIdEncrypted).
Generate a new IV using a cryptographically secure random number generator for every encryption call. Never reuse IVs.
3. Concatenate and Base64-encode.
Concatenate the 16-byte IV and
CaptchaSceneIdEncryptedin order, with no separator:IV + CaptchaSceneIdEncrypted.Base64-encode the concatenated byte array using standard encoding without line feeds.
The resulting string is EncryptedSceneId.
Java code example
The following example generates an EncryptedSceneId using AES-256-CBC encryption.
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.time.Instant;
import java.util.Base64;
public class SceneIdEncryptor {
// The IV is a fixed length of 16 bytes (AES block size).
private static final int IV_LENGTH_BYTES = 16;
/**
* Encrypts the sceneId to generate an EncryptedSceneId.
*
* @param sceneId The CAPTCHA scenario identifier (formerly CaptchaAppid).
* @param ekeyStr The ekey from the console (used as the encryption key).
* @param expireTimeSec The validity period in seconds. Must be between 1 and 86400.
* @return A Base64-encoded string: EncryptedSceneId (IV + encrypted data).
* @throws Exception Thrown for unsupported algorithms or other encryption errors.
*/
public static String encryptSceneId(String sceneId, String ekeyStr, int expireTimeSec) throws Exception {
if (expireTimeSec <= 0 || expireTimeSec > 86400) {
throw new IllegalArgumentException("expireTimeSec must be between 1 and 86400 seconds.");
}
// Get the current timestamp in seconds.
long timestamp = Instant.now().getEpochSecond();
// Step 1: Decode the ekey into a 32-byte key.
byte[] keyBytes = Base64.getDecoder().decode(ekeyStr);
// Step 2: Build the plaintext and encrypt with AES-256-CBC.
// Plaintext format: sceneId×tamp&expireTime
String plaintext = sceneId + "&" + timestamp + "&" + expireTimeSec;
byte[] plaintextBytes = plaintext.getBytes(StandardCharsets.UTF_8);
// Java uses PKCS5Padding, which is equivalent to PKCS7Padding for AES.
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Generate a cryptographically secure random 16-byte IV.
SecureRandom random = new SecureRandom();
byte[] iv = new byte[IV_LENGTH_BYTES];
random.nextBytes(iv);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
byte[] encryptedBytes = cipher.doFinal(plaintextBytes);
// Step 3: Concatenate IV + ciphertext, then Base64-encode.
byte[] result = new byte[IV_LENGTH_BYTES + encryptedBytes.length];
System.arraycopy(iv, 0, result, 0, IV_LENGTH_BYTES);
System.arraycopy(encryptedBytes, 0, result, IV_LENGTH_BYTES, encryptedBytes.length);
return Base64.getEncoder().encodeToString(result);
}
public static void main(String[] args) {
try {
String sceneId = "s123456789"; // Replace with your actual sceneId.
String ekey = "<your-ekey>"; // Replace with the ekey from the console.
int expireTimeSec = 3600; // Set the desired validity period.
String encryptedSceneId = encryptSceneId(sceneId, ekey, expireTimeSec);
System.out.println("EncryptedSceneId: " + encryptedSceneId);
// Output differs on each run because the IV is randomly generated.
} catch (Exception e) {
e.printStackTrace();
}
}
}Replace the following placeholder before running the example:
| Placeholder | Description |
|---|---|
<your-ekey> | The Encrypt Key (ekey) from the Alibaba Cloud Captcha console |
Step 2: Pass the encrypted string from the frontend
Before initializing the CAPTCHA, fetch EncryptedSceneId from your server and pass it as a parameter to initAliyunCaptcha.
EncryptedSceneId parameter
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
EncryptedSceneId | String | No | None | The encrypted scene ID generated by your server. |
JavaScript code example
// Fetch the EncryptedSceneId from your backend.
const getEncryptedSceneId = async () => {
const response = await fetch('/api/encrypt-scene-id', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
});
// Backend returns JSON: { "EncryptedSceneId": "..." }
const { EncryptedSceneId } = await response.json();
return EncryptedSceneId;
};
// Initialize the CAPTCHA with the encrypted scene ID.
const initCaptcha = async () => {
const encryptedId = await getEncryptedSceneId();
window.initAliyunCaptcha({
SceneId: '<your-scene-id>', // The scene ID from the Captcha console.
EncryptedSceneId: encryptedId,
// ... other initialization parameters
});
};
initCaptcha();Replace the following placeholder before using this example:
| Placeholder | Description |
|---|---|
<your-scene-id> | The scene ID from the scenario list in the Alibaba Cloud Captcha console |
Step 3: Enable Encryption Mode in the console
After you develop and test the frontend and backend code, you can enable Encryption Mode for the corresponding scenario in the Captcha console.
Log in to the Alibaba Cloud Captcha console. In the left navigation pane, click Scenarios.
On the Scenarios page, find the target scenario and turn on the switch in the Encryption Mode column.
After enabling Encryption Mode, the CAPTCHA server performs the following mandatory checks on all requests that include an EncryptedSceneId:
Decryption succeeds using the registered ekey.
The
sceneIdis valid.The
timestampfalls within the allowed time window (prevents replay attacks).The encrypted string is within the validity period defined by
expireTime.
Any request that fails a check is rejected.
Before you enable this switch, ensure that your server-side encryption logic and frontend integration are correctly implemented and fully tested.
Security checklist
Before going live with Encryption Mode, verify the following:
[ ] Generate a fresh IV per request. Never reuse initialization vectors. Use
SecureRandom(Java) or an equivalent cryptographically secure generator in your language.[ ] Keep the ekey secret. Store it as an environment variable or in a secrets manager. Never expose it in client-side code.
[ ] Set an appropriate validity period. Keep
expireTimeas short as practical for your use case to limit the exposure window if a token is intercepted.[ ] Test before enabling. Verify that your encryption logic produces valid tokens before turning on the console switch.
[ ] Monitor for rejections. After enabling, watch for unexpected request rejections that may indicate a configuration mismatch between your server and the CAPTCHA service.