Skip to content

简单鉴权

本文档定义基于secret的轻量级鉴权方案,适用于MQTT over TLS环境。

设计目标

  • 极简实现:设备端仅需字符串比对
  • 零依赖:不需要加密库
  • 易调试:请求内容明文可读

前置条件

  1. MQTT必须使用TLS:secret明文传输,依赖TLS保护
  2. 设备已持有secret:通过GATT配网获得

请求格式

MessagePending基础上增加secret字段:

json
{
  "sender": "app-001",
  "receiver": "device-001",
  "msg_id": "550e8400-e29b-41d4-a716-446655440000",
  "action": "unlock",
  "time": 1700000000,
  "exp": 1700000060,
  "secret": "550e8400-e29b-41d4-a716-446655440000",
  "value": {"door": "front"}
}
字段类型必填说明
secretstring设备凭证,配网时获得

验证流程

验证步骤

  1. 验证secret:与本地存储的secret比对
  2. 防重放:检查msg_id是否已处理过
  3. 检查过期:当前时间是否超过exp
  4. 缓存msg_id:记录已处理的msg_id(用于防重放)

防重放机制

设备端维护已处理msg_id缓存:

  • 缓存内容:msg_id + exp
  • 缓存清理:定期清理已过期的msg_id
  • 内存估算:按60秒过期、每秒1请求,约60个UUID ≈ 2KB
c
// 伪代码
typedef struct {
    char msg_id[37];
    int64_t exp;
} processed_msg_t;

processed_msg_t msg_cache[MAX_CACHE_SIZE];

bool is_duplicate(const char* msg_id) {
    for (int i = 0; i < cache_count; i++) {
        if (strcmp(msg_cache[i].msg_id, msg_id) == 0) {
            return true;
        }
    }
    return false;
}

响应格式

成功:按业务返回MessageComplete

鉴权失败

json
{
  "msg_id": "550e8400-e29b-41d4-a716-446655440000",
  "error": "invalid_secret"
}

重复请求

json
{
  "msg_id": "550e8400-e29b-41d4-a716-446655440000",
  "error": "duplicate_request"
}

请求过期

json
{
  "msg_id": "550e8400-e29b-41d4-a716-446655440000",
  "error": "request_expired"
}

实现示例

C语言(设备端)

c
#include <string.h>
#include <stdbool.h>
#include <time.h>

// 设备存储的secret
static char device_secret[37];

// 验证请求
typedef enum {
    AUTH_OK,
    AUTH_INVALID_SECRET,
    AUTH_DUPLICATE,
    AUTH_EXPIRED
} auth_result_t;

auth_result_t verify_request(const char* secret, const char* msg_id, int64_t exp) {
    // 1. 验证secret
    if (strcmp(secret, device_secret) != 0) {
        return AUTH_INVALID_SECRET;
    }

    // 2. 检查重复
    if (is_duplicate(msg_id)) {
        return AUTH_DUPLICATE;
    }

    // 3. 检查过期
    if (time(NULL) > exp) {
        return AUTH_EXPIRED;
    }

    // 4. 缓存msg_id
    cache_msg_id(msg_id, exp);

    return AUTH_OK;
}

JavaScript(APP端)

javascript
function buildRequest(action, value, secret) {
  const now = Math.floor(Date.now() / 1000)
  return {
    sender: 'app-001',
    receiver: 'device-001',
    msg_id: crypto.randomUUID(),
    action: action,
    time: now,
    exp: now + 60,  // 60秒后过期
    secret: secret,
    value: value
  }
}

// 使用示例
const request = buildRequest('unlock', { door: 'front' }, '550e8400-...')
mqttClient.publish('nodes/device-001/pending', JSON.stringify(request))

安全性说明

威胁防护方式
窃听secretTLS加密传输
伪造请求secret验证
重放攻击msg_id去重 + exp过期
内容篡改TLS完整性保护

重要

本方案必须在TLS环境下使用,否则secret将明文暴露!

与HMAC方案对比

简单鉴权HMAC签名
实现复杂度极低
依赖库需要HMAC
调试难度
离线安全❌ 依赖TLS
适用场景MQTT over TLS任意传输

物联网设备通信协议文档