python实现对服务器脚本敏感信息的加密解密功能


Posted in Python onAugust 13, 2019

背景

在实际项目实施中,会编写很多在服务器执行的作业脚本。程序中凡是涉及到数据库链接、操作系统用户链接、IP地址、主机名称的内容都是敏感信息。在纯内网系统中往因为开发时间紧迫,往往都直接将这些敏感信息明文方式写在脚本中了。

稍微规范一点的,创建一个通用的config文件,将所有这类敏感信息记录在这个文件中,脚本以读取文件方式获取这些信息。这种方式的好处是脚本不用在应用迁移、灾备部署的时候再起不同的版本,尤其是大数据平台作业运行的脚本,如果是需要做灾备集群,这种方式可以减少生产变更时的人工干预操作。但是这种方式仍不能解决安全性的问题,只要config文件泄露,那么平台会非常危险。

因此在这个config文件的基础上,对其进行改造,实现对内容的加密,而脚本使用时再对其进行解密。因此要求有一个程序能对文本内容进行加密,也能进行反向解密。

不可逆的加密方法使用最多的就是md5加密算法,我们一般用来检验文件的完整和安全性,不适用这个场景。

使用python语言对文本内容进行加解密有多种方式,从网上搜索结果看主要有以下几种:

1.方法一 使用base64转编码

Base64是一种用64个字符来表示任意二进制数据的方法。

用记事本打开exe、jpg、pdf这些文件时,我们都会看到一大堆乱码,因为二进制文件包含很多无法显示和打印的字符,所以,如果要让记事本这样的文本处理软件能处理二进制数据,就需要一个二进制到字符串的转换方法。Base64是一种最常见的二进制编码方法。

Base64的原理很简单,首先,准备一个包含64个字符的数组:

['A', 'B', 'C', ... 'a', 'b', 'c', ... '0', '1', ... '+', '/']

然后,对二进制数据进行处理,每3个字节一组,一共是3x8=24bit,划为4组,每组正好6个bit,得到4个数字作为索引,然后查表,获得相应的4个字符,就是编码后的字符串。

所以,Base64编码会把3字节的二进制数据编码为4字节的文本数据,长度增加33%,好处是编码后的文本数据可以在邮件正文、网页等直接显示。

如果要编码的二进制数据不是3的倍数,最后会剩下1个或2个字节怎么办?

Base64用\x00字节在末尾补足后,再在编码的末尾加上1个或2个=号,表示补了多少字节,解码的时候,会自动去掉。

Python内置的base64可以直接进行base64的编解码:

import base64
userPassword="sunlinemdp201810"
unkownPassword=base64.b64encode(bytes(userPassword,'utf-8'))
print("加密后:"+str(unkownPassword,'utf-8'))
kownPassword=str(base64.b64decode(unkownPassword),'utf-8')
print('解密后:'+kownPassword)

补充说明:python3中对字符串加解密的方法 base64.encodestring('test') 不能用 因此只能采用bytes方法然后中间进行格式转换

由于标准的Base64编码后可能出现字符+和/,在URL中就不能直接作为参数,所以又有一种"url urlsafe_b64encode"的base64编码方法,实现对+和/的转码,在现在使用的版本中这个功能已经整合在b64encode方法中了

userPassword="sunlinemdp201810"
unkownPassword=base64.b64encode(bytes(userPassword,'utf-8'))
print("加密后:"+str(unkownPassword,'utf-8'))
unkownPassword=base64.urlsafe_b64encode(bytes(userPassword,'utf-8'))
print("解密后:"+str(unkownPassword,'utf-8'))
base64.urlsafe_b64decode(unkownPassword)

2.方法二 win32com.client

样例代码如下:

import win32com.client
def encrypt(key,content): # key:密钥,content:明文
 EncryptedData = win32com.client.Dispatch('CAPICOM.EncryptedData')
 EncryptedData.Algorithm.KeyLength = 5
 EncryptedData.Algorithm.Name = 2
 EncryptedData.SetSecret(key)
 EncryptedData.Content = content
 return EncryptedData.Encrypt()
