关于本站
1、基于Django+Bootstrap开发
2、主要发表本人的技术原创博客
3、本站于 2015-12-01 开始建站
一直以来在我的网站中,对于登录和注册提交的数据都是明文提交。也就是说,如果随便监听网络,可以直接看到密码的明文。这样是很不安全。最好对密码这些敏感信息加密再提交。以登录为例,前端代码(简化)如下:
<form id="user_form" class="main_form" method='post'>
{%csrf_token%}
<div id="user_control">
<div class="control-group">
<label for="user_name">邮箱:</label>
<input type="text" id="user_name" name="user_name"/>
</div>
<div class="control-group">
<label for="user_pwd">密码:</label>
<input type="password" id="user_pwd" name="user_pwd"/>
</div>
</div>
<p id="tip_text" style="color:red;"></p>
<div class="form_buttons">
<input type="submit" value="登录"/>
</div>
</form>提交表单代码如下,我写成ajax异步提交的方式:
<script type="text/javascript">
$(function(){
//登录
$('#user_form').submit(function(){
//验证
var tip=$('#tip_text');
tip.text('');
if($('#user_name').val()==''){
tip.text('请输入邮箱');
return false;
};
if($('#user_pwd').val()==''){
tip.text('请输入密码');
return false;
};
//登录
$.ajax({
type: "POST",
data: $('#user_form').serialize(),
url: "{% url 'user_login' %}",
cache: false,
dataType: "json",
success: function(json, textStatus){
var is_success = json['success'];
if(is_success){
tip.text('登录成功,页面处理中...');
window.location.href = "/";
}else{
tip.text('邮箱或者密码错误,请重试');
};
},
error: function (XMLHttpRequest, textStatus, errorThrown){
tip.text("登录出错,请重试 "+errorThrown);
}
});
return false;
});
});
</script>其中,{% url 'user_login' %}设置url对应的响应方法如下:
#coding:utf-8
from django.http import HttpResponse
from django.contrib.auth import authenticate, login
import json
def user_login(request):
"""login"""
response_data = {}
try:
login_name = request.POST.get('user_name')
login_pwd = request.POST.get('user_pwd')
if len(login_name)*len(login_pwd)==0:
raise Exception(u"邮箱或密码为空")
user = authenticate(username=login_name, password=login_pwd)
if user is not None:
login(request, user)
else:
raise Exception(u"邮箱或密码不正确")
response_data['success'] = True
response_data['message'] = 'ok'
except e:
response_data['success'] = False
response_data['message'] = e.message
finally:
return HttpResponse(json.dumps(response_data),
content_type="application/json")加密方法有很多中,比较安全的加密方法是非对称加密RSA算法。也就是常见的公钥和私钥,公钥加密、私钥解密。公钥公开无所谓,如果没有对应的私钥是很难解密得到正确的内容。
那么,我们可以生成一对公钥和私钥。公钥给前端页面,私钥保存到settings中。前端再将用户名和密码组合之后加密,提交给服务器。服务器得到密文再根据私钥解密得到用户名和密码。再进一步验证、登录等操作。
思路理顺之后,开始安装相关的库。rsa算法有个rsa库,但这个得到的公钥和私钥有问题。自己可以使用,但给其他语言写的rsa算法却无法使用。建议安装pycrypto库,而且要安装最新版(我使用的是2.6.1版)。pycrypto的旧版没有rsa算法。执行如下命令安装:
pip install pycrypto
若安装出错,检查是否有权限以及是否有python-dev开发包。若没有,执行yum或apt-get安装python-dev。
安装完成之后,先生成一对密钥。进入Python命令行模式,执行如下代码:
#coding:utf-8 from Crypto import Random from Crypto.Hash import SHA from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5 from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5 from Crypto.PublicKey import RSA # 伪随机数生成器 random_generator = Random.new().read # rsa算法生成实例 rsa = RSA.generate(1024, random_generator) # master的秘钥对的生成 private_pem = rsa.exportKey() public_pem = rsa.publickey().exportKey() pub = public_pem.decode() pri = private_pem.decode()
再分别print输出pub和pri:
print(pub) print(pri)
分别可以得到公钥和私钥,复制并粘贴保存到settings.py文件中。例如(这个当然不是我使用的公钥和私钥,私钥一定要保护好):
PUBLIC_KEY = '''-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD3CKmYdAJXXdg18UdkndZNppW8 hhtJCbLy/sLMLGnUFdPg8hxIBHGigWqca+4R8DEUHizvM8LAuR4fCjHVodYEZyeb cpGeyXp06Cnrp5zEeRlbRJd2iUiBzTMNgTUCgPSkisiI6QTVKF1C6kafr5NAhYQg 4wKLCBiCmL58S9N+FwIDAQAB -----END PUBLIC KEY----- ''' PRIVATE_KEY = '''-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQD3CKmYdAJXXdg18UdkndZNppW8hhtJCbLy/sLMLGnUFdPg8hxI BHGigWqca+4R8DEUHizvM8LAuR4fCjHVodYEZyebcpGeyXp06Cnrp5zEeRlbRJd2 iUiBzTMNgTUCgPSkisiI6QTVKF1C6kafr5NAhYQg4wKLCBiCmL58S9N+FwIDAQAB AoGBAJa0HSqZUzhTUuyNll1GgQ98GgsZ0Rl8pkPhsZr3WVR+QHURnrk8pMpbo1tr 6J/e5UH9qrH+5MfH5x1OjdpjUXjJVAoQgvWgxGPN5MwMli9/tEooFIM/m3SNaHpt 1ivCPDCnu1oi7ptB0pSyaeLevK35x6BpQRwlfF+Qfz8PSjExAkEA+uG9dpYPegDs BqDMm6OFcn5TCUsIUcWItlnRWg1TJgOY6KGp2Omn9Jx8vah0KrUSdQIEFi9xBC1G /QYqb9x8iQJBAPwS03KhgAjXueafSFZoUBPrOyv/Vfe+4PuQpQ1NVmOHRJUiaMV0 ah/VjhizXl/XjFipB2opyI7zgVg6DFgpvZ8CQESF26XEHr4H+m9lA/2OkChRcISd Rcxv04NazN93vDopyV3gqe9hAkrBYyC6HeB8TGpA/rTAiHHHnBgH0xdydWECQGnK uOWGNEcByuqodOKW2uzRL79SZVEZ0jCiTzMa/yO8VKNGkrQ0HIoJxZ5GQVh2DVf0 cME0khC0z9coXZ/uvL8CQC+AtWk2QnxoSaV5v06kxH9WzOtQtoPQEVV4qvP4ftpR MJp7cjM4R1jrpfhoCk5rokizESoxavjxa4qZOMad07Y= -----END RSA PRIVATE KEY----- '''
这样,我们就可以通过from django.conf import settings读取这对密钥。
公钥可以在渲染登录页面,作为变量给前端。这个很简单,不用我多说吧?好吧,我还是简单写一下吧:
from django.conf import settings
from django.shortcuts import render
def login_page(request):
data = {}
data['public_key'] = settins.PUBLIC_KEY
return render(request, 'login.html', data)接下来,需要修改登录页面模板(login.html)。不过在这之前,先找个rsa算法的javascript库:jsencrypt。
从github下载下来,找到bin/jsencrypt.min.js并放到你的django项目中。
我们利用该库实现前端的rsa加密。修改前端页面如下:
<!--引入jsencrypt,具体路径和位置自行修改-->
<script src="/static/js/jsencrypt.min.js"></script>
<form id="user_form" class="main_form" method='post'>
{%csrf_token%}
<!--公钥-->
<input id="public_key" type="hidden" value="{{public_key}}" name="public_key">
<div id="user_control">
<div class="control-group">
<label for="user_name">邮箱:</label>
<input type="text" id="user_name" name="user_name"/>
</div>
<div class="control-group">
<label for="user_pwd">密码:</label>
<input type="password" id="user_pwd" name="user_pwd"/>
</div>
</div>
<p id="tip_text" style="color:red;"></p>
<div class="form_buttons">
<input type="submit" value="登录"/>
</div>
</form>之前的登录代码也要修改,对用户名和密码加密:
<script type="text/javascript">
$(function(){
//登录
$('#user_form').submit(function(){
//验证
var tip=$('#tip_text');
tip.text('');
if($('#user_name').val()==''){
tip.text('请输入邮箱');
return false;
};
if($('#user_pwd').val()==''){
tip.text('请输入密码');
return false;
};
//对用户名和密码合并,再rsa加密
var content = $("#user_name").val() + '|' + $("#user_pwd").val();
var encrypt = new JSEncrypt();
encrypt.setPublicKey($('#public_key').val());
var encrypted = encrypt.encrypt(content);
//组合POST的数据
var data = {};
data["csrfmiddlewaretoken"] = $("input[name=csrfmiddlewaretoken]").val();
data["encrypt_text"] = encrypted;
//登录
$.ajax({
type: "POST",
data: $.param(data),
url: "{% url 'user_login' %}",
cache: false,
dataType: "json",
success: function(json, textStatus){
var is_success = json['success'];
if(is_success){
tip.text('登录成功,页面处理中...');
window.location.href = "/";
}else{
tip.text('邮箱或者密码错误,请重试');
};
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
tip.text("登录出错,请重试 "+errorThrown);
}
});
return false;
});
});
</script>由于,无需也不能包含用户名和密码信息到POST的数据。所以重新组合新数据并POST提交。
这时,再修改后端代码,对密文解密并处理。如下修改的后端登录代码:
#coding:utf-8
from Crypto import Random
from Crypto.Hash import SHA
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5
from Crypto.PublicKey import RSA
import base64
from django.http import HttpResponse
from django.contrib.auth import authenticate, login
from django.conf import settings
import json
def user_login(request):
"""login"""
response_data = {}
try:
encrypt_text = request.POST.get('encrypt_text')
# 伪随机数生成器
random_generator = Random.new().read
# rsa算法生成实例
rsa = RSA.generate(1024, random_generator)
rsakey = RSA.importKey(settings.PRIVATE_KEY)
cipher = Cipher_pkcs1_v1_5.new(rsakey)
# 解密
text = cipher.decrypt(base64.b64decode(encrypt_text), random_generator)
# 根据竖线拆分得到用户名和密码
login_name, login_pwd = text.split('|')
if len(login_name)*len(login_pwd)==0:
raise Exception(u"邮箱或密码为空")
user = authenticate(username=login_name, password=login_pwd)
if user is not None:
login(request, user)
else:
raise Exception(u"邮箱或密码不正确")
response_data['success'] = True
response_data['message'] = 'ok'
except e:
response_data['success'] = False
response_data['message'] = e.message
finally:
return HttpResponse(json.dumps(response_data), content_type="application/json")到这里,就完成rsa前端对用户名和密码加密提到到后端。后端再加密,得到原文。再继续执行之前的操作。
同样,注册和修改密码等页面处理方式一样。我就不再赘述。
jiawei6636
棒
2020-07-21 18:52 回复