加密模式接入引导
加密模式是一项可选的安全增强功能。启用后,您的服务端需使用密钥(ekey)动态生成加密字符串,并传递给前端用于验证码初始化。该模式可有效防止因 sceneId 泄露而导致的服务盗用或恶意调用,从而提升接口安全性。
工作原理
服务端生成加密字符串:业务服务端使用从验证码控制台获取的密钥(ekey),将场景ID(
sceneId)、时间戳和有效期等信息加密,生成一个有时效性的加密字符串(EncryptedSceneId)。前端初始化验证码:前端从业务服务端获取该加密字符串,并在初始化验证码时将其作为参数传递。
验证码服务校验:验证码服务端接收到请求后,将使用在控制台开启的加密模式进行强制解密和安全校验。校验失败的请求将被拒绝。
步骤一:服务端生成加密字符串
获取密钥(ekey)
登录阿里云验证码控制台,在概览页面右上方区域,获取用于加密的密钥(ekey)。

构造待加密数据并执行加密
构造明文数据字符串。
数据格式:
sceneId×tamp&expireTime参数说明:
sceneId(String):验证码场景的唯一标识(原CaptchaAppid)。timestamp(Long):当前时间的 Unix 时间戳(单位:秒)。说明此时间戳不得晚于服务器接收请求的时间。
expireTime(Int):加密字符串的有效时长(单位:秒),取值范围为1至86400(即 1秒 至 24小时)。
数据示例:
sdewfwe&1712345678&3600
执行 AES-256 加密。
使用以下参数对上一步的明文字符串进行 AES 加密,得到加密后的字节数组( CaptchaSceneIdEncrypted)。
加密算法:AES
模式:CBC
填充方式:PKCS7Padding
密钥(Key):使用前面步骤获取的密钥(ekey)。
初始化向量(IV):一个随机生成的 16 字节数组。
重要为确保安全性,每次加密操作都必须使用一个全新的、通过密码学安全随机数生成器产生的 IV。严禁复用 IV。
拼接并进行 Base64 编码。
将 16 字节的 IV 与 AES 加密后的密文字节数组按顺序拼接。拼接格式:
IV+CaptchaSceneIdEncrypted,中间无连接符。对拼接后的字节数组进行 Base64 编码(标准编码,不含换行符)。
最终得到的字符串即为传递给前端的
EncryptedSceneId。
服务端代码示例 (Java)
以下示例展示了如何生成 EncryptedSceneId。
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 {
// IV 固定为 16 字节 (AES block size)
private static final int IV_LENGTH_BYTES = 16;
/**
* 对 sceneId 进行加密,生成 EncryptedSceneId
*
* @param sceneId 验证码业务标识(原 CaptchaAppid)
* @param ekeyStr 控制台获取的 ekey(作为密钥基础)
* @param expireTimeSec 密文过期时间,单位秒,范围 1~86400
* @return Base64 编码的字符串:EncryptedSceneId(IV + 加密数据)
* @throws Exception 加密过程中可能出现异常(如不支持的算法)
*/
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.");
}
// 获取当前时间戳(秒级)
long timestamp = Instant.now().getEpochSecond();
// ==================== 步骤 1: 构造密钥 Key(32字节) ====================
byte[] keyBytes = Base64.getDecoder().decode(ekeyStr);
// ==================== 步骤 2: 构造明文并执行 AES-256-CBC 加密 ====================
// 明文格式:sceneId×tamp&expireTime
String plaintext = sceneId + "&" + timestamp + "&" + expireTimeSec;
byte[] plaintextBytes = plaintext.getBytes(StandardCharsets.UTF_8);
// 创建 Cipher 实例:AES/CBC/PKCS7Padding
// 注意:Java 默认使用 PKCS5Padding,但其与 PKCS7 在 AES 中等价(块大小相同)
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // Java 不直接支持 PKCS7Padding,但行为一致
// 随机生成 16 字节 IV
SecureRandom random = new SecureRandom();
byte[] iv = new byte[IV_LENGTH_BYTES];
random.nextBytes(iv); // 安全随机填充 IV
IvParameterSpec ivSpec = new IvParameterSpec(iv);
// 使用 32 字节密钥初始化 SecretKeySpec
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
// 初始化 Cipher 为加密模式
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
// 执行加密,得到密文字节数组(即 CaptchaSceneIdEncrypted)
byte[] encryptedBytes = cipher.doFinal(plaintextBytes);
// ==================== 步骤 3: 拼接 IV + 密文,并进行 Base64 编码 ====================
// 创建一个新的字节数组:前 16 字节是 IV,后面是加密内容
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);
// Base64 编码,得到最终的 EncryptedSceneId
return Base64.getEncoder().encodeToString(result);
}
// ==================== 测试示例 ====================
public static void main(String[] args) {
try {
String sceneId = "s123456789"; // 替换为你的实际 sceneId
String ekey = "your_key"; // 替换为控制台获取的实际 AppSecretKey
int expireTimeSec = 3600; // 设置期望的有效期
String encryptedSceneId = encryptSceneId(sceneId, ekey, expireTimeSec);
System.out.println("EncryptedSceneId: " + encryptedSceneId);
System.out.println("Length: " + encryptedSceneId.length() + " characters");
// 示例输出(每次运行不同,因 IV 随机):
// EncryptedSceneId: YmFzZTY0RW5jb2RlZFN0cmluZzEyczM0dTV2Nnd4eXo=
} catch (Exception e) {
e.printStackTrace();
}
}
}
步骤二:前端集成
前端需先从业务服务端接口获取 EncryptedSceneId,然后在初始化验证码时传入该参数。
参数说明
参数 | 类型 | 是否必填 | 默认值 | 描述 |
| String | 否 | 无 | 加密后的 SceneId。创建验证场景后可获得原始 SceneId。使用控制台颁发的密钥(ekey),按照文档中的加密流程对该 SceneId 进行加密,最终得到的加密字符串即为加密后的 SceneId。 |
前端代码示例 (JavaScript)
// 1. 定义一个从您的业务后端获取加密字符串(EncryptedSceneId)的函数
const getEncryptedSceneId = async () => {
// 此处应调用您自己实现的后端接口
const response = await fetch('/api/encrypt-scene-id', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
});
// 假设后端返回JSON数据为:{ "EncryptedSceneId": "..." }
const { EncryptedSceneId } = await response.json();
return EncryptedSceneId;
};
// 2. 在初始化验证码时传入 EncryptedSceneId
const initCaptcha = async () => {
const encryptedId = await getEncryptedSceneId();
// 调用阿里云验证码初始化函数
window.initAliyunCaptcha({
// 场景ID。在新建验证场景后,可在验证码场景列表获取场景ID
SceneId: "******",
EncryptedSceneId: encryptedId,
// ... 其他初始化参数
});
};
// 执行初始化
initCaptcha();步骤三:在控制台开启校验
在完成前后端代码的开发和测试后,可在验证码控制台为相应场景开启加密模式。
登录阿里云验证码控制台,单击左侧导航栏的场景管理。
在场景管理页面,找到需要开启加密模式的目标场景,启用加密模式列下的开关。

开启后,验证码服务端将对所有传入 EncryptedSceneId 的请求执行以下强制校验:
解密是否成功。
sceneId是否合法。timestamp是否在允许的时间窗口内(防止重放攻击)。加密字符串是否在
expireTime定义的有效期内。
任何一项校验失败都会导致请求被拒绝。请务必在开启此开关前,确保您的服务端加密逻辑和前端集成已正确实现并完成测试。