def decrypt(key,content): # key:密钥,content:密文
 EncryptedData = win32com.client.Dispatch('CAPICOM.EncryptedData')
 EncryptedData.Algorithm.KeyLength = 5
 EncryptedData.Algorithm.Name = 2
 EncryptedData.SetSecret(key)
 EncryptedData.Decrypt(content)
 str = EncryptedData.Content
 return str

s1 = encrypt('sunline', 'hello world')
s2 = decrypt('sunline', s1)
print s1,s2

win32com是python操作windows程序的第三方包,放在服务器上使用不太合适。

3.方法三 PyCrypto

一个极好的用于信息安全的python库,包括所有主流算法。

具体可以参考:

附pycrypto调用方法

服务器文件加密实现

现在假定要对一个存储各类ip、账户、密码的global.properties文件进行加密,同时,支持在读取时进行解密。

global.properties的内容假定如下图所示:

bgp.inceptor.in1.ip=10.22.179.13
bgp.inceptor.in1.default=cmr
bgp.inceptor.in2.ip=10.22.179.14
bgp.inceptor.in2.default=default
bdp.ldap.mdp.username=mdp
bdp.ldap.mdp.password=mdp

每一行使用等号将信息分为两段,等号左边是信息项名称,等号右边是信息项具体的内容,我们要对信息项的具体的内容进行加密。

首先做需求分析,我们的需求可以拆分为以下几个:

  1. 实现对指定字符串内容基于某个密钥的加解密内容输出
  2. 读取指定加密配置文件,根据信息项名称读取指定内容后加解密输出
  3. 读取指定配置文件,对文件内每一行信息项的具体内容进行加解密后生成新的加解密后的配置文件

第二步做程序设计,我是从功能上进行拆分设计:

基本功能包括:

  1. 加密解密
  2. 获取文件
  3. 文件指定内容读取

交互操作包括:

  1. 参数读取解析
  2. 具体功能实现,输出结果或生成文件

输入输出设计:

  1. 输入:  功能类型 -d  对应 四种功能需求
  2. 输入:  密钥 -k    密钥内容
  3. 输入:  加密内容或解密内容 -c 对应功能2
  4. 输入:  配置文件路径名称  -f 对应功能 234
  5. 输入:  信息项内容  -i    对应功能4
  6. 输出:  加解密文   对应功能 1 4
  7. 输出:  文件路径及名称  对应功能 2 3

第三步,首先根据他人提供的方法做了一个对具体字符串进行加解密的类,唯一多做的处理就是对加密使用的密钥多了一个base64编码的过程,文件保存为optcrypt.py:

#coding: utf8
'''

实现对指定字符串内容基于某个密钥的加解密内容输出

密钥使用base64多加一层处理

version: v0.0.1
author: Duwj
date: 2018-10-24
'''
import sys
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
import base64
class optcrypt():
 def __init__(self, key):
  self.key = str(base64.b64decode(key))
  self.mode = AES.MODE_CBC
  #self.iv = Random.new().read(AES.block_size)
 #加密函数,如果text不是16的倍数【加密文本text必须为16的倍数!】,那就补足为16的倍数
 def aesencrypt(self, text):
  #密钥key 长度必须为16(AES-128)、24(AES-192)、或32(AES-256)Bytes 长度.目前AES-128足够用
  cipher = AES.new(self.key, self.mode, self.key)
  #cipher=AES.new(bytes(self.key), self.mode,Random.new().read(AES.block_size))
  #加密文本text必须为16的倍数
  add = 16 - (len(text) % 16)
  text = text + ('\0' * (16 - (len(text) % 16)))
  self.ciphertext = cipher.encrypt(text)
  #因为AES加密时候得到的字符串不一定是ascii字符集的,输出到终端或者保存时候可能存在问题
  #所以这里统一把加密后的字符串转化为16进制字符串
  return b2a_hex(self.ciphertext)
 #解密 
 def aesdecrypt(self, text):
  cryptor = AES.new(self.key, self.mode, self.key)
  #16进制转回后解密
  plain_text = cryptor.decrypt(a2b_hex(text))
  #rstrip()去掉补的空格
  return plain_text.rstrip('\0')
