开发环境
- 操作系统:Windows 10 Pro
- 数据库:Mysql
- 服务器:Django
- 语言:Python3.6 + html + JavaScript + css
3.3 用户环境
Windows、Mac、Linux、Android、IOS,通过浏览器访问。支持的浏览器为 IE、火狐、谷歌浏览器。
3.4 业务数据流
3.5 功能模块划分
3.6 功能模块定义
3.6.1 管理员模块
管理员模块需要经过银行管理员登陆并认证后操作。管理员可以审核用户注册、获取用户异常,并根据异常信息冻结账户,所有的操作记录数据库。
3.6.2 用户操作
用户包括电商用户和普通用户,都可以进行状态修改,比如修改个人信息、修改密码。有敏感操作时需要转到认证模块作安全认证。
3.6.3 身份认证
银行系统的敏感操作之前需要有安全认证。验证内容包括数字证书是否真实、是否过期,登陆状态是否正常。
3.6.4 订单审核
执行 SET 协议,判断订单信息是否真实,再执行支付操作,转账信息写入数据库,并更改账户余额。
3.6.5 通信模块
电商平台根据提供的支付链接转到银行系统,此后双方执行类似于 SSH 的协议互相认证身份并协商出临时对称密钥,用于加密之后的通信。
3.7 功能模块划分
3.7.1 用户基本信息表
Users
3.7.2 管理员基本信息表
Admins
3.7.3 转账信息
Transfer
3.7.4 银行卡信息
3.7.5 存取款信息
4.详细设计
4.1 注册
4.1.1 页面设计
4.1.2 实现方法
输入地址 127.0.0.1:8001,自动跳转到登陆页面,点击注册按钮进入注册页面。
传输安全:将 CA 服务器提供的证书放到 html 页面,用户客户端提交表单时首先提取证书中的公钥字段,利用公钥加密表单,传输到服务器。服务器接收到信息后首先用私钥解密,再执行下一步操作。
前端加密 Signup.html
<script> functionformAck(){ alert("success"); varcert=document.getElementById("cert").value;#从html中获取证书 varcertInfo=JSON.parse(cert).info.certInfo varpubKey=JSON.parse(certInfo).PublicKey#从证书中获取公钥 varencrypt=newJSEncrypt(); encrypt.setPublicKey(pubKey); vardata={ name:$('#name').val(), idcard:encrypt.encrypt($('#idcard').val(),true), phone:encrypt.encrypt($('#phone').val(),true), email:encrypt.encrypt($('#email').val(),true), passwd:encrypt.encrypt($('#passwd').val(),true), paypasswd:encrypt.encrypt($('#paypasswd').val(),true) }; console.log(data) $.ajax({ url:"/signup/", type:"POST", data:data, success:function(data1){ alert(data1) window.location.href="/login/" } }) }</script>
后端加密 Views.py
defsignup(request): ifrequest.method=="GET": returnrender(request,"signup.html") ifrequest.method=="POST": name=request.POST.get("name",None) idcard=tools.DecodeDecrypt(request.POST.get("idcard",None)).decode() phone=tools.DecodeDecrypt(request.POST.get("phone",None)).decode() email=tools.DecodeDecrypt(request.POST.get("email",None)).decode() passwd=tools.DecodeDecrypt(request.POST.get("passwd",None)).decode() paypasswd=tools.DecodeDecrypt(request.POST.get("paypasswd",None)).decode()
数据库存储密码:登陆密码和支付密码不能直接存入数据库,而是存加 salt 的哈希值。
4.2 登陆
4.2.1 页面设计
4.2.2 实现方法
用户点击登陆后,客户端向服务器发送一个 post 请求,包含 公钥加密后的ID 和登陆密码。服务器接收后,用系统私钥解密,解密成功后:
- 验证登陆密码的加 salt 哈希和数据库存储是否一致,一致的话执行下一步操作,不一致返回登陆界面
- 服务器设置 session,添加用户 ID 和 name 字段,之后每次操作验证登陆信息时,检查这两个 session 值是否存在即可
- 服务器返回“success“字段,客户端接收后执行 href="/viewuserinf/" ,执行信息查看操作
- 传输安全:用户在登陆界面提交的表单,前端用公钥加密,服务器用私钥解密,具体操作同注册的传输安全
4.3 信息查看
4.3.1 页面设计
4.3.2 实现方法
请求查看页面的请求类型全部为 get 型,url 为 127.0.0.1:8001/viewuserinf/,服务器接收到该请求后,首先验证session 的 id 字段是否存在,存在才可继续查看,不存在则清楚所有 session 并返回登陆界面。
Views.py
defviewuserinf(request): ifrequest.method=="GET": try: id_session=request.session["id"] tmp=Users.objects.get(id=int(id_session)) returnrender(request,"user_inf_show.html",{"inf":tmp}) except: returnrender(request,"login.html") returnrender(request,"login.html")
4.4信息修改
4.4.1 页面设计
4.4.2 实现方法
由于用户姓名、身份证号是认证信息,不可修改,登陆密码和支付密码不在此模块。所以这里只能修改手机号和电子邮箱。
获取信息修改页面的请求方式是 get,用户点击“信息修改”按钮或者直接在 浏 览 器 地 址 栏 中 输 入 url : http://127.0.0.1:8001/edituserinf/ ,就会返回信息修改页面。
信息修改的表单提交使用 post 请求,用户输入的表单信息用公钥加密后传输,服务器接收后用私钥解密,然后检查 session 的 id 字段是否存在,存在则修改成功,返回信息查看界面,否则返回登陆界面。
4.5 更改密码
4.5.1 页面设计
4.5.2 实现方法
获取修改密码界面的请求方式是 get,用户在登陆状态下,点击“修改密码”或 者 在 浏 览 器 地 址 栏 输 入 url:127.0.0.1:8001/editpasswd/获得界面。用户可选择登陆密码和支付密码,更改密码必须输入原密码。
表单提交的请求方式是 post 请求,客户端使用公钥加密表单,服务器接收请求后用私钥解密,之后:
- 检查服务器 session 中是否存在 id 字段,存在继续下一步,不存在返回登陆界面
- MD5加盐计算密码哈希值,与数据库存储的哈希值对比,相等,执行下一步,否则返回信息修改界面重新提交
- 计算新密码的加 salt 哈希值,存入数据库。修改完成后,如果是修改支付密码,返回信息查看界面,如果是修改登陆密码,删除 session 后返回登陆界面
安全设计 :客户端公钥加密传输表单,客户端私钥解密,保证传输安全。修改密码必须验证原密码,并且密码只存储哈希值,保证密码数据库安全。
4.6 银行卡管理
4.6.1 页面设计
查看所有个人银行卡:
添加银行卡:
添加银行卡:
用户获取银行卡管理界面的请求方式为 get,在登陆状态下点击“银行卡管理”或者 url 输入 127.0.0.1:8001/cardmanage/ 进入银行卡管理界面。服务器将银行卡信息返回给用户,每张银行卡信息包括卡号、建立时间、余额和状态。由于涉及到金额,银行卡一旦添加不可删除。
在银行卡管理模块可以选择添加银行卡,获取页面的请求方式仍是 get。获取到界面后,用户必须输入支付密码,点击确认添加,向服务器发送 post 请求,表单内容为 公钥加密后的支付密码。
服务器接收到请求后,首先检查 session 的 id 字段是否存在,存在执行下一步,否则删除全部 session 返回登陆界面。解密表单内容,获取明文支付密码,计算加 salt 哈希值,对比数据库支付密码哈希值,相同后即可分配银行卡。
银行卡添加成功后,分配一个唯一卡号,状态默认为正常,余额默认为 0。随后返回银行卡管理界面。
4.7 转账
4.7.1 页面管理
4.7.2 实现方法
在登录状态下,用户通过点击“转账”或者输入 url: 127.0.0.1:8001/transfer/向服务器发送 get 请求,进入转账界面。
用户选择本方卡号,输入对方卡号、转账金额、支付密码后确认转账,javascrpt使用公钥加密表单后传输给服务器。服务器接收并私钥解密后:
- 检查登陆状态,即检查 session 的 id 字段是否存在,不存在返回登陆界面,存在则进入下一步
- 计算用户输入的 paypasswd 的加 salt 哈希值,与数据库提取的密码哈希值对比,相同则进入下一步,不同则返回转账界面重新输入
- 将此转账信息写入数据库,再将对应的银行卡做余额更改。执行成功后进入转账查询界面。
安全:
- 客户端公钥加密后传输,防止旁路攻击
- 密码存哈希值,明文不出现数据库
- 转账记录表和银行卡表中记录的更改在确认转账可以执行后,才一起更改防止数据不同步
tmp1=Transfer(time=time, scard=CrashCard.objects.get(id=scard), dcard=CrashCard.objects.get(id=dcard), suser=Users.objects.get(id=uid), duser=Users.objects.get(id=CrashCard.objects.get(id=dcard).user.id), amount=amount, scbalance=CrashCard.objects.get(id=scard).balance-amount, dcbalance=CrashCard.objects.get(id=dcard).balance+amount)CrashCard.objects.filter(id=scard).update(balance=scbalance-amount)CrashCard.objects.filter(id=dcard).update(balance=dcbalance+amount)tmp1.save()
4.8 存款
4.8.1 页面设计
4.8.2 实现方法
在登录状态下,用户点击“存款”或者输入 url: 127.0.0.1:8001/ userdeposit/ 向服务器发送 get 请求,进入存款界面。
在存款界面,输入存款卡号和金额,用 RSA 公钥加密表单,传输给服务器。
服务器解密后,获取卡号和金额,更改数据库银行卡表单,完成操作。返回存取款查询界面。
4.9 取款
4.9.1 页面设计
4.9.2 实现方法
取款操作和存款操作的实现方法类似。不同的内容为:
- 取款的 url 为 127.0.0.1:8001/userdraw/
- 取款需要验证支付密码,支付密码需要计算加 salt 哈希值与数据库存储哈希值对比
4.10 转账查询
4.10.1 页面设计
4.10.2 实现方法
在登录状态下,用户点击转账查询或者输入url: 127.0.0.1:8001/ viewtransfer/向服务器发送get请求,进入转账查询界面。
服务器检查登陆状态,即验证 session 的 id 字段是否存在。存在则将该用户的转账记录返回客户端。
4.11 存取款查询
4.11.1 页面设计
4.10.2 实现方法
在登录状态下,用户点击转账查询或者输入url:127.0.0.1:8001/ viewdrawdeposit/向服务器发送get请求,进入转账查询界面。
存取款查询的实现方法与转账查询方法基本相同。
5.结束语
- 常规网站的设计如果不考虑安全,那么网站能用但是风险极高
- 加密传输可使用 RSA 公钥前端加密,后端解密
- 本次项目的实现让我了解了很多信息安全的知识,增加了动手能力
- 本门课程收获很大