需求

开发中需要将配置文件中的敏感信息非明文展示,如数据库账户密码等,本文使用python中的第三方库完成加密解密工作,环境为python3.8

实现

1.加密

from configparser_crypt import ConfigParserCrypt

# 加密文件名称,按需修改
file = 'config_dev.encrypted'

conf_file = ConfigParserCrypt()
# 创建新的aes_key
conf_file.generate_key()
# 创建完的aes_key请保存好,后续需要用来解密
aes_key = conf_file.aes_key
print(aes_key)

# 创建自己的配置项,注意格式,这里键值对里的值我用字典的话后续用get方法报错,改成json格式用json.loads方法获取后正常,可自行尝试有无其他格式或方法
# 该加密库继承自ConfigParser,关于配置可自行搜索相关用法
conf_file.add_section("config")
conf_file["config"] = {"type": "{\"alias\": \"mysql\"}",
                       "database": "{\"host\": \"127.0.0.1\", \"user\": \"username\", \"password\": \"yourpassword\", \"port\": \"3306\",\"database\": \"databasename\"}",
                       "redis": "{\"host\": \"127.0.0.1\", \"port\": \"6379\", \"password\": \"\"}"}
# 写入加密文件
with open(file, 'wb') as file_handle:
    conf_file.write_encrypted(file_handle)

# 将加密文件放入项目配置文件夹下

2.解密

from configparser_crypt import ConfigParserCrypt

# 这边最后是把配置项转成字典
config = dict()
# 加密好的配置文件路径
file_path='your_file_path'
conf_file = ConfigParserCrypt()
# 使用之前生成的aes_key
conf_file.aes_key = YOUR_KEY
conf_file.read_encrypted(file_path)
# 获取配置下中section为config的option,并获取对应的值,存入字典
for key in conf_file.options('config'):
    value = conf_file.get('config', key)
    config[key] = json.loads(value)
    
# 最后返回配置项字典config就可以使用了
  • 后续更新无需手动输入数据,可直接读取配置文件
import configparser
import json

from configparser_crypt import ConfigParserCrypt


def encrypt_config(config_path: str, encrypted_file_path: str, key_path: str, key_name: str) -> bytes:
    """
    读取ini格式配置文件并加密,密钥会自动保存或更新到对应文件
    :param config_path: ini格式配置文件路径,文件中section需为config,如有变化需修改代码 例:r'D:\projects\config_dev.ini'
    :param encrypted_file_path:加密后的文件路径及名称 例:r'D:\projects\temp\tests\encrypt_test.encrypted'
    :param key_path:生成的密钥保存文件路径,文件需存在,也可以是txt格式 例:r'D:\projects\temp\tests\login_key.py'
    :param key_name:密钥名称 例:'CONFIG_KEY'
    :return: bytes  返回密钥(方便测试)
    """
    # 创建字典保存读取到的配置信息
    config = dict()
    config_parser = configparser.ConfigParser()
    config_parser.read(config_path)
    for key in config_parser.options('config'):
        value = config_parser.get('config', key)
        config[key] = json.loads(value)

    # 创建加密类,开始加密
    conf_file = ConfigParserCrypt()
    # 生成密钥
    conf_file.generate_key()
    # 取得密钥
    aes_key = conf_file.aes_key
    # 将密钥存入对应文件,若不存在则添加在最后一行,如想手动更新密钥请注释下面10行
    with open(key_path, 'r') as fr:
        datas = fr.readlines()
        for i in range(len(datas)):
            if datas[i].strip()[:len(key_name)] == key_name:
                datas[i] = '{} = {}\n'.format(key_name,aes_key)
                break
        else:
            datas.append('{} = {}\n'.format(key_name,aes_key))
    with open(key_path, 'w') as fw:
        fw.writelines(datas)
    # 添加配置信息
    conf_file.add_section("config")
    temp = dict()
    for key, value in config.items():
        temp[key] = json.dumps(value)
    conf_file['config'] = temp
    # 保存加密文件
    with open(encrypted_file_path, 'wb') as file_handle:
        conf_file.write_encrypted(file_handle)
    return aes_key


def decrypt_config(file_path: str, key_path: str, key_name: str) -> dict:
    """
    将加密的配置文件解密,测试用
    :param file_path: 加密文件路径
    :param key_path: 密钥文件路径
    :param key_name: 密钥名称
    :return: dict 配置文件字典
    """
    # 创建字典用来保存配置信息
    config = dict()
    conf_file = ConfigParserCrypt()
    # 读取密钥
    with open(key_path, 'r') as fr:
        datas = fr.readlines()
        for line in datas:
            if line.strip()[:len(key_name)] == key_name:
                key = eval(line.strip().split('=',1)[-1].strip())
    # 设置密钥
    conf_file.aes_key = key
    # 解密
    conf_file.read_encrypted(file_path)
    # 保存至config
    for key in conf_file.options('config'):
        value = conf_file.get('config', key)
        config[key] = json.loads(value)
    return config


if __name__ == '__main__':
    # 测试
    config_path = r'D:\projects\config_dev.ini'
    encrypted_file_path = r'D:\projects\temp\tests\encrypt_test.encrypted'
    key_path = r'D:\projects\temp\tests\login_key.py'
    key_name = 'CONFIG_READ_KEY'
    key = encrypt_config(config_path, encrypted_file_path, key_path, key_name)
    config = decrypt_config(encrypted_file_path, key_path, key_name)
    print(config)