if __name__ == '__main__':
 #设置环境编码
 reload(sys)
 sys.setdefaultencoding('utf8')
 #测试
 pc = optcrypt('c3VubGluZW1kcDIwMTgxMQ==') 
 e = pc.aesencrypt("duwj") 
 d = pc.aesdecrypt("d518cdd30b854b84f5aa7c5511e03e38") 
 print "info:duwj,encrypt:"+e+",decrypt:"+d  

然后就是依托这个基础的字符串加解密类,实现对字符串、文件、信息项的加解密功能,在这个过程中没有对复杂的properties结构进行解析,单纯的使用=实现信息项和密文内容的分离,文件保存为server.py:

#!bin/python
#-*- coding: UTF-8 -*-

'''

脚本功能:

         1. 实现对指定字符串内容基于某个密钥的加解密内容输出
         2. 读取指定加密配置文件,根据信息项名称读取指定内容后加解密输出
         3. 读取指定配置文件,对文件内每一行信息项的具体内容进行加解密后生成新的加解密后的配置文件
使用说明:python server.py
         -d [选择方法[se 字符串加密 /sd 字符串解密/ie 信息项加密/id 信息项解密/fe 文件加密/fd 文件加密]] 
         -k [16位密钥]
         -c [加密内容]
         -f [文件名称]
         -i [信息项名称]
         字符串加解密必选项: -k -c
         信息项加解密必选项: -k -f -i
         文件加解密必选项:    -k -f

version: v0.0.1
author: Duwj
date: 2018-11-05
'''
import os
import sys
import getopt 
from optcrypt import optcrypt
#字符串加解密
def stringCrpyt(func_name,value):
 if func_name =="se":
  crpyt_value=pc.aesencrypt(value)
 else:
  crpyt_value=pc.aesdecrypt(value)
 return crpyt_value
#信息项加解密输出
def infoCrpyt(func_name,file_name,info_name):
 value=""
 try:
  pro_file = open(file_name, 'Ur')
  for line in pro_file.readlines():
   line = line.strip().replace('\n', '')
   if info_name == line.split('=')[0]:
    value = line.split('=')[1]
    #print value 
 except Exception, e:
   raise e
 finally:
  pro_file.close()
 if func_name == "ie":
  crpyt_value=pc.aesencrypt(value)
 elif func_name=="id":
  crpyt_value=pc.aesdecrypt(value)
 return crpyt_value 
#文件加解密
def fileCrpyt(func_name,file_name):
 try:
  read_file = open(file_name,'Ur')
  write_file = open(file_name+"."+func_name+"crypt",'w')
  if func_name == "fe":
   for line in read_file.readlines():
    line = line.strip().replace('\n', '')
    if line=="":
     pass
    elif line.find("#")!=-1:
     write_file.write(line+"\n")
    else:
     strs=line.split('=')[0]+"="+pc.aesencrypt(line.split('=')[1])
     write_file.write(strs+"\n")
  else:
   for line in read_file.readlines():
    line = line.strip().replace('\n', '')
    if line.find("#")!=-1:
     write_file.write(line+"\n")
    else:
     strs=line.split('=')[0]+"="+pc.aesdecrypt(line.split('=')[1])
     write_file.write(strs+"\n")
 except Exception, e:
   raise e
 finally:
  read_file.close()
  write_file.close()
 return file_name+"."+func_name+"crypt"
