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 %}
posted @ 2019-12-06 12:12  Mr-谢  阅读(1706)  评论(0)    收藏  举报