chinapnr / fishbase

自主开发、整理的一套 Python 基础函数库,涵盖 system 系统增强包、logger 日志记录增强包、file 文件处理增强包、 date 日期处理函数包、data 数据信息处理函数包、csv 处理增强函数包、crypt 加密/编码增强包等,可减少程序开发工作量、降低引用复杂度。
MIT License
94 stars 29 forks source link

获取敏感数据的掩码表示 #292

Closed jacsonking closed 3 years ago

jacsonking commented 3 years ago

敏感数据包括:身份证号、银行卡号、手机号、邮箱


class GetSensitiveMask(object):
    """
    获取敏感数据的掩码表示
    """
    @staticmethod
    def identity_number(data):
        """
        身份证号掩码表示(前 3 后 3 显示)
        :param:
            * data(string): 身份证明文
        :return:
            * mask_data(string): 身份证的掩码表示
        """
        return data[:3] + '*' * (len(data) - 6) + data[-3:]

    @staticmethod
    def bankcard_number(data):
        """
        银行卡号掩码表示(前 6 后 4 显示)
        :param:
            * data(string): 银行卡明文
        :return:
            * mask_data(string): 银行卡号的掩码表示
        """
        return data[:6] + '*' * (len(data) - 10) + data[-4:]

    @staticmethod
    def mobile_number(data):
        """
        手机号掩码表示(前 3 后 4 显示)
        :param:
            * data(string): 手机号明文
        :return:
            * mask_data(string): 手机号的掩码表示
        """
        # 后4位掩码表示
        return data[:3] + '*' * 4 + data[-4:]

    @staticmethod
    def email(data):
        """
        手机号掩码表示(@之前首末位显示)
        :param:
            * data(string): 手机号明文
        :return:
            * mask_data(string): 手机号的掩码表示
        """
        # email, @之前首末位显示,其余掩码
        need_mask = data.split('@')[0][1:-1]
        mask_data = data.replace(need_mask, '*' * len(need_mask))
        return mask_data
wingfish commented 3 years ago

是需要提供上述功能?

jacsonking commented 3 years ago

是需要提供上述功能?

是的,希望 fishbase 能提供该功能,个人觉得该功能与业务无关,并且使用频率较高,建议纳入 fishbase。

类及方法实现如下:


class GetSensitiveMask(object):
    """
    获取敏感数据的掩码表示

    举例如下::

        print('--- GetSensitiveMask demo ---')
        print(GetSensitiveMask.identity_number('429004199205270758'))
        print(GetSensitiveMask.bankcard_number('9558800200136454752'))
        print(GetSensitiveMask.mobile_number('13958462541'))
        print(GetSensitiveMask.email('xiaolongli@163.com'))
        print('---')

    执行结果::

        --- GetSensitiveMask demo ---
        429************758
        955880*********4752
        139****2541
        x********i@163.com
        ---

    """

    @staticmethod
    def identity_number(data):
        """
        身份证号掩码表示(前 3 位后 3 位显示,其他掩码)
        :param:
            * data(string): 身份证号明文
        :return:
            * mask_data(string): 身份证号掩码表示
        """
        return data[:3] + '*' * (len(data) - 6) + data[-3:]

    @staticmethod
    def bankcard_number(data):
        """
        银行卡号掩码表示(前 6 位后 4 位显示,其他掩码)
        :param:
            * data(string): 银行卡号明文
        :return:
            * mask_data(string): 银行卡号掩码表示
        """
        return data[:6] + '*' * (len(data) - 10) + data[-4:]

    @staticmethod
    def mobile_number(data):
        """
        手机号掩码表示(前 3 位后 4 位显示,其他掩码)
        :param:
            * data(string): 手机号明文
        :return:
            * mask_data(string): 手机号掩码表示
        """
        # 后4位掩码表示
        return data[:3] + '*' * 4 + data[-4:]

    @staticmethod
    def email(data):
        """
        邮箱账号掩码表示(@之前首末位显示,其他掩码)
        :param:
            * data(string): 邮箱账号明文
        :return:
            * mask_data(string): 邮箱账号掩码表示
        """
        need_mask = data.split('@')[0][1:-1]
        mask_data = data.replace(need_mask, '*' * len(need_mask))
        return mask_data
wingfish commented 3 years ago

我大致明白你意思了,我会看一下你的代码并测试一下,最近正好要发1.4版本。

wingfish commented 3 years ago

