bk-user icon indicating copy to clipboard operation
bk-user copied to clipboard

【暂不支持】数据库存储字段加密处理;页面展示信息脱敏处理

Open Zoeyzhou11 opened this issue 2 years ago • 8 comments

需求背景 1、按照《个人信息安全法》实现用户数据的保护,数据库中,涉及到用户个人信息的数据需要进行加密储存,如姓名(第三级)、手机(第二级)、邮箱(第二级)、密码(第四级)。 2、第一条中信息中,需要实现加密传输。主要场景为用户登陆时需要密文传输。 3、加密算法:通过国密(SM4)、AES-GCM(>=128bits) (SM4算法是某客户强制要求的,AES也有客户提出,但需求强度不大,麻烦 @Xmandon 评估一下是否可以同步支持

原始需求截图: image

需求描述 1、不同客户可能会要求页面展示信息脱敏,希望在用户字段配置时,可以配置用户字段信息在页面上是否脱敏展示,同时配置字段信息在数据库是否加密,以及加密方式 2、用户登录时,用户密码密文传输 3、(拓展)《个人信息安全法》中提到,信息传输需要符合相关的保密法规,一般客户都会较为关注内网安全,因此在内网中用户管理数据被上其他saas调用时,可以为明文传输。但用户管理通过开放接口向外部系统推送数据时,可能需要支持加密传输

Zoeyzhou11 avatar Aug 22 '22 09:08 Zoeyzhou11

优先设计和排期

Xmandon avatar Aug 29 '22 03:08 Xmandon

2、用户登录时,用户密码密文传输

done

Xmandon avatar Oct 10 '22 03:10 Xmandon

https://cloud.tencent.com/document/product/573/49386 https://cloud.tencent.com/developer/article/1695498

wklken avatar Oct 26 '22 02:10 wklken

国密加密的事情,暂时不支持,需要统一调研方案实现。

Xmandon avatar Oct 26 '22 03:10 Xmandon

1.优先支持 <国密加密-手机、邮箱、ip字段>; 2.本次需求开发暂不包括加密条件下支持搜索功能 3.字段脱敏展示,转另一个issue跟进:https://github.com/TencentBlueKing/bk-user/issues/769

Canway-shiisa avatar Nov 07 '22 06:11 Canway-shiisa

开发方案:

加密字段

Profile: display_name / telephone / email

LogIn: extra_value (包含了client_ip)【整个extra_value进行加密】

加密思路
  1. 支持对应字段存储加密 (Django Encrypt Field)【上层接口/产品无影响, 在ORM 查询就消化掉了加解密】
  2. 可注入加密扩展
  3. 对存量数据进行加密适配【数据升级脚本】
加密方案
  1. 支持对应字段存储加密
encryption_algorithm = settings.EncryptionAlgorithm
encryption_algorithm_map = {
    "SM4": SM4Handler
}

class EncryptedMixin(models.Field):
    internal_type = "CharField"
    prepared_max_length = None
	
    def __init__(self, key=None, **kwargs):
        kwargs.setdefault('max_length', self.prepared_max_length)
	# 设置成⼀个注⼊, 根据环境变量确定这套环境的加密⽅式是什么
	self.handler = encryption_algorithm_map["encryption_algorithm"]
 	super().__init__(**kwargs)
        
    def get_db_prep_value(self, value, connection, prepared=False):
         value = super().get_db_prep_value(value, connection, prepared)
 	 if value is not None:
	    encrypted_text = self.handler.encrypt(value)
	    if self.max_length and len(encrypted_text) > self.max_length:
 	        raise EncryptedFieldException(f"Field {self.name} max_length={self.max_length}encrypted_len={len(encrypted_text)}")
	    return encrypted_text
 	return None
        
    def from_db_value(self, value, expression, connection, *args):
         if value is None:
             return value
 	 return self.to_python(self.handler.decrypt(value))
        
    def get_internal_type(self):
         return self.internal_type
 
class EncryptedTextField(EncryptedMixin, models.TextField):
    internal_type = "TextField"
    
class EncryptedCharField(EncryptedMixin, models.CharField):
    internal_type = "CharField"
  1. SM4加密处理
from gmssl.sm4 import CryptSM4, SM4_ENCRYPT, SM4_DECRYPT

SM4_KEY = settings.SM4_KEY	# bytes类型
class SM4Handler():
    def encrypt(self, plain_text) -> str:
        # 将python格式数据转换成json,再转换成bytes,sm4加密bytes格式数据;
        value = bytes(json.dumps(plain_text), 'utf-8')
        crypt_sm4 = CryptSM4()
        crypt_sm4.set_key(SM4_KEY, SM4_ENCRYPT)

    	# 使用crypt_ecb进行加密value
        encrypt_value = crypt_sm4.crypt_ecb(value)
        return encrypt_value
        
    def decrypt(self, encrypted_text) -> str:
	crypt_sm4 = CryptSM4()
   	crypt_sm4.set_key(SM4_KEY, SM4_DECRYPT)
        # 将加密数据通过SM_KEY进行解密;
        decrypt_value = crypt_sm4.crypt_ecb(encrypted_text)

        # 解密数据转换为python格式数据;
        value = json.loads(str(decrypt_value, 'utf-8'))
        return value
  1. model处理
class User(models.Model):
    display_name = EncryptedCharField(algorithm="sm4", verbose_name=_("用户名"), default=None)
    telephone = EncryptedCharField(verbose_name=_("手机号"), default=None)
    email = EncryptedCharField(verbose_name=_("邮箱地址"), default=None)
    extras = EncryptedJsonField(verbose_name=_("自定义字段"), default={})    

Canway-shiisa avatar Nov 07 '22 09:11 Canway-shiisa

  • SM4Handler to SM4CryptHander, 并且继承一个基类
  • 需要支持 环境变量-> 配置文件 配置加密算法/加密key
  • 需要确认精确查询是否能拿到 object.get(telephone=123456) / object.filter(email="[email protected]")
  • 加密后的字段长度, 会不会超过原先的设置(需要考虑, 最大长度会是多少, 新装及环境升级)
  • 写一个测试demo验证下, 然后重新贴下代码(上面的代码格式是错乱的)

wklken avatar Nov 07 '22 11:11 wklken

加密后, 前端的功能以及后台接口会受到影响

例如手机号加密后, 无法模糊搜索, 产品前端的搜索入口+后台搜索接口都会受影响, 只能精确匹配 => 影响用户体验及上游系统的用户体验

wklken avatar Jan 30 '23 02:01 wklken