也说Hadoop敏感信息加密方案的尝试(上) 原

#前言 每个公司都会遇到数据安全性的问题,数据在当下甚至未来,其安全性只会越来越重要。而在大数据的环境下,数据多以集群存储,量大而复杂是大数据的一个重要特征,在这种情况下,数据的安全性方案该如何设计才能保证数据安全,同时保证集群负载小,对外透明度高呢?

目前的集群状况是上了Kerberos,我想这是集群安全性的一个必要前提,即使你说集群位于公司内网,但是没上Kerberos谈安全和权限就没什么卵用。其次集群上了Sentry,这是对权限管理的进一步加强,对Hive表可控制权限到列,对HDFS文件也可做具体权限控制。

一个公司大量的数据可能都是行为数据,所以并没有太多需要保密的处理,需要加密的往往是敏感数据,比如身份证信息,某些ID等。HDFS在文件层面提供了透明加密机制,配置好后可创建加密区,通过API又可把数据从加密区恢复出来,在DataNode端直接查看Block块,数据是加密的,保证了安全性。但是它针对所有数据加密,虽说对上层透明,安全好用,但是对集群压力大,很多不需要加密的数据做加密处理,是一种资源浪费。

这里想要提到的方案就是针对Hive表字段加密,一个表具备几十个字段,需要做保护的可能只有其中一两个,通过提供一个UDF,在数据入Hive表时,在需要加密的字段上调用,UDF对上层透明,可实现数据保护。在数据需要解密的时候,同样提供UDF用于解密,调用即可得到明文。

#方案 上面的一个想法,造就了很多种不同方案,一个个尝试,一个个排除,最后发现回到原点,只有一种方案合适。尝试过的若干方案分两大类,按处理类型分为数据散列处理AES对称加密

##数据散列处理 散列处理是指Hash一类的处理,算法有md5, sha1, sha-256以及更高位数的散列算法。它有个显著特征是雪崩效应,原文稍有改变,算出来的值就会完全不同。Hash是一种摘要算法,同一种hash算法,针对不同的输入,输出的位数是固定的,所以hash存在碰撞的可能。在用于数据加密的时候,如果存在hash碰撞,就会导致数据丢失,一个明文会覆盖另一个明文。所以通过hash处理的话,就必须通过无碰撞碰撞概率在可接受范围内的验证,同时敏感字段可能因为业务需要而在特定场景下需要还原,而hash不可逆,所以这种方案必须得做好明密文映射表

hash碰撞的概率可参考下图: hash碰撞的概率

对于字段的结构,如果我们很清楚并且在可穷举范围内的话,我们可以选择一个盐,然后穷举所有可能,从而可以找到确定无碰撞的盐。对于无法穷举的,只能验证一下碰撞概率是否在可接受范围内。

###把散列算法布成服务,对外提供明密文访问的API 优势在于:

  1. 服务做Hash计算,有碰撞则换盐,可避免碰撞产生
  2. 密文请求的同时把映射表做完,不用单起服务做映射表,不会漏掉明文
  3. 散列只用做一次,减少计算开销

劣势在于:

  1. 每一行都要请求,服务并发太大,需要设计得好,缓存服务做的非常好
  2. 服务单点,一旦宕机所有数据都没法跑
  3. 最重要的一点,安全和权限管理不好做,一旦API泄露,就可以由明文撞出密文

###在UDF里做散列,控制盐的权限,然后单独起服务做映射表 一个字段对应一个盐,控制好盐的权限,比如把盐存入Hive表里,借用Sentry的权限控制实现表列的权限控制。在UDF里获取盐,然后实现加密,但是解密需要从映射表来,所以得专门起服务做映射表。

优势在于:

  1. 可以避免高并发,没有单点故障
  2. 盐值可实现权限管理,安全性可以得到保障

劣势在于:

  1. 散列碰撞可能存在,数据可能丢失,需验证概率大小是否在可接受范围内
  2. 映射表需单独维护,必须在所有数据入库之前先跑,还要做去重等处理
  3. 映射表的维护要随业务而变,有新的数据源接入就要更改服务,极其麻烦

以上是散列处理的两种具体方案,由于散列的不可逆,导致如果需要还原明文,它的代价就非常大,映射表的维护是极其麻烦的事情,而且备份和安全性都不好处理。但如果企业不要求还原,那这里的第二种方案不失为一个好的方案。

##AES对称加密 AES才是真正的加密算法,上述的散列只能是一种摘要算法,而非加密算法。

AES加密:一种对称加密的算法,加密和解密使用同一种秘钥。加密的过程是向量的移位运算过程,它会对输入进行16字节的划分,然后进行移位运算,解密则是其反向过程。

AES加密有很多不同的模式,不同模式的运算方式不一样,有的模式还需要初始化向量。其中CFBOFB模式不会处理填充情况(即输入不满16字节的,是否填充为16字节)。所以AES的输出长度与输入长度是相关的,与秘钥长度无关。

规律:输入是16*n字节,没有填充的情况下,输出和输入长度相同,有填充的情况下,输出为16*(n+1)。如果输入不是 16字节的整数倍,是16*n16*(n+1)的区间内,没有填充的情况下,输出和输入长度相同,有填充情况下,输出长度是16*(n+1)

在JDK里默认有AES 128位的加解密API,如果需要更高位数的,就需要下载额外的jar包,但一般128位日常加密就够使了。

在AES加密里,我们可以把加密解密放在UDF里,只需做好秘钥Key的管理即可。

前期有个误解,以为Sentry能控制UDF的使用权限,最后验证发现,Sentry其实只能控制UDF的创建权限,而不能控制使用权限。一个普通用户想要有UDF的创建权限,则必须给他关联上hive.aux.jars.path里配置的目录下的jar包的ALL权限。

所以权限的控制只能放在Key的权限上,所有能取到Key的人,就具备了这个key所对应字段的加解密权限。前期以为能对UDF和Key都做权限控制,这样分两级权限,把秘钥在后端做的更透明,可以加强权限的管理,有些人无需解密操作,就可以把解密的UDF不对他开放。结果发现只是我们自己乐了一下~

在AES加解密的秘钥控制上,又有几种不同的细分方案。针对秘钥的存储,分为Hive表存储KMS秘钥管理服务存储

###Hive表存储秘钥 这种方式比较简单(事实证明简单粗暴的往往是最好用的~),很好理解。通过创建多个列,不同列对应不同字段的秘钥,利用Sentry把权限控制到列,即把权限控制到了字段key的级别。

###KMS秘钥管理服务 它是Hadoop本身提供的一个秘钥管理组件,用于HDFS文件加密的,我们可以利用它作为我们秘钥管理的服务,它支持Kerberos认证和SSL,同时对权限可控制到具体key,权限管理上非常方便。

关于KMS秘钥管理服务,这里有单独的一篇文章做介绍,KMS秘钥管理服务

未完待续,下篇博客见 也说Hadoop敏感信息加密方案尝试(下)

欢迎小主们转载,但请注明出处:https://my.oschina.net/u/2539801/blog/808054

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章