01.
华为云 IoTDA业务流
华为云IoT设备接入云服务(简称“IoTDA”)提供海量设备的接入和管理能力,可以将IoT设备联接到华为云,支撑设备数据采集上云和云端下发命令给设备进行远程控制,配合华为云其他产品,帮助快速构筑物联网解决方案。
使用物联网平台构建一个完整的物联网解决方案主要包括3部分:物联网平台、业务应用和设备。
其中,业务应用又可拆解为应用集成层和设备数据集成层两部分,前者基于IoTDA提供的丰富的原子API实现设备管理和控制,后者基于IoTDA提供数据流转能力实现设备数据采集。
通过上述分析,在IoTDA的业务流中,存在多个交互过程,包括但不限于:①应用集成层与平台、②设备与平台、③平台与设备数据集成层。
交互必然存在认证鉴权,此文以上述三个交互过程为例,对IoTDA的鉴权和认证进行分析,帮助开发者理解其中的安全原理和机制,快速上手华为云IoT设备接入云服务。
02.
认证鉴权的基本概念
在进入IoTDA业务流认证鉴权前,首先,我们要先理解“认证鉴权”这一概念。
这里我们引入一个例子,帮助我们快速理解。唐三藏西天取经,路过一个个关隘,过程我们很熟悉了——唐三藏递送通关文牒,口念:“贫僧唐三藏,从东土大唐而来,去往西天拜佛求经”。
对应着我们的哲学三问:
我是谁?(贫僧唐三藏)
我从哪里来?(从东土大唐而来)
我要到哪里去?(去往西天拜佛求经)
声明了自己的身份以及执行的操作。
关隘把守人员:
验证身份:他是不是东土大唐派来的唐三藏?——认证(凭据为通关文牒)。
东土大唐派遣(委托)唐三藏去西天取经,凭据为通关文牒。——授权(授权媒介为通关文牒)
通关文牒中派遣是否真实?——鉴权(通关文牒的真实性)
要不要放他通行?——权限控制(通关)
2.1 认证(Identification)
对访问系统的主体的身份进行验证的过程,确认访问主体是它所声明的。访问主体使用**“身份标识符+认证凭证”**来证明自己的身份。
一般来说,认证有三种方式:
基于信息秘密的身份认证,你知道的内容(something you know):静态口令、预共享密钥、公私钥对、数字证书…
基于信任物体的身份认证,你持有的证明(something you have):智能卡、动态令牌卡(u盾)、身份证…
基于生物特征的身份认证,你就是这个人(something you are):生物特征(虹膜、面部、指纹、语音等)
高安全要求的场景下,会使用多种认证方式组合进行身份校验,即多因素认证。
2.2 授权(Authorization)
资源所有者委派执行者,赋予其指定范围的权限,执行对资源的操作。
资源所有者:拥有资源的所有权利,一般就是资源的拥有者。
执行者:被委派去执行资源的相关操作。
操作权限:可以对资源进行的某种操作。
资源:有价值的信息或数据等,受到安全保护。
现实生活中,授权的实现方式(授权媒介)有银行卡、门禁卡、钥匙、证书等,在互联网应用开发领域,授权的实现方式有:
通过web服务器的session机制,一个访问会话保持着用户的授权信息
通过web浏览器的cookie机制,一个网站的cookie保持着用户的授权信息
颁发授权令牌(token),一个合法有效的令牌中保持着用户的授权信息
通常要求授权媒介不可被篡改,不可随意伪造,很多时候需要受保护,防止被窃取。
2.3 鉴权(Authentication)
对一个声明者的身份权利的真实性进行鉴别。
授权和鉴权是一个一一对应的流程,有授权才会去鉴权,鉴权就是对授权所颁发授信媒介进行解析,确认其真实性。
2.4 权限控制(Access/Permission Control)
权限控制是指对可执行的各种操作组合配置为权限列表,然后根据执行者的权限,若其操作在权限范围内,则允许执行,否则禁止。
权限,是将执行者的行为抽象化的一个概念。
控制,是根据执行者的权限,对其所执行的操作进行判断,决定允许或禁止当前操作的执行。
常见的权限系统设计模型有DAC(Discretionary Access Control)自主访问控制、MAC(mandatory access control)强制访问控制、RBAC(Role-Based Access Control)基于角色的访问控制、ABAC(Attribute-based access control)基于属性的访问控制。
2.5 四者的关系
认证、授权、鉴权和权限控制这四个环节是一个前后依次发生、上下游的关系:认证-->授权-->鉴权-->权限控制。
认证和授权经常同时发生,让人误以为两者一样,其实两者是不一样的概念,两者都有对身份的确认过程,主要区别在于:
认证是确认声明者的本身身份,其作为授权的上游衔接而存在;
鉴权是对声明者所声明的真实性进行确认的过程,其作为授权的下游衔接而存在。
03.
认证鉴权的方式
“基于信息秘密的身份认证”的这一类认证方式较为常见,本文涉及的认证手段均属此类。
服务端对客户端的认证鉴权要解决两个关键问题:
确认客户端的身份;
确认请求来自确定身份的客户端。
3.1 基于账号口令认证鉴权:
客户端和服务端均持有认证客户端的账号口令,客户端认证和鉴权过程均携带账号口令,服务端通过验证账号口令的正确性来完成认证和鉴权。
此种方式需要保证口令存储和传输过程的秘密性,不被服务端和客户端以外的第三方窃取。一旦口令遭到泄露,客户端身份将有可能被仿冒,在更新泄露的口令前都始终存在极大的安全隐患。因此,我们很容易想到给凭据增加一个期限。
3.2 临时令牌鉴权:
与“基于账号口令认证鉴权”相同,客户端和服务端预共享账号口令,认证过程中,客户端携带账号口令,服务端验证账号口令的正确性。不同的是,认证通过后,服务端向客户端下发有一定时效性的令牌即Token,客户端在令牌有效期内使用该临时令牌与服务端进行业务交互,服务端基于该Token对客户端进行鉴权。
在鉴权阶段使用有时效性的凭据,可有效避免口令在鉴权阶段的泄露。此种方式仍然需要保证口令存储和认证传输过程中的秘密性,同时也需要保证临时令牌在时效内的秘密性,一定程度上降低了口令泄露的概率。
3.3 对称加密认证:
与前两者类似,客户端和服务端预共享账号口令。认证和鉴权过程中,客户端使用口令作为加密秘钥对请求或请求的摘要做加密,将密文附加在认证和鉴权的请求中,服务端收到请求后,使用口令对密文做解密或对摘要做验证,随即完成对客户端的认证和鉴权。
此种方式仍需保证口令存储的秘密性,但可喜的是实现了口令不出现在传输过程中,显著降低了口令泄露的风险。
账号和口令是客户端身份的象征,谁持有了该客户端的账号和口令就被认为是该客户端。客户端的账号口令本应只属于客户端所有,但因服务端的验证需要,客户端需与服务端共享该账号及口令。若有一种验证方式,能够实现服务端不持有口令即可完成口令的验证,那么将带来安全性的跨越式提升。
3.4 非对称加密认证:
非对称加密应运而生。客户端生成一对唯一的密钥对,密钥对包含一个公钥和一个私钥,两者一一对应,秘钥对有如下属性:密钥对包含公钥和私钥,如果用其中一个密钥加密一段数据,则必须用另一个密钥才能解密。
在“对称加密认证”的基础上,客户端与服务端预共享公钥。认证和鉴权过程中,客户端使用私钥对请求或请求的摘要加密,将密文附加在认证和鉴权的请求中,服务端收到请求后,使用公钥对密文解密或对摘要做验证,随即完成对客户端的认证和鉴权。当服务端需要给客户端回复信息时,服务端可使用公钥对信息加密,该信息也只能由客户端的私钥解密。
如上过程我们可总结为:”公钥共享,私钥保密;公钥加密,私钥解密;私钥签名,公钥验签“。只要客户端不泄露私钥,那么就是安全的。
此种方式仅需保证私钥在客户端端存储的秘密性,同时也可实现整个端到端通信过程的安全可信。
3.5 证书认证:
前一种方式下,若存在大量的客户端,那么预共享公钥显然会是个繁琐的过程。
好在办法总比困难多。信任模型能够解决“大量客户端”与服务端预共享公钥的问题。
具体的做法是:我们对公钥做一个变身,公钥叠加客户端身份信息得到TBS(to be signed),引入一个可信的第三方负责对客户端身份信息做公证(可信第三方使用其私钥对TBS签名,将TBS、签名算法及签名值组合而成得到证书),认证和鉴权过程中,客户端将证书传输给服务端,服务端仅需通过预共享可信第三方的公钥,使用该公钥验证证书并提取到客户端身份信息、服务端公钥,即可完成对客户端公钥的预共享,随即可完成后续的认证和鉴权。
如上过程我们可以理解为:预共享客户端公钥的目的是将身份标识及对应的公钥提供给服务端,证书方式将此过程交给可信第三方完成,服务端从客户端提供的证书中提取这两种信息,这两种信息的真实性通过可信第三方的公证(对证书验签)来保证。
如果客户端私钥遭泄露怎么办?那么就引入了吊销机制。
可信第三方维护了一个被吊销了的客户端证书列表,并将该列表获取方式附加在它所颁发的证书的扩展信息中;客户端一旦泄露自身私钥,则向可信第三方申请吊销该证书;申请通过后可信第三方将该证书添加到证书吊销列表中。服务端在验证客户端证书时,从证书中读取证书吊销列表获取方式,从而获取到已吊销的证书列表,确认该证书是否已被吊销,实际实现中为了避免性能消耗,服务端定期从可信第三方获取吊销证书列表并做缓存,每次比对仅需在缓存中比对,无需频繁从可信第三方拉取吊销列表。
3.6 双向证书认证:
前一小节介绍了服务端对客户端的认证,客户端认证服务端,也只需要在客户端预置服务端的证书CA,即可实现双向证书认证。
双向证书认证是一种使用数字证书作为通信实体身份鉴别依据的认证手段。基于:
非对称加密特性:密钥对包含公钥和私钥,如果用其中一个密钥加密一段数据,则必须用另一个密钥才能解密。”公钥共享,私钥保密;公钥加密,私钥解密;私钥签名,公钥验签“。
数字证书:包含一个公钥、身份信息以及证书授权中心的数字签名。
信任模型:当可以确定一个实体身份或者有一个足够可信的身份签发者证明该实体的身份时,才能做出信任那个身份的决定。
举个例子,来自中国的张三要和来自美国的David通信,在会话建立前双方都需要确认对方的身份(张三:对方是不是美国的David?David:对方是不是中国的张三?)。
张三来自中国,身份由ca_china.crt颁发,David来自USA,身份由ca_usa.crt颁发。张三要确认David的身份,需要使用ca_usa.crt来验证其身份,反之,David需要确认张三的身份,需要使用ca_china.crt来确认张三的身份。通信双方均使用ca认证对端为双向认证,仅一方认证另一方,为单向认证。
04.
IoTDA的多种认证方式
4.1 应用集成层与平台
这部分的业务流程为应用调用平台提供的应用侧API来实现。平台针对向应用提供的应用侧API封装了多种编程界面:
Console:即华为云官网控制台(以下简称“Console”),为Web界面,最大的优点是无需任何编程基础,非常直观,租户进行通过浏览器输入账号密码,登陆华为云控制台,即可实现Console上的业务操作。
华为云SDK V3:华为云简单易学、隐藏细节、多语言支持;
API Explorer:快速检索,在线调试,联动文档;
CLI:独立执行、多OS平台、自动升级;
自行封装:提供java语言的样例(支持apache-httpclient和okhttp)。
认证方式有账号密码和访问秘钥两种,均为“基于信息秘密的身份认证”,就使用的授权媒介(或称为鉴权依据)而言,前者为Token,后者为签名。账号密码不做过多赘述,此处重点介绍访问秘钥。
4.1.1 访问秘钥
4.1.1.1 永久安全凭证
“永久安全凭据”又称“访问秘钥”,也称“AK/SK”(Access Key ID/Secret Access Key),是您通过开发工具(API、CLI、SDK)访问华为云时的身份凭证,不能登录控制台。系统通过AK识别访问用户的身份,通过SK进行签名验证,通过加密签名验证可以确保请求的机密性、完整性和请求者身份的正确性。
4.1.1.2 临时安全凭证
为满足客户对安全的时效性需要,华为云提供了与永久安全凭证相对应的临时安全凭证,其中包括临时AK/SK和SecurityToken。临时安全凭证与永久安全凭证的工作方式几乎相同,仅存在小量差异。
4.1.1.3 安全凭证签名过程
签名过程为:
1.构造规范请求
CanonicalRequest =
HTTPRequestMethod + '\n' +
CanonicalURI + '\n' +
CanonicalQueryString + '\n' +
CanonicalHeaders + '\n' +
SignedHeaders + '\n' +
HexEncode(Hash(RequestPayload))
HashedCanonicalRequest = Lowercase(HexEncode(Hash.SHA256(CanonicalRequest)))
2.创建待签字符串
StringToSign =
Algorithm + \n +
RequestDateTime + \n +
HashedCanonicalRequest
3.计算签名
signature = HexEncode(HMAC(Secret Access Key, StringToSign))
4.添加签名信息到请求头
Authorization: algorithm Access=Access key, SignedHeaders=SignedHeaders, Signature=signature
4.1.2 用户界面
图形界面:
Console:通过浏览器输入账号密码;
API Explorer:通过浏览器输入账号密码;
调试工具:
CLI:AK/SK;
Postman:Token
编程界面:
华为云SDK V3:AK/SK;
自封装:提供java语言的样例(支持apache-httpclient和okhttp)。
在业务实践过程中,多数客户对华为云SDK V3青睐有加,极少数客户选择自封装的方式。本章节对这两种方式做一个java语言版本的演示。
4.1.2.1 华为云SDK V3(推荐)
https://support.huaweicloud.com/sdkreference-iothub/iot_10_10002.html
方式一:使用通用认证类(BasicCredentials)
// 基础版地址
List<String> basicEndpoints = Arrays.asList(
"https://iotda.cn-north-4.myhuaweicloud.com",
"https://4e1af840db.iotda.cn-north-4.myhuaweicloud.com"
);
// 创建认证
ICredential auth = new BasicCredentials()
.withAk(ak)
.withSk(sk)
.withDerivedPredicate(new Function<HttpRequest, Boolean>() {
@Override
public Boolean apply(HttpRequest httpRequest) {
// 根据endpoint判断需要使用何种签名方式
// 基础版使用AKSK鉴权方式,此处返回false;
// 非基础版需要使用衍生AKSK鉴权方式,此处返回true
String endpoint = httpRequest.getEndpoint();
return !basicEndpoints.contains(endpoint);
}
});
// 创建IoTDAClient实例并初始化
IoTDAClient client = IoTDAClient.newBuilder()
.withCredential(auth)
// 基础版:请选择IoTDARegion中的Region对象
//.withRegion(IoTDARegion.CN_NORTH_4)
// 标准版/企业版:需自行创建Region对象
.withRegion(new Region(REGION_ID, ENDPOINT))
.build();
方式二:使用IoTDA的专属鉴权类(IoTDACredentials)
// 创建认证
ICredential auth = new IoTDACredentials()
.withAk(ak)
.withSk(sk)
.withDefaultEndpoint(true); // 标准基础版,此处设置为 true
// 创建IoTDAClient实例并初始化
IoTDAClient client = IoTDAClient.newBuilder()
.withCredential(auth)
// 基础版:请选择IoTDARegion中的Region对象
.withRegion(IoTDARegion.CN_NORTH_4)
.build();
// *********************** 访问标准版/企业版 ***********************
// 创建认证
ICredential auth = new IoTDACredentials()
.withAk(ak)
.withSk(sk)
.withDefaultEndpoint(false); // 标准标准版/企业版,此处设置为 false
// 创建IoTDAClient实例并初始化
IoTDAClient client = IoTDAClient.newBuilder()
.withCredential(auth)
// 标准版/企业版:需自行创建Region对象
.withRegion(new Region(REGION_ID, ENDPOINT))
.build();
// *********************** 通过内部网络组件访问基础版 ***********************
// 创建认证
ICredential auth = new IoTDACredentials()
.withAk(ak)
.withSk(sk)
.withDefaultEndpoint(true); // 标准基础版,此处设置为 true
// 创建IoTDAClient实例并初始化
IoTDAClient client = IoTDAClient.newBuilder()
.withCredential(auth)
// 标准版/企业版:需自行创建Region对象
.withRegion(new Region(REGION_ID, "https://internl-nginx:8080"))
.build();
4.1.2.2 自封装(存量系统使用)
AK/SK认证
// 初始化基础版信息。默认以 `https://iotda.cn-north-4.myhuaweicloud.com` 为基础版,
// 若某些情况(例如客户端与平台之间通过客户自身内网网络组件转发)下基础版地址有变化,则可通过如下方法添加:
// ClientExt.addBasicEndpoint("https://custom-proxy.endpoint:443");
// ClientExt.addBasicEndpoint("http://custom-proxy.endpoint:8080");
// ClientExt.addBasicEndpoint("http://172.1.2.3:8080");
// ClientExt.addBasicEndpoint("https://172.1.2.3:1883");
// 构造请求
Request request = new Request();
request.setKey(Constants.ACCESS_KEY);
request.setSecret(Constants.SECRET_KEY);
// 设置url、headers、method、requestBody等
// 签名(此处对基础版和标准版/企业版做了兼容性处理)
HttpRequest httpRequest = ClientExt.sign(regionId, request);
// 发送请求
HttpResponse httpResponse = httpUtils.execute(httpRequest);
Token认证(需自行管理Token的生命周期)
// 设置url、headers、method、requestBody等
HttpRequest httpRequest = buildHttpRequest();
// 设置Token(需自行解决Token过期或失效时的轮换问题)
header.put("X-Auth-Token", token);
// 发送请求
HttpResponse httpResponse = httpUtils.execute(httpRequest);
4.2 设备与平台
平台提供X.509证书双向认证和秘钥认证两种设备侧认证方式。客户可根据设备的能力和实际业务需要自行选择。
4.2.1 X.509证书双向认证
证书双向认证完整业务流程为:
证书双向认证过程为:
4.2.2 密钥认证
public static String sha256_mac(String str, String timeStamp) {
String passWord = null;
try {
Mac sha256Hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(timeStamp.getBytes("UTF-8"), "HmacSHA256");
sha256Hmac.init(secretKey);
byte[] bytes = sha256Hmac.doFinal(str.getBytes("UTF-8"));
passWord = byteArrayToHexString(bytes);
} catch (Exception e) {
log.error(ExceptionUtil.getBriefStackTrace(e));
}
return passWord;
}
4.3 平台与设备数据集成层
当前华为物联网平台支持HTTP/HTTPS和AMQP两种订阅方式,未来还将支持MQTT订阅方式。
4.3.1 HTTP/HTTPS
第三方应用服务(HTTP推送):应用服务器通过调用物联网平台的创建规则触发条件、创建规则动作、修改规则触发条件接口配置并激活规则,在指定应用服务器的URL后,将平台获取发生变更的设备业务信息(如设备生命周期管理、设备数据上报、设备消息状态、设备状态等)和管理信息(软固件升级状态和升级结果)推送给指定URL的服务器。
Https方式:使用证书双向认证,IoT平台加载由客户提供的用于认证应用服务器证书的CA证书。与之对应的,作为服务端,应用侧如果需要认证IoT平台的身份,需要加载IoT平台的CA证书。
4.3.2 AMQP
用户侧使用平台为其生成的accessKey/accessCode作为认证凭据,与IoT平台建立长链接,实现数据拉取和推送以实现数据集成。
往期推荐
☞ 国内 IoT 物联网平台终局的思考