python+flask实现个人密码管理
python+flask实现个人密码管理
我是个重度互联网用户,手里头的各种账号简直数不胜数,各种不同的密码管理起来更是十分麻烦,若是每个网站用同一个密码,风险性极大,为了解决这个问题,自己参考网上生成密码的方式写了这个密码管理的flask程序。用这个程序,我可以只记住一个复杂的密码,就可以得到其他账号的密码,且过程不可逆。
也即,只要你的主密码没有泄露,任何一个其他密码被破解,也无法得到你的主密码,这样就保证了其他账号密码的安全。
程序实现的功能
网站界面:
此程序是的目的是利用一个密钥管理其他所有的密码,再配合自己的记忆,或者记事本之类的,记住密码的简记名字。这样自己就只需要记住一个复杂的密钥,就可得到其他所有账号的密码。比如:我有一个test网站的账户,简记为test,密码位数是16位,自己再设置一个复杂的主密码,为了方便,这里设置为asdf。
只要输入的三个参数相同,最后得到的密码一定相同,且生成的密码较为复杂,无试探破解的可能。
从上面的例子,我可以只用记住asdf这个密钥,还有每个密码对应的简记名字和密码位数。这个密钥,就可以设置成一个只可能自己知道,别人无破解的可能(量子计算除外)的密钥。
点击生成后,就会得到由该程序生成的密码。
结果界面如下:
点击按钮可以将生成的密码复制到系统剪切板,支持手机端和电脑端的复制(都用的chrome,其他浏览器没试过,应该都支持)
下面简单介绍下这个程序设计的思路
Python核心代码
对输入的三个参数进行处理,生成最终密码的程序在generate.py文件中,其实代码也非常简单,就是用到了Python的伪随机和md5加密。
程序初始化参数
由上面截图可以看出,在该程序中用到了三个参数,分别为简记名(rem_name), 密码长度(length), 密钥(key)。初始化部分代码如下:
def __init__(self, rem_name, length, key):
self.rem_name = rem_name
self.length = int(length)
self.key = key
除了上面三个需要自己输入的参数之外,在编写程序时,需要预先写好最终生成密码的范围,比如我设置的数组为:
base_str = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ',', '.', '~',
'!', '@', '#', '$', '%', '^', '&', '*', ';', ':', '?']
这个数组的用途就是,在最后生成密码的时候,会从上面这个数组中伪随机的选择指定个数的字符组合成最终密码。
md5加密
关于md5加密的原理简单说一下就是,对任意的输入文本,经过md5加密之后,生成一定长度(本程序中为32位)的“随机”字符,且该过程不可逆。这个随机并不是真正的随机,因为,如果输入的文本完全相同,生成的md5字符串是相同的。之所以说它随机,是因为它可以说毫无规律,无法通过简单的暴力破解获取原输入文本,一般用于数字签名等。
这部分的代码如下:
def genhash(self):
string = self.rem_name.join(self.key)
hash_md5 = md5() # MD5 hash object
# MD5 encode
h_md5 = hash_md5.copy()
h_md5.update(string.encode('utf-8')) # encode to utf8
self.md5_str = h_md5.hexdigest() # get the md5 string
利用伪随机生成最终密码
最后一个函数便是用上面生成的一串md5字符,用伪随机的方式选择base_str中的字符,最后将结果返回。代码很简单。
上面md5加密生成了32位的字符串,在本算法中,并不需要用到所有的32位字符,因为一般都不会设置这么长的密码。
算法的思路是,设定一个循环,记循环变量为i,每次循环,都选取md5字符串的前i个,作为random函数的随机数种子,再使用random.randint()函数生成一个整数,这个整数限定在(0, p-1)之间(其中p为base_str数组的长度),将所得到的这个整数作为数组索引,从base_str中选取对应索引的字符,得到最终密码的一个字符,循环相应的次数,便得到了最终密码。代码如下:
def random_choose(self):
print(self.md5_str)
result = []
for i in range(self.length):
random.seed(self.md5_str[:i])
index = random.randint(0, len(base_str)-1)
result.append(base_str[index])
return result
下面是generate.py的完整代码:
#!/usr/bin/python
from hashlib import md5
import random
base_str = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ',', '.', '~',
'!', '@', '#', '$', '%', '^', '&', '*', ';', ':', '?']
class passwd():
def __init__(self, rem_name, length, key):
self.rem_name = rem_name
self.length = int(length)
self.key = key
def genhash(self):
string = self.rem_name.join(self.key)
hash_md5 = md5() # MD5 hash object
# MD5 encode
h_md5 = hash_md5.copy()
h_md5.update(string.encode('utf-8')) # encode to utf8
self.md5_str = h_md5.hexdigest() # get the md5 string
# print(md5_str)
def random_choose(self):
print(self.md5_str)
result = []
for i in range(self.length):
random.seed(self.md5_str[:i])
index = random.randint(0, len(base_str)-1)
result.append(base_str[index])
return result
if __name__ == "__main__":
# change the keys to your own keys
keys = 'customized keys'
password = passwd('qq', 16, keys)
password.genhash()
result = password.random_choose()
print(result)
由于是密码管理程序,如果只使用python,想在手机端查看自己密码的时候,就会很不妨方便,为此,创建一个flask应用,部署到自己的服务器,这样用手机打开自己的域名就可以访问,再配合bootstrap的响应式设计,手机端也有较好的使用体验。
下面是将该程序放进flask,并最终部署到服务器的过程。
flask创建
参考flask教程,创建好flask应用,这里不详细说明,python虚拟环境中需要安装的模块只有Flask。
创建完成后,将bootstrap和上面的generate.py放到flask目录中,代码结构如下:
.
├── app
│ ├── app.py
│ ├── generate.py
│ ├── static
│ └── templates
├── passwd.service
└── venv
├── bin
├── include
├── lib
├── lib64 -> lib
└── pyvenv.cfg
其中passwd.service是后面会用到的,将flask设置开机启动的服务文件。
venv为Python虚拟环境的目录。app中存放flask的主要文件。
app.py内容如下:
from flask import Flask, jsonify, render_template, request, session, redirect, url_for
import random
import string
import math
import os
import generate
from flask import jsonify
app = Flask(__name__,static_url_path='')
app.config['SECRET_KEY']=os.urandom(24)
@app.route('/', methods=['GET', 'POST'])
def index():
return render_template('index.html')
@app.route('/show_passwd/', methods=['GET', 'POST'])
def show_passwd():
rem_name = request.form.get('rem_name')
length = request.form.get('length')
key = request.form.get('key')
password = generate.passwd(rem_name, length, key)
password.genhash()
result = password.random_choose()
result = ''.join(result)
return render_template('result.html', result=result)
# return ''.join(result)
# return 'hello'
@app.route("/get_my_ip", methods=["GET"])
def get_my_ip():
return jsonify({'ip': request.remote_addr}), 200
if __name__ == '__main__':
app.run()
其他的文件就都是bootstrap的css和js,所有的文件都在我的github。
uwsgi运行flask
在服务器端,为了稳定性和安全性,需要用uwsgi等程序运行flask.
passwd.service内容如下:
[Unit]
Description=flask for passwd
After=network.target
[Service]
User=git
Group=git
WorkingDirectory=/home/git/passwd/app
Environment="PATH=/home/git/passwd/venv/bin"
ExecStart=/home/git/passwd/venv/bin/uwsgi --socket 0.0.0.0:8000 -p 3 -w app:app
PrivateTmp=true
[Install]
WantedBy=multi-user.target
User设置使用哪一个用户运行,group为用户所在的组,/home/git/passwd为该项目在linux服务器中存放的路径,将app这一级的所有文件和目录放置/home/git/passwd中即可,如果自己放在其他目录,对应修改即可。
将passwd.service放到/etc/systemd/system/, 再启动passwd.service并设置开机启动即可:
systemctl enable passwd.service
systemctl start passwd.service
nginx配置
添加nginx配置文件:
/etc/nginx/conf.d/flask.conf
添加以下内容:
server {
listen 80;
server_name www.yourdomain.com;
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:8000;
}
}
其中,端口8000,与上述uwsgi设置成一样即可。可以自己修改。替换自己的域名。
最后重启nginx服务
systemctl restart nginx
配置ssl证书(可选)
使用Let‘s encript为网站配置ssl证书
Finally
最后,终于完成了整个过程,不出意外,在浏览器中输入自己设置的域名即可使用该程序了,手机端也可以。