关于本站
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 回复