• 联邦学习[加密方式]



    0 背景

    联邦学习主要在于解决不同数据孤岛之间的信息共享问题,在数据不出本地的基础上,完成更上层的信息共享。联邦学习中的横向联邦学习,其形式有点类似分布式机器学习,但是本质不是同一个东西。

    但是联邦学习领域存在一个定义不同的现象,就是:

    • 老外,比如谷歌主导的联邦学习,总是以跨设备(如智能输入法),或者跨数据孤岛(如不同企业的数据中心)来区分,然后总会以有个所谓中心点协调开始介绍(当然也有P2P联邦学习),并关注非独立同分布等数据,以及如何解决活跃设备的联机以及更新等,主要是工程方面问题;
    • 而以国内杨强教授等人主导的,是从数据角度划分,即1)跨设备为横向联邦,即大家特征一致,缺样本;2)不同领域企业之间的合作,如银行和保险公司合作的纵向联邦(主打特征不同,需要互相补充特征);3)以及特征也不够,需要迁移学习的联邦迁移学习。

    相对而言,联邦学习最主要解决的问题,就是信息不泄露,但是既然数据不交换,那怎么解决联合呢?毕竟需要信息交互。这里的信息交互,主要就是模型梯度,虽然梯度已经不容易看出具体的原始信息,但是总是能区分是机器学习还是深度学习,亦或是更深层次的区分,等等。这自然需要加密算法的存在。

    1 加密方式类型

    随着各个国家的法律法规的发布,隐私保护会变得日益严格,其中涉及的技术包含但不限于:

    差分隐私(Differential Privacy,DP)
    同态加密(Homomorphic Encryption,HE)
    多方安全计算(Secure Multi-party Computation, MPC)
    秘密共享(Secret Sharing)
    可信计算(Trusted Computing,TC)
    摘要算法
    密钥交换协议 key exchange,KE

    2 差分隐私(Differential Privacy,DP)

    差分隐私是用户数据加密后上传到平台服务器后,平台可以用这些加密后的数据计算出用户群体的相关特征,但无法解析某个个体的信息。举个简单的例子,假设现在有一个婚恋数据库,2个单身8个已婚,只能查有多少人单身。刚开始的时候查询发现,2个人单身;现在张三跑去登记了自己婚姻状况,再一查,发现3个人单身。所以张三单身。这里张三作为一个样本的的出现,使得攻击者获得了奇怪的知识。而差分隐私需要做到的就是使得攻击者的知识不会因为这些新样本的出现而发生变化。

    通常采用的做法是给数据加入噪声,这个噪声不是随便加的,加得太大,数据失真,加得太少,起不到保护作用,噪声是有要求的,假设数据集\(D\),现在加入噪声\(M\)得到数据集\(D'\) ,将数据集\(D\)中随意拿到一个记录,再加入噪声\(M\)得到\(D^{''}\),对\(D'\)\(D^{''}\)的数据计算结果要一样的才可以,参考1参考2。为了满足差分隐私的思想,通常的做法是向查询结果中引入随机性。对于数值型的查询结果,常用的方法是向查询结果中加入服从拉普拉斯分布的噪声,这种方法被称为拉普拉斯机制。

    差分隐私(Differential Privacy)是一个框架,用于评估一个旨在保护隐私的机制(算法)所提供的隐私保证。

    我们不需要现在去理解它的数学意义,暂且跳过这个公式也不会影响接下来的理解。它的核心思想就是说,对于相差一条记录的两个数据集(\(D1\),\(D2\)),查询它们获得相同结果的概率(\(Pr\))是非常接近的,对于非常接近的衡量是由公式中的 \(\epsilon\) 决定的,称其为隐私预算(privacy budget)

    举个简单例子,参考

    noise = numpy.random.laplace(loc, scale=1/ε, size=1)  # 从参数为(loc, scale)的拉普拉斯分布中随机抽取1个样本,返回数组类型的变量noise
    noise_count = count + noise[0]  # 向原始的计数结果count中添加噪声,得到浮点型的噪声计数noise_count
    

    3 同态加密(Homomorphic Encryption,HE)

    同态加密是很久以前密码学界就提出来的一个问题。早在1978年,Ron Rivest, Leonard Adleman, 以及Michael L. Dertouzos就以银行为应用背景提出了这个概念。其中Ron Rivest和Leonard Adleman分别就是著名的RSA算法中的R和A。同态加密是基于数学难题的计算复杂性理论的密码学技术。对加密后的数据进行处理得到输出,将这输出进行解密,其解密的结果与处理未加密的原始数据得到的结果是一样的。

    同态加密分为全同态、层次同态、半同态(也叫部分同态)三种。

    • 半同态加密 (Partial Homomorphic Encryption, PHE):半同态加密或部分同态加密,英文简称为SWHE(Somewhat Homomorphic Encryption)或PHE(Partially Homomorphic Encryption)。只支持某些特定的运算法则f ,PHE的优点是原理简单、易实现,缺点是仅支持一种运算(加法或乘法);
    • 层次同态加密(Liveled HE,LHE):一般支持有限次数的加密算法,LHE的优点是同时支持加法和乘法,并且因为出现时间比PHE晚,所以技术更加成熟、一般效率比FHE要高很多、和PHE效率接近或高于PHE,缺点是支持的计算次数有限,如Boneh-Goh-Nissim方案。
    • 全同态加密 (Fully Homomorphic Encryption, FHE):支持无限次的任意运算法则f,FHE有以下类别:基于理想格的FHE方案、基于LWE/RLWE的FHE方案等等。FHE的优点是支持的算子多并且运算次数没有限制,缺点是效率很低,目前还无法支撑大规模的计算.

    第一个构造出全同态加密方案的人是Gentry,这是他在Stanford攻读博士学位的研究成果。在2009年Graig Gentry给出FHE的构造前,很多加密方案都具有部分同态的性质。实际上,最经典的RSA加密,其本身对于乘法运算就具有同态性。Elgamal加密方案同样对乘法具有同态性。Paillier在1999年提出的加密方案也具有同态性,而且是可证明安全的加密方案。2009年前的HE方案要不只具有加同态性,要不只具有乘同态性,但是不能同时具有加同态和乘同态。这种同态性用处就不大了,只能作为一个性质,这类方案的同态性一般也不会在实际中使用,参考

    2011年,Gentry和Halevi在IBM尝试实现了两个HE方案:Smart-Vercauteren的SWHE方案[SV10]以及Gentry的FHE方案[Gen09],并公布了效率。结果如何呢?(原始数据可以在2nd Bar-Ilan Winter School on Cryptography找到)

    • Smart-Vercauteren的SWHE方案效率如下:
    • 看着好像还行,不过这Dimension有点夸张啊…也就是说公钥很长…那么,Gentry的FHE方案如何呢?效率如下

      公钥2.3GB,KeyGen需要2个小时,也是醉了…

    这里简略介绍了里程碑:

    3.1 全同态加密

    全同态加密,即支持无限次的加法和乘法

    3.2 层次同态加密

    层次同态加密即性质上支持加法和乘法,但是只是有限次数

    3.2 半同态加密

    半同态加密指的是只支持加法或者乘法一种运算,如只支持乘法性质的RSA算法1RSA算法2,

    import rsa
    public_key, private_key = rsa.newkeys(1024)
    pub_pkcs = public_key.save_pkcs1()
    priv_pkcs = private_key.save_pkcs1()
    
    mess = 'hello word'
    public_key = rsa.PublicKey.load_pkcs1(pub_pkcs)
    private_key = rsa.PrivateKey.load_pkcs1(priv_pkcs)
    
    encry_str = rsa.encrypt(mess.encode('utf-8'), public_key)
    origin = rsa.decrypt(encry_str, private_key)
    
    origin=origin.decode('utf-8')
    

    Paillier只支持数乘以及加法,

    from phe import paillier
    import numpy as np
    
    public_key, private_key = paillier.generate_paillier_keypair()
    
    secret_number_list = [3.141592653, 300, -4.6e-12]
    
    encrypted_number_list = [public_key.encrypt(x) for x in secret_number_list]
    [private_key.decrypt(x) for x in encrypted_number_list]
    #------------------------------
    enc_mean = np.mean(encrypted_number_list)
    enc_dot = np.dot(encrypted_number_list, [2, -400.1, 5318008])
    
    print("enc_mean:", private_key.decrypt(enc_mean))
    print("enc_dot:", private_key.decrypt(enc_dot))
    #=================================
    a, b, c = encrypted_number_list
    
    a_plus_5 = a + 5                    #= a + 5
    print("a + 5 =",private_key.decrypt(a_plus_5))
    
    a_plus_b = a + b                    #= a + b
    print("a + b =",private_key.decrypt(a_plus_b))
    
    a_times_3_5 = a * 3.5               #= a * 3.5
    print("a * 3.5 =",private_key.decrypt(a_times_3_5))
    
    a_minus_1 = a - 1                 #= a + (-1)
    print("a - 1=",private_key.decrypt(a_minus_1))
    
    a_div_minus_3_1 = a / -3.1          #= a * (-1/3.1)
    print("a / -3.1 =",private_key.decrypt(a_div_minus_3_1))
    
    a_minus_b = a - b                   #= a + (b*-1)
    print("a - b =",private_key.decrypt(a_minus_b))
    

    4 多方安全计算(Secure Multi-party Computation, MPC)

    安全多方计算(Secure Muti-party Computation,简称MPC,亦可简称SMC或SMPC)问题首先由华裔计算机科学家、图领奖获得者姚期智教授于1982年提出,也就是为人熟知的百万富翁问题:两个争强好胜的富翁Alice和Bob在街头相遇,如何在不暴露各自财富的前提下比较出谁更富有?

    姚氏“百万富翁问题”后经O Goldreich、Micali以及Wigderson等人的发展,成为现代密码学中非常活跃的研究领域,即安全多方计算,其数学描述为,“有n个参与者\(P_1\),\(P_2\),…\(P_n\),要以一种安全的方式共同计算一个函数,这里的安全是指输出结果的正确性和输入信息、输出信息的保密性。具体地讲,每个参与者\(P_1\),有一个自己的保密输入信息\(X_1\),n个参与者要共同计算一个函数\(f(X_1,X_2, … ,X_n)=(Y_1,Y_2, … ,Y_n)\),计算结束时,每个参与者\(P_i\)只能了解\(Y_i\),不能了解其他方的任何信息。”

    4.1 Private Set Intersection, psi

    不要和:稳定度指标(population stability index ,PSI)搞混了

    PSI是一种安全的多方计算加密技术,它允许持有集合的两方比较这些集合加密版本以计算交集。在这种情况下,除了交集中的元素之外,双方都没有向对方透露任何信息。按Private Set Intersection(PSI)简介和资料分享中介绍的:

    到现在为止,PSI协议种类很多,但是主要还是分为以下几个部分:
    (1)基于哈希的PSI:主要是应用加密的哈希函数,然后计算哈希结果。缺点是安全性很差。
    (2)基于公钥加密的PSI:有基于Diffie-Hellmann(DH)的,有基于RSA盲签名的,有基于bloom filter的,基于OPRF的,基于多项式插值的。
    (3)基于电路的PSI:主要分为两个小部分,一是基于GoldreichMicali-Wigderson protocol计算协议,另外一个是基于姚期智教授的混淆电路计算协议。
    (4)基于遗忘传输的PSI:这也现在比较流行的PSI协议,基于OT的PSI协议B.Pinkas, T.Schneider, M. Zohner.Scalable Private Set Intersection Based on OT.Simple, Fast Malicious Multiparty Private Set Intersection

    4.2 不经意传输 Oblivious Transfer,OT

    不经意传输(oblivioustransfer)是一个密码学协议,在这个协议中,消息发送者从一些待发送的消息中发送一条给接收者,但事后对发送了哪一条消息仍然oblivious(不知道),这个协议也叫茫然传输协议。

    第一种形式的不经意传输(oblivious transfer),最初是在1981由Michael O.Rabin提出,在这种不经意传输中,发送者Alice发送一条消息给接收着Bob,而Bob以1/2的概率接收到信息,在结束后Alice并不知道Bob是否接收到了信息,而Bob能确信地知道自己是否收到了信息。

    另一种更实用的不经意传输协议,被称为2选一不经意传输(1 out 2 oblivious transfer)由 Shimon Even, Oded Goldreich, 和Abraham Lempel 在1985年提出,在这种形式的不经意传输模型中,Alice每次发两条信息(m1、m2)给Bob,Bob提供一个输入,并根据输入获得输出信息,在协议结束后,Bob得到了自己想要的那条信息(m1或者m2),而Alice并不知道Bob最终得到的是哪条,参考例子

    有许多不经意传输的构造方法:Bellare-Micali构造Naor-Pinka构造以及Hazay-Lindell构造

    4.3 Secret Share MPC Protocol(SPDZ)

    4.4 姚式混淆电路(Yao’s Garbled Circuit)

    一种著名的基于不经意传输的两方安全计算协议,它能够对任何函数进行求值。混淆电路的中心思想是将计算电路(我们能用与电路、或电路、非电路来执行任何算术操作)分解为产生阶段和求值阶段。每一方都负责一个阶段,而在每一阶段中电路都被加密处理,所以任何一方都不能从其他方获取信息,但他们仍然可以根据电路获取结果。混淆电路由一个不经意传输协议和一个分组密码组成。电路的复杂度至少是随着输入内容的增大而线性增长的。

    5 秘密共享(Secret Sharing)

    秘密共享(Secret Sharing,SS)是1979年由Shamir和Blakey提出的,并在此之后40多年秘密共享被广泛认识和深入的研究。

    博文1介绍的,秘密共享著名的(t,n)阈值方案如图所示:设秘密s被分成n个部分,每一部分被称为一个子秘密并由一个持有者持有,并且大于等于t个参与者所持有的子秘密可以重构恢复秘密s,而少于t个参与者所持有的子秘密无法重构秘密并且无法获得秘密s的任何信息。
    参考文献:1、Secret-sharing schemes: A survey;2、Secret sharing for cloud data security: a survey;3、A survey on perfectly-secure verifiable secret-sharing;4、简单例子;5、进展博文;

    秘密共享主要包括算数秘密共享(Arithmetic Secret Sharing)、Shamir秘密共享和二进制秘密共享(Binary Secret Sharing)

    5.1 Feldman Verifiable Secret Sharing

    Feldman Verifiable Secret Sharing简称(Feldman VSS算法),作者Paul Feldman于1997年的论文《A Practical Scheme for Non-interactive Verifiable Secret Sharing》是第一个有效的VSS算法。

    6 可信计算,Trusted Computing

    可信计算/可信用计算(Trusted Computing,TC)是一项由可信计算组(可信计算集群,前称为TCPA)推动和开发的技术。可信计算是在计算和通信系统中广泛使用基于硬件安全模块支持下的可信计算平台,以提高系统整体的安全性。可信计算概述中描述,在计算平台中,首先创建一个安全信任根,再建立从硬件平台、操作系统到应用系统的信任链,在这条信任链上从根开始一级测量认证一级,一级信任一级,以此实现信任的逐级扩展,从而构建一个安全可信的计算环境。有点类似区块链的想法。一个可信计算系统由信任根、可信硬件平台、可信操作系统和可信应用组成,其目标是提高计算平台的安全性。

    1999年, IBM、HP、Intel和微软等著名IT企业发起成立了可信计算平台联盟(TCPA, Trusted Computing Platform Alliance),这标志着可信计算进入产业界。2003年,TCPA 改组为可信计算组织(TCG, Trusted Computing Group)。目前,TCG已经制定了一系列的可信计算技术规范,如可信PC、可信平台模块(TPM)、可信软件栈(TSS)、可信网络连接(TNC)、可信手机模块等,且不断地对这些技术规范进行修改完善和版本升级,参考可信计算的原理是整个链路都经过可信认证,所以无论从应用、操作系统还是硬件,必须经过授权才能使用,其包括5个关键技术概念:认证密钥,安全输入输出,内容屏蔽/受保护执行,封装存储,远程证明。

    按照发展历程,我国沈昌祥院士认为:软件可靠性相关的可信计算定义为可信1.0,TCG的可信计算定义为可信2.0,而沈院士的可信理念则定义为可信3.0

    6.1 可信执行环境(Trusted Execution Environment,TEE)

    可信执行环境(Trusted Execution Environment,TEE)是运行在分离核心之上的一种防篡改处理环境,它为执行代码的真实性以及运行时完整性提供保证,为其持久存储器保存的代码、数据、运行状态等信息提供保证,此外,TEE也提供远程证明以及第三方信任机制。目前得到了包括ARM、AMD、英特尔等众多机构和厂商的支持,中国也有大量的企业与机构参与到与TEE相关的国际组织活动中。TEE的最初的标准是OTMP制定的《ADVANCED TRUSTED ENVIRONMENT: OMTP TR1》,随着OTMP组织的解散,标准被GSMA掌握。目前TEE的标准工作大部分是非盈利组织GlobalPlatform推动的,该组织致力于TEE相关规范建设,推动TEE与TPM的整合,并提出了安全元素(Secure Elements,SE)的相关主张。与TPM的整体安全保护不同,TEE更注重于为第三方应用软件提供一个保护环境,参考1

    6.2 可信任平台模块 (Trusted Platform Module,TPM)

    TPM是具有加密功能的安全微控制器,旨在提供涉及加密密钥的基本安全功能。TPM芯片集成在主板上并通过硬件总线与系统的其他部件通信。TPM作为可信计算平台的核心,实际上是一块安装在主板上,含有密码运算部件和存储部件的系统级芯片。TPM技术最核心的功能在于对CPU处理的数据流进行加密,同时监测系统底层的状态。在此基础上,可以开发出唯一身份识别、系统登录加密、文件夹加密、网络通讯加密等各个环节的安全应用,它能够生成加密的密钥,还有密钥的存储和身份的验证,可以高速进行数据加密和还原,作为保护BIOS和OS不被修改的辅助处理器,通过TSS与TPM的结合来构建跨平台与软硬件系统的可信计算体系结构。即使用户硬盘被盗也不会造成数据泄漏。TPM的序号无法轻易被读出,其读取过程经过加密算法处理,与IC卡一样具有传输加密的安全特性,即TPM芯片就是一颗内嵌于计算机内的智能卡,该芯片的序号代表着该机、该装置、该硬件等信息。TPM上的数字就如同身份证号码,是唯一识别而不重复的一组数字,参考

    6.3 可信计算模块(Trusted Computing Module,TCM)

    中国拥有自主知识产权的可信计算规范被称为TCM(Trust C Module),与之对应的国际可信计算的规范TPM。TCM与TPM1.2有很多的相同点,TCM是借鉴了TPM1.2的架构,替换了其核心算法后的产品。

    6.4 可信软件栈(Trusted Software Stack,TSS)

    7 摘要算法

    消息摘要算法的主要特征是加密过程不需要密钥,并且经过加密的数据无法被解密,可以被解密逆向的只有CRC32算法,只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文。消息摘要算法主要应用在“数字签名”领域,作为对明文的摘要算法。著名的摘要算法有RSA公司的MD5算法和SHA-1算法及其大量的变体。消息摘要是把任意长度的输入揉和而产生长度固定的伪随机输出的算法。几乎所有的数字签名方案都要和快速高效的摘要算法(Hash函数)一起使用,当公钥算法与摘要算法结合起来使用时,便构成了一种有效地数字签名方案。

    这个过程是:首先用摘要算法对消息进行摘要,然后在把摘要值用信源的私钥加密;接收方先把接收的明文用同样的摘要算法摘要,形成“准签体”,然后再把准签体与用信源的公钥解密出的“签体”进行比较,如果相同就认为消息是完整的,否则消息不完整。这种方法使公钥加密只对消息摘要进行操作,因为一种摘要算法的摘要消息长度是固定的,而且都比较“短”(相对于消息而言),正好符合公钥加密的要求。这样效率得到了提高,而其安全性也并未因为使用摘要算法而减弱。

    消息摘要的主要特点有:

    • 无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。例如应用MD5算法摘要的消息有128个比特位,用SHA-1算法摘要的消息最终有160比特位的输出,SHA-1的变体可以产生192比特位和256比特位的消息摘要。一般认为,摘要的最终输出越长,该摘要算法就越安全。
    • 消息摘要看起来是“随机的”。这些比特看上去是胡乱的杂凑在一起的。可以用大量的输入来检验其输出是否相同,一般,不同的输入会有不同的输出,而且输出的摘要消息可以通过随机性检验。但是,一个摘要并不是真正随机的,因为用相同的算法对相同的消息求两次摘要,其结果必然相同;而若是真正随机的,则无论如何都是无法重现的。因此消息摘要是“伪随机的”。
    • 一般地,只要输入的消息不同,对其进行摘要以后产生的摘要消息也必不相同;但相同的输入必会产生相同的输出。这正是好的消息摘要算法所具有的性质:输入改变了,输出也就改变了;两条相似的消息的摘要确不相近,甚至会大相径庭。
    • 消息摘要函数是无陷门的单向函数,即只能进行正向的信息摘要,而无法从摘要中恢复出任何的消息,甚至根本就找不到任何与原信息相关的信息。当然,可以采用强力攻击的方法,即尝试每一个可能的信息,计算其摘要,看看是否与已有的摘要相同,如果这样做,最终肯定会恢复出摘要的消息。但实际上,要得到的信息可能是无穷个消息之一,所以这种强力攻击几乎是无效的。
    • 好的摘要算法,没有人能从中找到“碰撞”,虽然“碰撞”是肯定存在的。即对于给定的一个摘要,不可能找到一条信息使其摘要正好是给定的。或者说,无法找到两条消息,使它们的摘要相同。

    7.1 消息摘要 Message Digest,MD

    消息摘要算法生成的消息摘要都是128位的。包括:MD2,MD4,MD5;从安全性上说:MD5 > MD4 > MD2。电驴(点对点的下载工具)使用的是经过改良的MD4的算法,这种改良后的MD4算法主要是用于通过P2P下载的文件截成块,分块之后进行摘要,通过摘要来验证所文件的最终的完整性,如果不完整是解压不开的,参考

    7.2 安全散列 Secure Hash Algorithm, SHA

    安全散列算法也是输出固定长度摘要信息,包括:SHA-1,SHA-2(SHA-224,SHA-256,SHA-384,SHA-512)等。

    7.3 消息认证码 Message Authentication Code,MAC

    HMAC(keyed-Hash Message Authentication Code):含有密钥的散列函数算法,包含了MD和SHA两个系列的消息摘要算法,HMAC只是在原有的MD和SHA算法的基础上添加了密钥。其融合了MD,SHA:

    • MD系列:HmacMD2,HmacMD4,HmacMD5
    • SHA系列:HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA38, HmacSHA512

    8 密钥交换协议

    密钥交换指的是不通过第三方完成双方的密钥交换。传统上,双方之间的安全加密通信要求他们首先通过一些安全的物理渠道来交换密钥,比如电话事先告知等。其中Diffne Hellman密钥交换是最经典的,Diffie-Hellman密钥交换方法允许双方通过一个不安全的渠道直接建立一个共享的密钥,这个密钥的对称密钥被用来加密接下来的通信,密钥交换协议

    8.1 Diffne Hellman Key Exchange

    这里给出了DH的介绍:

    OAKLEY
    SKEME

    防御性蒸馏
    对抗训练正则化

    参考文献

    [] 联邦学习:保护用户数据隐私
    [] 联邦学习的研究与应用 ccf-tf 14
    [] mit的什么是差分隐私
    [] 哈佛的差分隐私定义
    [] [DP]Learning With Differential Privacy
    [] [DP]The Algorithmic Foundations of Differential Privacy
    [] [SPDZ]Multiparty Computation from Somewhat Homomorphic Encryption
    [] [SPDZ]Overdrive: Making SPDZ Great Again
    [] [Paillier]Public-Key Cryptosystems Based on Composite Degree Residuosity Classes
    [] [PSI]Private Set Intersection(PSI)简介和资料分享
    [] [PSI]Private Set Intersection(PSI
    [] [PSI]隐私集合求交(Private Set Intersection,PSI)技术的发展、挑战与未来 (二),有论文列表
    [] [MPC]Secure Multiparty Computation (MPC)
    [] [SS]秘密分享Secret Sharing
    [] [TC]可信计算与可信执行环境TEE学习研究资源整理

  • 相关阅读:
    eclipse新建JSP页面报错:Multiple annotations found at this line解决方法
    yum 安装报错:*epel: mirrors.aliyun.comError: xzcompressionnot available
    shell脚本中定义路径变量出现的BUG
    Rsync 12种故障排查及思路
    定时清除 /var/log/massage 下的信息脚本文件
    企业集群架构之全网备份
    局域网的某个机器无法上网,的排错思路
    日志审计
    在VUE中使用富文本编辑器ueditor
    ABP框架使用 Swagger
  • 原文地址:https://www.cnblogs.com/shouhuxianjian/p/16049432.html
Copyright © 2020-2023  润新知