if __name__ == "__main__":
 #设置环境编码
 reload(sys)
 sys.setdefaultencoding('utf8')
 msg='''使用说明:python server.py 
   -d [选择方法[se 字符串加密 /sd 字符串解密/ie 信息项加密/id 信息项解密/fe 文件加密/fd 文件加密]] 
   -k [16位密钥]
   -c [加密内容]
   -f [文件名称]
   -i [信息项名称]
   字符串加解密必选项: -k -c 
   信息项加解密必选项: -k -f -i
   文件加解密必选项: -k -f 
   '''  
 #获取参数
 opts, args = getopt.getopt(sys.argv[1:], "d:k:c:f:i:")
 if len(opts)==0:
  print msg
  sys.exit(0)
 for op, value in opts:
  if op == "-d":
   func_name = value
  elif op == "-k":
   key_content = value
  elif op == "-c":
   txt_content = value
  elif op == "-f":
   file_name = value
  elif op == "-i":
   info_name = value
 #print(opts) 
 #初始化密钥
 pc = optcrypt(key_content)
 #根据功能类型执行
 if func_name in("se","sd"):
  print stringCrpyt(func_name,txt_content)
 elif func_name in ("ie","id"):
  print infoCrpyt(func_name,file_name,info_name) 
 elif func_name in ("fe","fd"):
  print fileCrpyt(func_name,file_name)
 else:
  print("there is no function named "+func_name)
 sys.exit(0)

注意在项目文件夹中增加一个init.py文件以便于脚本能识别optcrypt模块。

测试脚本test.sh:

#!/bin/bash
#依赖python pycrypt模块 安装这个模块的命令是 python setup.py install 
#系统必须现安装yum install python-devel
#测试加解密程序
#c3VubGluZW1kcDIwMTgxMQ== 是对 sunlinemdp201811 进行base64编码后的值 可以修改 方法为:
# 1.命令行执行 python 进入python编程环境
# 2.执行以下代码 
# import base64
# print s= base64.b64encode("sunlinemdp201811") # 引号内为想编码的密钥文本
#帮助
python server.py
#字符串加密
python server.py -d se -k c3VubGluZW1kcDIwMTgxMQ== -c sunline
#字符串解密
python server.py -d sd -k c3VubGluZW1kcDIwMTgxMQ== -c cd3f4a3b1c4a189d3fe985495f6f963b
#文件加密
python server.py -d fe -k c3VubGluZW1kcDIwMTgxMQ== -f global.properties
#文件解密
python server.py -d fd -k c3VubGluZW1kcDIwMTgxMQ== -f global.properties.fecrypt
#信息项加密输出
python server.py -d ie -k c3VubGluZW1kcDIwMTgxMQ== -f global.properties -i database.ora10g.username
#信息项解密输出
python server.py -d id -k c3VubGluZW1kcDIwMTgxMQ== -f global.properties.fecrypt -i database.ora10g.username
#shell中获取python输出值的方法:
outputString=`python server.py -d ie -k c3VubGluZW1kcDIwMTgxMQ== -f global.properties -i database.ora10g.username`
echo outputString:${outputString}
outputFile=`python server.py -d fe -k c3VubGluZW1kcDIwMTgxMQ== -f global.properties`
echo outputFile:${outputFile}

输出结果:

[root@localhost encrypt]# ./test.sh
使用说明:python server.py 
   -d [选择方法[se 字符串加密 /sd 字符串解密/ie 信息项加密/id 信息项解密/fe 文件加密/fd 文件加密]] 
   -k [16位密钥]
   -c [加密内容]
   -f [文件名称]
   -i [信息项名称]
   字符串加解密必选项: -k -c 
   信息项加解密必选项: -k -f -i
   文件加解密必选项: -k -f 
   
cd3f4a3b1c4a189d3fe985495f6f963b
sunline
global.properties.fecrypt
global.properties.fecrypt.fdcrypt
d518cdd30b854b84f5aa7c5511e03e38
dw
outputString:d518cdd30b854b84f5aa7c5511e03e38
outputFile:global.properties.fecrypt

续会对脚本进行内容补充,主要是增加一些之前为了功能实现而忽略的异常处理和日志登记的内容。

附程序代码地址

附加密算法介绍

总结

