Simple Life

和这个世界交手这许多年   你是否光彩依旧,兴致盎然...

您现在的位置是:首页 爱折腾 爱折腾详情

给你的web网站登录加上USBkey验证

发布时间:2016-3-10 作者:Felix 浏览(5625)

    为了满足项目安全性要求,网站加上了USBKey登录验证,这样网站目前是登录密码、HTTPS、验证码、隐藏80端口再加USBKey的两种加密模式,虽然有些是防君子不防小人,但也满足了一般的安全要求。USBKey我采用了淘宝上比较普遍的vikey加密狗,商家没有提供python实现,于是按照实现原理,自己研究了下,整理下来有需要的可以看看。

    

USBKey

    1. USBKey介绍:

        USBKey限制登录,电脑插上正确的USBKey可以登录,否则不行,身份认证的原理总的来说有如下两种:

        1、在客户端检查锁的信息,并将用户锁的信息提交给服务端,服务端检查是否合法。

         A、检查加密狗的信息可以是加密狗硬件ID或事先写入到加密狗的数据(例如将用户名和密码写入加密狗)

         B、使用这种验证的方式一般是用来替换原来的用户名及密码输入,安全性一般

        2、使用算法的方式,进行两端验证

         A、第一种方法只是简单地从客户端读取加密狗硬件ID或从加密狗中读取加密狗的数据,

                  这样就容易被一些黑客编写一些程序对这些进行模仿,

                  从而绕过从客户端读取加密锁。

         B、方法二则是先从服务器端生产一个随机数据,然后将该随机数发给客户端,

                  同时服务器端使用与加密狗一致的算法对该随机数进行加密,

                  生成一组服务器端验证数据;

         C、而在客户端,在获得服务器发过来的随机数据后,客户端使用对应的算法同样对该随机数据

                  进行加密,生成一客户端验证数据,返回给服务器端,

         D、如果相同,则为合法用户,如果不相同,则为非法用户。

         E、只有在服务器的加密密钥与设置在加密狗中的加密密钥一致时,两边加密的结果才能相符,

                 才能被合法验证。加密狗中的秘钥可以由开发商自行设置。

        

ubyl.png

    

    2. 确定方案:

        第一种方式太过简单,安全系数不高。最后我决定两种结合起来用。

        1. USBKey自身的硬件ID与用户简介绑定,登录时判断硬件ID是否与绑定的USBKey一致。

        2. 登陆页GET请求时返回随机数,js请求USBKey,对随机数进行加密,POST请求提交加密后的数据,后端对随机数加密,判断是否一致。(3Des对称加密)

    

     3. 方案实现:

        1. 首先得了解下3Des加密,python有第三方库 pyDes链接

            此加密方式不同于RSA,为对称加密,不清楚的同学补下密码学。项目中我把加密的key保存在setting文件中,USBKey中使用帮助工具,将密钥及一些初始配置烧写进去,当然烧写也需要管理员登录的。

# USB KEY随机字符串内容
USB_RANDOM_STRING = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
# USB KEY随机字符串长度
USB_RANDOM_NUM_LENGTH = 24
# 3Des加密密钥
USB_DES_KEY = 'lc2p6wwmvrsyxpvkf1hr6j7n'

        2.看下表结构

            1. user 表

CREATE TABLE `user_nsuser` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `username` varchar(30) NOT NULL COMMENT '用户名',  
  `password` varchar(128) NOT NULL COMMENT '密码',
  `usb_key` varchar(100) DEFAULT NULL COMMENT 'usb_key序列号',
  PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=62 DEFAULT CHARSET=utf8;

            2. usbkey_info 表

CREATE TABLE `user_usbkeyinfo` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `sn` varchar(30) NOT NULL COMMENT 'usbkey序列号',
  `key_id` varchar(50) NOT NULL COMMENT 'usbkey硬件序列号',
  `has_used` tinyint(1) NOT NULL COMMENT '是否已使用',
  `user_id` int(11) DEFAULT NULL COMMENT '用户id',
  PRIMARY KEY (`id`),
  UNIQUE KEY `sn` (`sn`),
  UNIQUE KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

        a. usbkey_info为事先录入的usbkey信息,类似于一个库存表。

        b. user表中保存用户信息,usb_key字段是人为标注在usbkey壳上的序列号,用以区分,

            当创建新用户或修改用户信息需要usbkey登录时,绑定此序列号(而非硬硬件ID)。

            同时,usbkey_info中响应的usbkey记录要做变更,并绑定userid为当前用户,has_used字段置为1(已使用)

        

        3. html 处理

var ViKeyInterface;  //初始化插件
function LoadViKeyInterface() 
{
    try
    {
        if (document.implementation && document.implementation.createDocument && typeof XSLTProcessor != 'undefined') 
        { 
            ViKeyInterface= document.getElementById('ViKeyInterface');
        }
        else
        {
            ViKeyInterface=new ActiveXObject("ViKeyActiveX.ViKeyInterface.1");
        }
    var ViKeyCount;
    ViKeyCount = ViKeyInterface.IVikeyFind();
 }
   catch(e)  
   {  
    alert("没有安装ViKey加密狗网页控件, 请安装ViKey加密狗网页控件");  // 插件购买时商家会提供
    return false;
   }  
    return true;
   }
window.onload = function() 
{
    LoadViKeyInterface();
}

function ViKeyHID()  //获取硬件ID
{
   var ViKeyIndex;
   var ViKeyHID;

   ViKeyIndex = 0;  
   ViKeyHID = ViKeyInterface.IVikeyGetHID(ViKeyIndex);
}

function Des3Encrypt()   //3Des加密
{
   var ViKeyIndex;
   var test_value = "4fbG1eT9r8Uk0dFUxLfdcYrX"  // 初始返回的随机字符串
   var buffer="";
   
   ViKeyIndex = 0;
   buffer = ViKeyInterface.IVikey3DesEncrypt(ViKeyIndex, FM.edtDesEncrypt.value);
}

    4. 后端登录验证处理(截取form中部分代码

import binascii

from user.models import UsbKeyInfo
from utils import pydes

if self.user.usb_key:
    if not key_id:
        raise forms.ValidationError(u'请确认usb key是否插入。')
    else:
        k = pydes.triple_des(settings.USB_DES_KEY, pydes.ECB, None, pad=None, padmode=pydes.PAD_PKCS5)
        d = k.encrypt(str(random_num))  # 3Des加密随机数
        right_value = binascii.b2a_hex(d)
        if not des_value.lower() == right_value[:-16]:  # 后端加密与前端usbkey加密的值对比
            raise forms.ValidationError(u'请使用指定的usb key。')
        usb_info = UsbKeyInfo.objects.filter(sn=self.user.usb_key, has_used=True, user=self.user)
        if not usb_info.exists() or (usb_info.exists() and (not key_id == usb_info[0].key_id)):  
            raise forms.ValidationError(u'请使用正确的usb key。')  # 判断与绑定的usbkey硬件ID是否一致

    至此,绑定了usbkey的用户登录就必须得插上usbkey才能登录了。


基于 Django 搭建

服务器采用的 阿里云

域名来自 万网

苏ICP备16015443号

©2015-2016 felixglow.com.

GitHub

Design by Felix