python django环境下使用RSA算法加密明文登录密码
登录时,明文密码传输到后台,可通过抓包获取到明文密码,造成安全隐患。可使用加密算法(如RSA)先加密密码,再传输到后台解密,保障数据传输安全。
js插件下载地址 http://travistidwell.com/jsencrypt/index.html
一、使用的包
后端:cryptodome,base64
前端:jsencrypto.min.js
二、思路及代码分析
(一)基本思路
View.py定义登录,GET方式打开登录页面时,动态生成RSA公私钥对,公钥以json数据的形式传到前端,保存在一个隐藏的或其他标签供jsencrypto加密使用,私钥存储在session里面或者静态文件里面。前端使用jsencrypto.min.js 调用公钥加密密码,以post方式传到后台。后台从session或者静态文件读取私钥进行解密。
后端代码 views.py
from django.shortcuts import render,HttpResponse,redirect from django.utils.decorators import method_decorator from utils import check_code from io import BytesIO from Crypto.PublicKey import RSA from Crypto import Random from Crypto.Cipher import PKCS1_v1_5 import base64 from django.views import View from django.contrib.auth import authenticate from django.contrib.auth import login from django.contrib.auth import logout from pository import models from kindadmin.discovery import autoDiscoveryAdmin autoDiscoveryAdmin() def rsa(func): def inner(request,*args,**kwargs): random_generator = Random.new().read rsa = RSA.generate(1024, random_generator) rsa_private_key = rsa.exportKey() rsa_public_key = rsa.publickey().exportKey() # 1. 以session的方式存储私钥,PKCS1格式 # request.session['privkey'] = rsa_private_key.decode() # 2. 存储到静态文件 # print(rsa_private_key) request.session['primary_key'] =rsa_private_key.decode() request.session['public_key'] = rsa_public_key.decode() return func(request,*args,**kwargs) return inner class Login(View): @method_decorator(rsa) def get(self,request,*args,**kwargs): return render(request, 'kindbackend/login.html') def post(self,request,*args,**kwargs): code = request.POST.get('code').lower() error = '' if code != request.session.get('check_code').lower(): error = '验证码不正确!' return render(request,'login.html',{'error':error}) passwd = request.POST.get('password') user = request.POST.get('username') privkeystr = request.session.get('primary_key').encode() # privkey 为私钥对象,由n,e等数字构成 privkey = RSA.importKey(privkeystr) cipher = PKCS1_v1_5.new(privkey) # 现将base64编码格式的password解码,然后解密,并用decode转成str password = cipher.decrypt(base64.b64decode(passwd.encode()), 'error').decode() user = authenticate(username=user,password=password) if user: login(request,user) return redirect(request.GET.get('next','/kindadmin/')) # return redirect(request.GET.get('next','/crm/')) error = '用户名或密码错误!' return render(request, '/kindadmin/login.html', {'error': error}) class Logout(View): def get(self,request): logout(request) return redirect('/kindadmin/login/') class CreateImgCode(View): def get(self,request): f = BytesIO() # 直接在内存开辟一点空间存放临时生成的图片 img, code = check_code.create_validate_code() # 调用check_code生成照片和验证码 request.session['check_code'] = code # 将验证码存在服务器的session中,用于校验 # img.save(f1, 'PNG') # 生成的图片放置于开辟的内存中 img.save(f, 'PNG') # 生成的图片放置于开辟的内存中 return HttpResponse(f.getvalue()) # 将内存的数据读取出来,并以HttpResponse返回f.getvalue()
前台 js.js代码
function LoginInit() { this.login = function () { $('#login_sub').on('click',function () { //公钥加密 var pwd =$('#id_passwd').val(); //明文密码 var pubkey = $('#pubkey').val(); //公钥,pkcs#1格式,字符串 var jsencrypt = new JSEncrypt(); //加密对象 jsencrypt.setPublicKey(pubkey); // 设置密钥 var en_pwd = jsencrypt.encrypt(pwd); //加密 $('#id_passwd').val(en_pwd); //返回给密码输入input console.log(en_pwd) $('#loginfrom').submit()//post提交 }); }; this.flushcode = function () { $('#code').on('click',function () { $(this).attr('src',$('#code').attr('src')+'?') }) } }
login.html
{% extends 'layout.html' %}
{% load staticfiles %}
{% block title %}登录{% endblock %}
{% block css %}
<style>
.login{
width: 40%;
margin-top: 30px;
margin-left: 300px;
}
</style>
{% endblock %}
{% block content %}
<div class="login">
<form action="/login.html" method="post" id="loginfrom" novalidate>
{% csrf_token %}
<div class="form-group">
<label for="{{ loginfrom.user.id_for_label }}">{{ loginfrom.user.label }}</label><br>
{{ loginfrom.user }}{{ loginfrom.user.errors.0 }}
</div>
<div class="form-group">
<label for="{{ loginfrom.passwd.id_for_label }}">{{ loginfrom.passwd.label }}</label><br>
{{ loginfrom.passwd }}{{ loginfrom.passwd.errors.0 }}
<input type="hidden" value="{{ pub_key }}" id="pubkey">
</div>
<div class="form-group">
<label for="{{ loginfrom.code.id_for_label }}">{{ loginfrom.code.label }}</label><br>
{{ loginfrom.code }}<img src="/create-img.html" alt="" id="code">{{ loginfrom.code.errors.0 }}
</div>
<button type="button" class="btn btn-default" id="login_sub">登录</button>
</form>
</div>
<script src="{% static 'js/jsencrypt.js' %}"></script>
<script src="{% static 'js/jquery-3.1.1.js' %}"></script>
<script src="{% static 'js/js.js' %}"></script>
<script>
$(function () {
var obj = new LoginInit();
obj.login();
obj.flushcode();
})
</script>
{% endblock %}
浙公网安备 33010602011771号