You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何校验RESTful接口仅被Android应用调用而非CURL、Postman等工具

技术实现方案

1. 核心请求签名校验机制

  • 客户端预埋专属密钥:给每个合法Android版本分配独有的AppSecret,打包时编译进APK的so库中,不要硬编码在Java/Kotlin层避免反编译直接获取
  • 签名规则统一:客户端每次发起请求时,将请求路径+请求参数+当前时间戳+设备唯一标识+AppSecret拼接后做SHA256加密生成签名字段,和时间戳、设备标识一起放在自定义请求头里传输
  • 服务端校验逻辑:Quarkus端编写全局拦截器,收到请求后首先判断请求携带的时间戳和服务器时间差是否超过5分钟(防止重放攻击),再用完全相同的规则生成签名和请求头携带的签名比对,不一致直接返回403

2. Android应用身份合法性校验

  • 包名+签名证书指纹校验:客户端请求时上报APK的包名和签名证书的SHA256指纹,服务端提前存储官方应用的包名和指纹白名单,比对不通过直接拦截

注意:指纹获取逻辑要放在native层实现,避免被篡改后上报假的指纹信息

3. 运行环境安全校验

  • 客户端在发起请求前先做运行环境检测:包括是否是模拟器、是否被Xposed/Frida等Hook工具注入、是否被二次打包,检测到风险环境直接拒绝发起请求
  • 可叠加自定义UA校验,设置专属的UA规则,不符合规则的请求直接拦截,该规则为基础防护,不可单独作为校验依据

4. Quarkus服务端落地实现

可以通过JAX-RS全局请求拦截器实现所有校验逻辑,示例代码如下:

@Provider
@PreMatching
public class OfficialAppRequestFilter implements ContainerRequestFilter {
    // 提前配置好的官方App白名单、AppSecret等信息,可放到Quarkus配置文件中
    private static final Set<String> VALID_PACKAGE_NAMES = Set.of("com.你的官方应用包名");
    private static final Set<String> VALID_CERT_FINGERPRINTS = Set.of("你的官方签名证书SHA256指纹");
    private static final String APP_SECRET = "预埋到客户端so库的专属密钥";

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        // 1. 提取自定义请求头参数
        String timestamp = requestContext.getHeaderString("X-App-Timestamp");
        String signature = requestContext.getHeaderString("X-App-Signature");
        String packageName = requestContext.getHeaderString("X-App-Package");
        String certFingerprint = requestContext.getHeaderString("X-App-Cert-Fingerprint");
        String deviceId = requestContext.getHeaderString("X-App-Device-Id");

        // 基础参数非空校验
        if (Stream.of(timestamp, signature, packageName, certFingerprint, deviceId).anyMatch(Objects::isNull)) {
            requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
            return;
        }

        // 2. 时间差校验,防止重放攻击
        long reqTime = Long.parseLong(timestamp);
        if (Math.abs(System.currentTimeMillis() - reqTime) > 5 * 60 * 1000) {
            requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
            return;
        }

        // 3. 包名和证书指纹校验
        if (!VALID_PACKAGE_NAMES.contains(packageName) || !VALID_CERT_FINGERPRINTS.contains(certFingerprint)) {
            requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
            return;
        }

        // 4. 签名校验(请求体需要提前做缓存处理,避免流被消费后后续接口无法读取)
        String rawSignContent = requestContext.getUriInfo().getPath() + 
                                缓存的请求体字符串 + 
                                timestamp + 
                                deviceId + 
                                APP_SECRET;
        String serverSign = DigestUtils.sha256Hex(rawSignContent);
        if (!serverSign.equals(signature)) {
            requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
            return;
        }
    }
}

5. 补充防护建议

  • 所有接口必须走HTTPS传输,防止中间人抓包篡改请求头和参数
  • 密钥和签名规则定期迭代更新,App端通过热更或者版本强制升级适配新规则
  • 增加异常请求频率限制,短时间内多次校验失败的IP直接封禁一段时间,防止暴力破解

内容的提问来源于stack exchange,提问作者Prakash Dutta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 04:06:03