[论文分享]基于区块链技术的服务端资源权限控制系统设计与实现
前情
这几年对区块链进行了学习,也算是有些感悟,想以类似论文的形式将一些想法表现出来(这也能严谨一些,文章组织也更有条理),分享给大家,希望能与大家多交流。在我来看,区块链是一项技术,在某一点上往往难以量化其优点和贡献的,这就更需要去深入详细的思考,了解其特性可以带来的变革。
0.引言
随着区块链技术的兴起,互联网浪潮逐渐从web1.0、web2.0向web3.0转变。去中心化浪潮使得用户由信息的接收者、沟通者转为信息的提供者及制造者。数据逐渐由传统的寡头公司转移到用户手中,随之而来的则是用户对身份主权、数据主权的回收与支配,最终实现价值的普惠流动。这个去中心化既是计算上的去中心,也是存储上的去中心化。然而就当前而言,web3.0也不可避免地过于理想化,治理挑战、技术挑战、监管挑战都对其大规模落地带来影响。在很长一段时间内,网络上都将会出现中心化与去中心化并存的情形,中心化服务提供商基于基于去中心化技术支撑,对网络上的用户提供服务。在此背景下原本中心化的服务端应当处理好中心化与去中心化的权衡,在其中更要做好权限管理工作。
用户的权限控制是个敏感的话题,涉及到用户与服务提供商之间的信任问题。传统的权限控制系统由用户发出操作申请,由服务器程序在后端完成并存储,整个过程存在权限、数据的中心化问题,无法保证用户权限分发控制的不可篡改性及公开可追溯性,且用户并未全程参与,信任问题尚未解决。此外,用户的权限分发也对权限控制提出了更高的要求,基于信息管理的传统权限控制方法往往难以满足。因此,实现可信、可追溯的权限管理控制具有重要的工程意义和应用价值。本文基于区块链技术,设计了一种服务端资源权限控制系统,包括资源权限分发转移机制及基于权限的资源控制方法,有效地解决了Web3.0趋势下权限控制难、中心化的问题,具有一定的工程价值及研究意义。
1. 背景介绍
近年来,随着互联网技术的不断进步,互联网用户与服务提供商的角色也发生悄然转变。Web1.0时代,网站是信息及数据的提供者,用户参与信息的浏览和使用。Web2.0时代,用户逐渐参与到资源、数据的创建中来,基于中心化服务进行交换、沟通,但数据、权限控制等仍为网站所持有。2020年来,Web3.0概念逐渐兴起,在去中心化浪潮下,用户逐渐走向舞台的中心,对资源、数据、权限的控制权逐渐回到用户手中,凭借身份凭证,用户逐步可以实现对数据、权限的自主控制。因此,在此转变趋势下,服务端的权限控制方法也应随之发生改变。
传统RBAC(Role-Based Access Control)
传统的权限控制方法是基于资源,数据作为资源存储在社区的服务端,而权限则通过数据库中用户-角色-权限的数据表标识,用户如要访问资源,服务端则会首先对用户在受访问资源上的权限进行校验,最终给出授权与否的判断。 国内外对此进行过一些研究:早在1995年,D Ferraiolo及 J Cugini等人就对基于角色的准入控制进行了研究,从此RBAC(Role-Based Access Control)逐渐进入国内外学者的视野。2002年,清华大学的林磊等人对授权的行为模型展开了研究,并在RBAC的基础上提出了一套使用于MIS系统的权限控制应用模型。2012年,北京工商大学的李双提出了一种扩展的RBAC模型(ERBAC),不仅继承了传统RBAC的所有优势,同时可以不做修改的嵌入到工作流系统中并实现动态访问控制。武汉理工大学的向奎在2013年设计了一个可接口集成,数据集成,流程集成的基于角色访问控制的通用用户权限管理系统,实现了用户和权限的逻辑分离,能够动态的为用户分配权权限。2016年及2020年,同济大学的邵剑雨等人及河南师范大学的张荣荣分别实现了基于动态信任值的访问控制方法及具有可维性的三位权限控制模块:前者通过动态调整用户信任值克服了当前访问控制在移动互联网环境下安全性不足的缺点并有效控制用户在不同状态下对不同资源的访问权限,后者在RBAC的基础上加入组织和角色组以实现权限体系的可复用及可扩展。尽管研究卓有成效,但传统的权限控制方法原生地存在局限性:权限本身也作为数据字段存储在服务端,而用户对权限的控制本质上是请求对服务端数据的更改,这将不可避免地带来中心化问题,用户难以确保自己对权限的排它性、准入性,同时也难以保证用户权限分发控制的不可篡改性及公开可追溯性,导致用户与服务端间的信任问题。
区块链与权限的结合
意识到传统权限控制方法的局限性,国内外学者结合了新兴的区块链技术,对此做出了一些改进,具体包括以下:2017 年,卡迪阿雅德大学的Aafaf等人基于区块链技术,为物联网环境设计了名为FairAccess的权限控制框架并通过进行了试验。一年后,奈良科技大学的Yuanyu Zhang等人同样为物联网环境设计了基于智能合约的权限控制框架,利用智能合约实现权限的动态控制。2020年,汪利鹏等人提出了区块链协同权限控制方法及装置,通过公私钥实现用户对于共享资源的鉴权请求及浏览,实现业务关联方数据共享。2021年,苏州科学技术大学的的石鹏展提出一种对称加密的数据权限管理方案,实现对存储在区块链中的隐私数据的访问控制。同年,国防科技大学的舒展鹏等人对指挥信息系统用户权限管理问题展开研究,利用区块链的多链架构划分指挥信息系统的业务席位,实现操作行为的统一规范管理。但整体看来,目前并未对技术进行整合并建立统一、有效的权限管理机制。
技术背景
在区块连浪潮下,用户的个人信息将已不再以用户名-密码的形式储存在服务端,而是以私钥-公钥(及地址)的身份存在于分布式网络中,其示意图如图1所示。用户在首次进入网络后通过加密算法(如椭圆加密等)生成私钥-公钥对,私钥由用户个人持有,对应用户密码,公钥及地址则对外可见,作为用户对外身份所展示。用户使用私钥签名,在服务端端使用公钥进行验证,验证用户身份,并以此为用户的操作进行授权。而区块链本质上是链接在一起的区块数据,Merkle哈希树使得其难以篡改,极其微小的修改也会带来区块哈希值的巨大变化。数据的更改和转移,以交易的形式存入区块并记录在链上,任何人都无法篡改,这也保证了权限管理的透明性、不可否认性。
本文基于区块链技术,针对中心化、去中心化并存的网络环境中,设计了一种服务端资源权限控制系统,该系统以用户为核心,面向资源设计,有效地解决了资源权限控制难、权力中心化的问题。本文对该系统的核心组件进行了实现,并与传统资源权限控制系统展开了对比。同时本文也对未来Web3.0社区数据、存储、权限去中心化的趋势进行了探讨,具有一定的工程价值及研究意义。
2. 基于智能合约的资源权限分发转移机制设计
用户的活动与交互会产生、创建资源(资源可以是文本、语音、数据接口等等),而用户则拥有该数据的所有权限,不被其他用户随意访问、占用。这就要求资源(尤其是敏感资源)的所有权、使用权应在网络中是透明的、不可篡改的。基于区块链技术,建立智能合约,将权限通过Token(凭证/代币)进行实体化,即可保证用户权限的不可篡改。具体示意图如下图所示:
用户与服务端(链上部分)均可接入区块链网络,作为节点而存在。链上有多个全节点或轻节点,全节点可验证、提交交易并对外广播。而轻节点可通过与全节点的通信查询交易信息。用户与服务提供商之间通过HTTP服务进行正常通信,用户通过数字签名向服务端进行身份证明,随后进行活动并进行资源的创建。在此过程中,如产生部分敏感资源,资源将(加密)存储至中心化服务器,且服务端(链上部分)应实现权限上链,保证资源访问及权限转移的透明性。
在资源创建完成后,服务端将为该资源创建智能合约,合约的Token(代币)则标识对资源的所有权。在该合约的创世区块中,该合约将权限代币分配给资源的创建用户。如果有多个用户同时参与了资源的创建过程,则权限代币将被按比例发送到各个用户的地址中去。生成Token的量取决于资源被访问的手段及Token是否会被销毁。正如商品在市场上自由流通,资源也可以在用户之间共享、转移,这就体现在代币的转移。当两个用户之间需要转移资源的权限时,资源所有者可以从身份地址将代币(部分或所有)转移至新用户的地址,代币的转移过程只在链上进行,服务端仅能对交易进行观察,而无法对交易进行干涉。权限代币的转移示意图如下图所示:
如果用户想放弃对资源的权限,可以直接将所有权限代币打入黑洞(0x00000…dead),即将权限代币转移至黑洞地址,此时用户不再拥有权限代币,已失去对于该资源的控制权,完成了权限的销毁。
3.基于上链权限的资源控制方法设计
基于权限的资源控制不仅包括对于权限的认证,同时也包括基于权限对资源的加密控制。尽管权限已经上链,解决了用户的权限生成、转移、销毁的中心化问题,但系统仍需要对于资源进行妥善处理(如加密存储等),否则用户-服务端间的信任问题仍然难以解决。本节将介绍基于权限凭证的认证与授权、权限代币的重新分发及资源的加密访问。
基于权限代币的认证与授权
用户所创建的资源存储在中心服务器中,并为验证器所保护。当资源受到访问时,验证器向链上的节点发出请求,请求中附带用户的身份(即地址)及该资源所对应的合约,以验证链上用户的地址是否包含对应资源的权限代币。如果不满足,则用户的请求将被驳回,如果用户的链上地址存在权限代币且其数量满足特定要求(如代币的数量等),则用户将被认证为资源的所有者并被授权,用户即可实现对于资源的访问。基于权限代币的认证与授权过程如下图所示:
权限代币的回收与重新分发
权限代币代表着用户对于资源的所有权,但其所有权不是一成不变的。正如代币具有支付属性,用户在访问资源时,也可以扣除一定的权限代币。此时,资源的访问就具有了计量属性,用户对资源的访问也要付出相应的代价,当用户的代币不足以支付资源访问所需的花费时,该操作将被中心化服务器的验证器所拒绝。当用户选择消耗权限代币进行访问时,用户所支付的代币则会被转移到验证器的链上地址中,并通过重新分发或销毁机制进行流转。
资源的加密存储及控制
当资源存储在服务器端,这不可避免地对数据、资源的安全性带来了挑战。当用户进行登陆操作并进行内容创作时,资源文件在离开用户端前,就会被切分成多块,在用户端使用公钥进行加密并发送至服务器。此时,其余用户由于不知道私钥,所以资源难以被访问。当资源的权限需要转移时,在用户转让端由用户使用私钥对数据解密,还原明文资源、数据,再使用受让端公钥对数据加密,最后并传回服务端。服务端在资源的产生及权限转移过程中均不接触原始数据,从而保证了数据的隐秘性和安全性。
4. 服务端资源权限控制系统核心组件实现
本文基于以上设计,实现了服务端资源权限控制系统核心组件,组件包括:私有链的搭建、权限智能合约编写及验证器,系统组成如下图所示。
本文基于Geth工具搭建了私有链,对外开放rpc端口,实现底层支撑,保障智能合约的运行。同时本文结合ERC20及ERC721智能合约接口框架,实现了资源权限控制智能合约,合约代码段具体组成如下所示。其中server变量代表服务器名称,tokenOwners变量是tokenId(即资源编号)到资源所有者地址的映射,tokenBalance则是用来寻找给定资源下给定用户的资源凭证(代币)数量。_mint方法则由服务端发起,生成资源代币并指定所有人。transfer方法和destroy方法则是对资源代币的转移和销毁。checkBalance方法则允许服务器调用以查看指定用户所拥有的指定资源凭证的数量。
本文基于Golang的Echo框架搭建了服务端验证器。验证器由eths模块、routes模块、config模块及utils模块组成。eths模块储存Solidity智能合约的abi及编译后的go文件,并基于go-ethereum编写账户管理及合约交互代码。routes模块基于Echo框架,对外提供http服务,函数可供服务端调用,对内则调用eths模块。config模块支持对keystore文件存储位置、智能合约地址及私有链接入点rpc地址进行配置。utils则支持对网络请求处理及相关的文本处理。
本文对系统的功能展开了测试,测试结果表明,合约的创建、权限代币的生成、转移均在链上可查,同时非授权对象对权限代币的更改也将被拒绝。合约链上交互截图如下图所示。
测试结果表明设计的基于区块链技术的服务端资源权限控制系统能够达到权限上链、透明控制的目标,本文将其与传统基于角色的权限控制方法进行了对比,对比情况如下表所示。由表可知基于区块链技术的服务端资源权限控制将权限上链,权限所有对象从服务端改为权限所有用户,整个管理过程透明、去中心话,很好地解决了用户与服务端之间的信任问题。
存储形式 | 存储位置 | 所有对象 | 是否透明 | 是否中心化 | |
---|---|---|---|---|---|
RBAC | 数据库字段 | 服务端 | 服务端 | 否 | 是 |
基于区块链的权限控制 | 智能合约代币(Token) | 链上 | 权限所有用户 | 是 | 否 |
5. 思考:不足与展望
本文基于区块链技术,设计了一种服务端资源权限控制系统,有效地解决了权限控制难、中心化的问题,然而当前的设计依然存在一定的问题,具有一定的局限性。本文将对此做出探讨,并提出可能的改进措施。
- 每当用户进行资源的创建,就会为该资源(数据)生成相关的权限代币。尽管这可以批量化、自动化进行,但有可能会出现粒度过细的问题,往往会造成算力、存储空间的浪费。实际上,用户仅需要保证隐私、重要数据的安全,对于隐私性、重要性要求不高的资源或数据,可以明文在服务器中存储,这样资源的浪费问题能达到很大程度的缓解。又或者用户可以通过同一份智能合约,基于映射数据结构,实现对于多份资源的权限控制。
- 数据存储时,为了数据的隐秘性,服务器端对数据的实际内容应是不可知的,这使得明文的加密及密文的解密都应当在用户端进行。以上对用户端的性能提出了一定要求。实际上,服务端应对数据、资源的规模做出了限制,不满足的将被驳回,否则非对称加密会使得数据加密、传输的时延难以令人接受。
- 数据经加密后,仍然存储在服务端,但却无法被社区服务所直接访问,需通过验证器进行中继,而权限的上链查询会降低用户访问资源的流畅性,服务端故障也会导致数据的丢失与不可恢复。实际上,这可以通过优化区块链性能进行改善。同时,为了彻底实现数据的去中心化存储,也可采用诸如IPFS(星际文件系统)等分布式文件存储技术,此时数据完全不依赖于中心化服务器的位置,但相应服务的实时性、易用性也会受到相当程度的影响。服务提供商在架构设计选择时应当做好权衡以达成平衡。
6. 结束语
在去中心化浪潮下,中心化服务端应当处理好中心化与去中心化的权衡,实现数据、资源的权限控制。本文基于区块链技术,提出了一种服务端资源权限控制系统,包括资源权限分发转移机制及基于权限的资源加密存储、控制方法。尽管该系统仍存在算力浪费、性能要求较高的趋势,仍未彻底实现数据的去社区化及去中心化,但仍在中心化与分布式决策权衡提供了思路。希望随着科技的发展,更多分布式技术能够涌现,为人们提供便利。
7 附录
智能合约代码
以下是权限管理的智能合约代码,欢迎交流。
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "./openzepplin/Ownable.sol";
contract ResourceAuthorizationManagement is Ownable{
event Transfer(address indexed from, address indexed to, uint256 tokenId, uint256 tokenAmounts);
// ---------------------------------------------------------------------------
string public server;
mapping(uint256 => address) public tokenOwners;
mapping (uint256 => mapping(address => uint256)) tokenBalances;
mapping (uint256 => string) public tokenDescriptions;
// ---------------------------------------------------------------------------
constructor(string memory servername) public {
server = servername;
}
// ---------------------------------------------------------------------------
modifier _ifTokenExist(uint256 tokenId){
require(tokenOwners[tokenId]!=address(0x0),"TokenId non-exist");
_;
}
modifier _isOwnableOfToken(uint256 tokenId, address add){
require(tokenOwners[tokenId]==add,"Not valid user of the token");
_;
}
modifier _hasSufficientAmount(uint256 tokenId, uint256 amounts){
require(tokenBalances[tokenId][msg.sender] >= amounts,"No sufficient token");
_;
}
// ---------------------------------------------------------------------------
function _mint(uint256 tokenId, address tokenOwner, uint256 tokenAmount, string memory tokenDescription) public onlyOwner(){
tokenOwners[tokenId] = tokenOwner;
tokenBalances[tokenId][tokenOwner] = tokenAmount;
tokenDescriptions[tokenId] = tokenDescription;
}
function transfer(address to, uint256 tokenId, uint256 amounts ) public _hasSufficientAmount(tokenId,amounts) {
tokenBalances[tokenId][msg.sender] -= amounts;
tokenBalances[tokenId][to] += amounts;
emit Transfer(msg.sender,to,tokenId,amounts);
}
function destroy(uint256 tokenId) public _isOwnableOfToken(tokenId,msg.sender){
transfer(address(0x0),tokenId,tokenBalances[tokenId][msg.sender]);
}
function checkBalance(address addr, uint256 tokenId) public view _ifTokenExist(tokenId) returns (uint256){
return tokenBalances[tokenId][addr];
}
}