以上所述是小编给大家介绍的python实现对服务器脚本敏感信息的加密解密功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Python 相关文章推荐
python获取糗百图片代码实例
Dec 18 Python
用Python编程实现语音控制电脑
Apr 01 Python
python BeautifulSoup设置页面编码的方法
Apr 03 Python
Python 列表排序方法reverse、sort、sorted详解
Jan 22 Python
关于Django显示时间你应该知道的一些问题
Dec 25 Python
PyQt5每天必学之QSplitter实现窗口分隔
Apr 19 Python
pandas 条件搜索返回列表的方法
Oct 30 Python
python重要函数eval多种用法解析
Jan 14 Python
Python换行与不换行的输出实例
Feb 19 Python
python实现mask矩阵示例(根据列表所给元素)
Jul 30 Python
pymongo insert_many 批量插入的实例
Dec 05 Python
python 算法题——快乐数的多种解法
May 27 Python
python多线程+代理池爬取天天基金网、股票数据过程解析
Aug 13 #Python
Python字符串处理的8招秘籍(小结)
Aug 13 #Python
python实现批量修改服务器密码的方法
Aug 13 #Python
基于python分析你的上网行为 看看你平时上网都在干嘛
Aug 13 #Python
Python实现微信翻译机器人的方法
Aug 13 #Python
python读写csv文件的方法
Aug 13 #Python
python根据多个文件名批量查找文件
Aug 13 #Python
You might like
php简单静态页生成过程
2008/03/27 PHP
利用PHP脚本在Linux下用md5函数加密字符串的方法
2015/06/29 PHP
Nigma vs Liquid BO3 第一场2.14
2021/03/10 DOTA
一些易混淆且不常用的属性,希望有用
2007/01/29 Javascript
JavaScript内核之基本概念
2011/10/21 Javascript
基于jQuery实现交互体验社会化分享代码附源码下载
2016/01/04 Javascript
浅谈jquery之on()绑定事件和off()解除绑定事件
2016/10/26 Javascript
微信小程序进行微信支付的步骤昂述
2016/12/01 Javascript
Javascript 对cookie操作详解及实例
2016/12/29 Javascript
canvas绘制表盘时钟
2017/01/23 Javascript
vue-router跳转页面的方法
2017/02/09 Javascript
利用n 升级工具升级Node.js版本及在mac环境下的坑
2017/02/15 Javascript
详谈表单重复提交的三种情况及解决方法
2017/08/16 Javascript
webpack3+React 的配置全解
2017/08/21 Javascript
JS中Promise函数then的奥秘探究
2018/07/30 Javascript
[01:13]2014DOTA2西雅图邀请赛 舌尖上的TI4
2014/07/08 DOTA
Python实现查看系统启动项功能示例
2018/05/10 Python
python可视化实现代码
2019/01/15 Python
Python利用pandas处理Excel数据的应用详解
2019/06/18 Python
python跳出双层for循环的解决方法
2019/06/24 Python
python selenium爬取斗鱼所有直播房间信息过程详解
2019/08/09 Python
python 使用opencv 把视频分割成图片示例
2019/12/12 Python
jupyter修改文件名方式(TensorFlow)
2020/04/21 Python
python中使用input()函数获取用户输入值方式
2020/05/03 Python
关于h5中的fetch方法解读(小结)
2017/11/15 HTML / CSS
采用专利算法搜索最廉价的机票:CheapAir
2016/09/10 全球购物
拓展培训心得体会
2014/01/04 职场文书
竞职演讲稿范文
2014/01/11 职场文书
《称象》教学反思
2014/04/25 职场文书
市场营销工作计划书
2014/05/06 职场文书
春节慰问信范文
2015/02/15 职场文书
村官个人总结范文
2015/03/03 职场文书
人事行政助理岗位职责
2015/04/11 职场文书
文明礼貌主题班会
2015/08/14 职场文书
springboot+VUE实现登录注册
2021/05/27 Vue.js
漫画《尖帽子的魔法工坊》宣布动画化
2022/04/06 日漫