数据加密-用python实现对服务器脚本敏感信息的加密解密
off999 2024-09-23 11:33 34 浏览 0 评论
背景
在实际项目实施中,会编写很多在服务器执行的作业脚本。程序中凡是涉及到数据库链接、操作系统用户链接、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调用方法:
https://www.dlitz.net/software/pycrypto/api/current/)
服务器文件加密实现
现在假定要对一个存储各类ip、账户、密码的global.properties文件进行加密,同时,支持在读取时进行解密。
global.properties的内容假定如下图所示:
bgp.inceptor.in1.ip=192.168.1.1
bgp.inceptor.in1.default=cmr
bgp.inceptor.in2.ip=192.168.1.2
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
附程序代码地址:
https://github.com/jykggtkk/review/tree/master/review/1.basic/encrypt)
附加密算法介绍:
https://wenku.baidu.com/view/4fb8e0791711cc7931b716aa.html
相关推荐
- apisix动态修改路由的原理_动态路由协议rip的配置
-
ApacheAPISIX能够实现动态修改路由(DynamicRouting)的核心原理,是它将传统的静态Nginx配置彻底解耦,通过中心化配置存储(如etcd)+OpenRest...
- 使用 Docker 部署 OpenResty Manager 搭建可视化反向代理系统
-
在之前的文章中,xiaoz推荐过可视化Nginx反向代理工具NginxProxyManager,最近xiaoz还发现一款功能更加强大,界面更加漂亮的OpenRestyManager,完全可以替代...
- OpenResty 入门指南:从基础到动态路由实战
-
一、引言1.1OpenResty简介OpenResty是一款基于Nginx的高性能Web平台,通过集成Lua脚本和丰富的模块,将Nginx从静态反向代理转变为可动态编程的应用平台...
- OpenResty 的 Lua 动态能力_openresty 动态upstream
-
OpenResty的Lua动态能力是其最核心的优势,它将LuaJIT嵌入到Nginx的每一个请求处理阶段,使得开发者可以用Lua脚本动态控制请求的生命周期,而无需重新编译或rel...
- LVS和Nginx_lvs和nginx的区别
-
LVS(LinuxVirtualServer)和Nginx都是常用的负载均衡解决方案,广泛应用于大型网站和分布式系统中,以提高系统的性能、可用性和可扩展性。一、基本概念1.LVS(Linux...
- 外网连接到内网服务器需要端口映射吗,如何操作?
-
外网访问内网服务器通常需要端口映射(或内网穿透),这是跨越公网与私网边界的关键技术。操作方式取决于网络环境,以下分场景详解。一、端口映射的核心原理内网服务器位于私有IP地址段(如192.168.x.x...
- Nginx如何解决C10K问题(1万个并发连接)?
-
关注△mikechen△,十余年BAT架构经验倾囊相授!大家好,我是mikechen。Nginx是大型架构的必备中间件,下面我就全面来详解NginxC10k问题@mikechen文章来源:mikec...
- 炸场!Spring Boot 9 大内置过滤器实战手册:从坑到神
-
炸场!SpringBoot9大内置过滤器实战手册:从坑到神在Java开发圈摸爬滚打十年,见过太多团队重复造轮子——明明SpringBoot自带的过滤器就能解决的问题,偏偏要手写几十...
- WordPress和Typecho xmlrpc漏洞_wordpress主题漏洞
-
一般大家都关注WordPress,毕竟用户量巨大,而国内的Typecho作为轻量级的博客系统就关注的人并不多。Typecho有很多借鉴WordPress的,包括兼容的xmlrpc接口,而WordPre...
- Linux Shell 入门教程(六):重定向、管道与命令替换
-
在前几篇中,我们学习了函数、流程控制等Shell编程的基础内容。现在我们来探索更高级的功能:如何控制数据流向、将命令链接在一起、让命令间通信变得可能。一、输入输出重定向(>、>>...
- Nginx的location匹配规则,90%的人都没完全搞懂,一张图让你秒懂
-
刚配完nginx网站就崩了?运维和开发都头疼的location匹配规则优先级,弄错顺序直接导致500错误。核心在于nginx处理location时顺序严格:先精确匹配=,然后前缀匹配^~,接着按顺序正...
- liunx服务器查看故障命令有那些?_linux查看服务器性能命令
-
在Linux服务器上排查故障时,需要使用一系列命令来检查系统状态、日志文件、资源利用情况以及网络状况。以下是常用的故障排查命令,按照不同场景分类说明。1.系统资源相关命令1.1查看CPU使...
- 服务器被入侵的常见迹象有哪些?_服务器入侵可以被完全操纵吗
-
服务器被入侵可能会导致数据泄露、服务异常或完全失控。及时发现入侵迹象能够帮助你尽早采取措施,减少损失。以下是服务器被入侵的常见迹象以及相关的分析与处理建议。1.服务器被入侵的常见迹象1.1系统性能...
- 前端错误可观测最佳实践_前端错误提示
-
场景解析对于前端项目,生产环境的代码通常经过压缩、混淆和打包处理,当代码在运行过程中产生错误时,通常难以还原原始代码从而定位问题,对于深度混淆尤其如此,因此Mozilla自2011年开始发起并...
- 8个能让你的Kubernetes集群“瞬间崩溃”的配置错误
-
错误一:livenessProbe探针“自杀式”配置——30秒内让Pod重启20次现象:Pod状态在Running→Terminating→CrashLoopBackOff之间循环,重启间隔仅...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- apisix动态修改路由的原理_动态路由协议rip的配置
- 使用 Docker 部署 OpenResty Manager 搭建可视化反向代理系统
- OpenResty 入门指南:从基础到动态路由实战
- OpenResty 的 Lua 动态能力_openresty 动态upstream
- LVS和Nginx_lvs和nginx的区别
- 外网连接到内网服务器需要端口映射吗,如何操作?
- Nginx如何解决C10K问题(1万个并发连接)?
- 炸场!Spring Boot 9 大内置过滤器实战手册:从坑到神
- WordPress和Typecho xmlrpc漏洞_wordpress主题漏洞
- Linux Shell 入门教程(六):重定向、管道与命令替换
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)