该 class 放在 data 这里; 1 英文专用名字和 data 其他 class 保持一致,IdCard ; 2 增加demo 代码; 3 增加单元测试 tc 来验证掩码显示是否正确; 4 发现 random class 中命名不够规范,之后需要修改, bankcard 等; gen_random_bank_card() gen_random_id_card()

jacsonking commented 3 years ago

我大致明白你意思了,我会看一下你的代码并测试一下,最近正好要发1.4版本。

好的。另外,我思考了一下,建议如下: 1 类名参考 SensitiveDataMask; 2 获取身份证号掩码方法名参考 idcard_number; 3 所有方法添加两个参数(即需要显示前,后的明文数),原方法中的值作为默认值;比如:mobile_number(data, front=3, behind=4) 表示前 3,后 4 显示明文,其他掩码; 4 原 demo_data.py 中存在方法可能未同步更新,比如:IdCard.get_zonecode_by_area(),CardBin.get_bank_by_name(),经简单测试发现应该分别对应方法:IdCard.get_zone_info() 和 CardBin.get_bank_info();

wingfish commented 3 years ago

1 我这次的修改,的确class name我修改了,get作为动词都到里面觉得方法了。 2 前后明文数参数这次先不修改了,目前这样从实用角度应该可以,我考虑之后四个方法可以合并成一个方法,idcard等也作为参数,不过那样要考虑的细节会增加不少。 3 demo中的确这两年很多没有加入,我会这次先调整掩码这些。

具体代码和ut的代码如下,ut还比较简单,只验证了一个成功,对于出错处理也比较简单,ut也还没有加入。

# v1.4 edit by David Yi, 根据 @jacsonking #292 建议和代码,增加敏感数据掩码类
class SensitiveMask(object):
    """
    获取敏感数据的掩码表示

    举例如下::

        print('--- GetSensitiveMask demo ---')
        print(SensitiveMask.identity_number('429004199205270758'))
        print(SensitiveMask.bankcard_number('9558800200136454752'))
        print(SensitiveMask.mobile_number('13958462541'))
        print(SensitiveMask.email('xiaolongli@163.com'))
        print('---')

    执行结果::

        --- GetSensitiveMask demo ---
        429************758
        955880*********4752
        139****2541
        x********i@163.com
        ---

    """

    @staticmethod
    def get_idcard_number(data):
        """
        身份证号掩码表示(前3位后3位显示,其他用掩码*表示)
        :param:
            * data(string): 身份证号明文
        :return:
            * mask_data(string): 身份证号掩码表示
        """
        try:
            mask_data = data[:3] + '*' * (len(data) - 6) + data[-3:]
            return mask_data
        except ValueError:
            print("转换身份证掩码时发生错误")

    @staticmethod
    def get_bankcard_number(data):
        """
        银行卡号掩码表示(前6位后4位显示,其他用掩码*表示)
        :param:
            * data(string): 银行卡号明文
        :return:
            * mask_data(string): 银行卡号掩码表示
        """
        try:
            mask_data = data[:6] + '*' * (len(data) - 10) + data[-4:]
            return mask_data
        except ValueError:
            print("转换银行卡掩码时发生错误")

    @staticmethod
    def get_mobile_number(data):
        """
        手机号掩码表示(前3位后4位显示,其他用掩码*表示)
        :param:
            * data(string): 手机号明文
        :return:
            * mask_data(string): 手机号掩码表示
        """
        try:
            mask_data = data[:3] + '*' * 4 + data[-4:]
            return mask_data
        except ValueError:
            print("转换手机号码掩码时发生错误")

    @staticmethod
    def get_email(data):
        """
        邮箱账号掩码表示(@之前首末位显示,其他用掩码*表示)
        :param:
            * data(string): 邮箱账号明文
        :return:
            * mask_data(string): 邮箱账号掩码表示
        """
        try:
            need_mask = data.split('@')[0][1:-1]
            mask_data = data.replace(need_mask, '*' * len(need_mask))
            return mask_data
        except ValueError:
            print("转换电子邮件掩码时发生错误")

unittest

    # 2021.6.22 edit by David Yi,
    def test_get_idcard_number_01(self):
        values = SensitiveMask.get_idcard_number('620105199412201639')
        assert values == '620************639'

    def test_get_bankcard_number_01(self):
        values = SensitiveMask.get_bankcard_number('4391880006990109')
        assert values == '439188******0109'

    def test_get_mobile_number_01(self):
        values = SensitiveMask.get_mobile_number('13801108286')
        assert values == '138****8286'

    def test_get_email_01(self):
        values = SensitiveMask.get_email('david@gmail.com')
        assert values == 'd***d@gmail.com'

非常感谢交流,多多联系!