在一线互联网公司就职,对技术工作充满热爱,希望一生走技术的道路。
分类: C/C++
2018-08-02 15:32:25
开发背景->开放平台对接外部客户需要对外数据交换
数据安全->数据加密
多客户数据间隔离->隔离方案(数据隔离,安全加解密隔离)
有了背景了解我们自然想到数据加密的方式,下面了解一下有哪些加密方法。
加密方式:对称加密,非对称加密
1.对于对称性加密算法,信息接收双方都需事先知道密匙和加解密算法且其密匙是相同的
几种对称性加密算法:AES,DES,3DES
DES是一种分组数据加密技术(先将数据分成固定长度的小数据块,之后进行加密),速度较快,适用于大量数据加密,而3DES是一种基于DES的加密算法,使用3个不同密匙对同一个分组数据块进行3次加密,如此以使得密文强度更高。
相较于DES和3DES算法而言,AES算法有着更高的速度和资源使用效率,安全级别也较之更高了,被称为下一代加密标准。
2.非对称加密算法需要两个密钥来进行加密和解密,这两个秘钥是公开密钥(public key,简称公钥)和私有密钥(private key,简称私钥)
几种非对称性加密算法:RSA,DSA,ECC(椭圆曲线加密算法)
RSA是企业级应用标准,使用最广泛的是RSA算法,RSA和DSA的安全性及其它各方面性能都差不多,而ECC较之则有着很多的性能优越,RSA是企业级应用标准,164bitECC约等于1024bit的RSA,经常使用在移动设备上。
在实际的操作过程中我们通常采用的方式是:采用非对称加密算法进行签名校验,然后用对称加密算法加密数据,这样我们就集成了两类加密算法的优点,既实现了加密速度快的优点,又实现了安全方便管理密钥的优点。如果在选定了加密算法后,那采用多少位的密钥呢?一般来说,密钥越长,运行的速度就越慢,应该根据的我们实际需要的安全级别来选择,一般来说,RSA建议采用1024位的数字,AES采用128位。
糖大夫开放平台安全加密具体怎么做的呢?
我们选用了128位AES对称加密和1024位RSA非对称加密结合的方式保证数据安全,所有的请求必须通过非对称加密方法生成签名,服务端先进行签名校验,通过后才会处理数据。(外部合作方通过公钥生成签名,开放平台通过私钥解密校验)
1.生成签名规则:传输内容content+ts(时间戳)进行MD5得到值 md5,对md5进行RSA公钥加密并base64encode得到签名字段值sign
2.签名校验规则:对sign进行base64decode然后进行RSA解密得到md5,获取内容密文进行AES解密获得内容加ts进行md5运算 跟sign解密得到的比对。
3.传输的内容进行AES加密,然后将到的结果再进行base64编码后传输。
AES 和RSA加解密我采用了openssl库,使用openssl库有几点注意:128位AES加密是以128位也就是16个字节作为一个块来存储数据,如果数据长度不是16字节整数倍需要填充,填充模式需要自己实现,我采用zeropadding模式 填充,如果用pkpadding方式可能会打印日志的时候显示乱码,对功能没影响。
代码:
if (data_bak.length() % AES_BLOCK_SIZE > 0)
{
padding = AES_BLOCK_SIZE - data_bak.length() % AES_BLOCK_SIZE;
}
data_length += padding;
while (padding > 0)
{
data_bak += '\0';
padding--;
}
在使用openssl的RSA加解密的时候,由于RSA_new()和RSA_free()会依赖一个全局的hash表,网上有的文章提示需要调用API CRYPTO_cleanup_all_ex_data清楚管理CRYPTO_EX_DATA的全局hash表。但是如果你的程序是多线程会引起core,为什么呢?
看看原始说明:
/* Release all "ex_data" state to prevent memory leaks. This can't be made
* thread-safe without overhauling a lot of stuff, and shouldn't really be
* called under potential race-conditions anyway (it's for program shutdown
* after all). */
void CRYPTO_cleanup_all_ex_data(void)
{
IMPL_CHECK
EX_IMPL(cleanup)();
}
我理解这个函数是非线程安全的,是进程内共享的,所以一个线程释放了hash数据其他线程正在进行rsa加解密就会无法获取到从而导致非法内存访问,只有在程序真正需要关闭的时候调用已避免内存泄漏。
我们这样的方案可以防御什么?
1.传输内容都是特定秘钥加密的,保证传输安全,无法截获解密。
2.无法篡改内容构造请求:签名中包含传输内容的md5,传输内容如果被修改md5将不同,签名校验无法通过。
3.无法网络劫持请求重放,因为请求中带了ts时间戳,ts无法被修改,服务端会校验请求时间的有效性(一般时间有效性间隔服务端通过配置自己定义,时间间隔越短安全性越高,时间间隔越大容错性越强)。
来点详细的:
名称 |
作用 |
生成 |
appid |
第三方的唯一标识id |
由糖大夫统一分配 |
ts |
请求时的时间戳 |
请求时的时间戳 |
sign |
请求内容的签名,用于确认请求的合法性、不可抵赖性 |
通过糖大夫分配的RSA公钥,对请求内容加ts的md5RSA签名得到 |
content |
实际请求体加密后的内容,保证信道传输的安全,原文以json格式组成。 |
原始的json实际请求字段,通过糖大夫分配的AESKEY进行加密后得到 |
示例:
testc79nhdppcbt5ovnwafrzzwljdg920ve56e1srj4mx1mahrv6obacr05w36t5
1490260173
E2qxUyIXPw6/YH6SNH/TCOw7rHaoSasiUYr8d6PEtf6zinUdcE6UjwwNrfuMAhXWUBwS4rrEOJYBYdkcE26kSViMznceQBEEvoKKo3eTWF/kz6/xsIkAXtjorH12iSb60Uri9d9Jj3LGvDNUwbHu9i2VuGA9ui7Adcs7+cUUbFs=
mt7r6f4jxsX0UPrQq2T8VGYVjT5w4p319UHsL2mcPtSygZvjHGmenp2uSiLO2q+0HGGUgcwZ6F BSz1thvZdmjA==
上面是糖大夫开放平台的数据交换格式,appid是身份标识,ts是时间戳明文(主要用于检测合作方服务器时间偏差),content和sign是加密后的密文,在不知道AES秘钥和RSA秘钥的情况下是无法修改密文的,appid必须是糖大夫之前分配的有效id,ts虽然是明文但是sign中也包含了ts进行的加密,所以篡改ts会签名校验不通过。
为了保证多客户之间的数据隔离,我们每个appid分配的AES秘钥和RSA秘钥都是不同的。同时从业务逻辑上我们客户的设备的归属也做了校验,对应的客户只能获取隶属于自己的设备的血糖数据。
糖大夫数据开放平台体系架构介绍
糖大夫开放平台目前统一使用HTTP协议。
目前提供两类数据交互方式:
(1)第三方主动拉取,该方式可以方便第三方指定获取想要的数据、历史数据,主动上传数据。
(2)糖大夫推送给第三方,该方式可以实时地将数据同步给第三方。
糖大夫开放平台-合作方拉取模型
糖大夫开放平台-推送数据模型
推送模型使用了hippo组建作为消息队列,统一申请了topic生产组和消费自,hippo介绍可以参考:
平台内做了哪些数据安全校验,隔离和优化:
1.接口权限授权校验,每个合作方能够获取哪些数据必须约定好在服务端进行授权,否则调用时权限校验不通过,无法获取数据。
2.设备隶属关系校验,合作方主动获取某些设备对应的血糖或其他信息时会进行设备归属校验,非自身名下的设备数据会自动过滤。
3.调用记录和推送数据的可追溯性,所有的调用请求和推送记录都会进行日志记录,对于请求原始数据及服务应答数据都有详细记录,方便核对数据,日志表进行了合理的分表操作保证高效。
4.配置修改热生效,授权和配置修改不需要重启服务,有独立的线程定时拉取配置保证数据能够及时生效,线程内部加了读写锁避免了脏数据产生,内存配置校验也减轻db操作,提高权限校验性能。
5.拉取个性化数据模块与开放平台解耦,个性化数据模块由独立的业务模块提供,通过内网与开放平台交互,数据处理逻辑不在开放平台内部,开放平台做为对外交互的统一入口。