ASP.NET中使用动态令牌进行安全认证

一、前言

在有的项目中,为提高用户身份验证的安全性,需要在账号密码认证身份的基础上增加额外的认证,如加密狗、IC卡等。本例提供另一种方法,采用动态令牌的方式认证,用户在登录时需输入自己令牌产生的口令,认证成功后才能进入系统。

 

二、动态令牌介绍

动态令牌是一个内嵌特殊运算芯片的身份认证产品,根据密钥和动态因子产生动态口令,每次动态随机生成一个新的6位或8位密码。

动态因子可以是时间(时间型)、触发事件(事件型)、服务器端产生随机数(冲击响应)。

动态令牌认证原理可大体上可认为是设备端和程序端使用相同的密码算法、相同的参数独立计算口令值,用户输入设备上显示的口令值后,程序检查是否与自己生成的口令值匹配。

动态令牌

本文使用的动态令牌型号是坚石诚信ET Z201,属于时间型令牌,其大小跟U盘差不多,内置电池,具有以下特点:

1)每分钟更新口令值,为6位长度无规律数字。

2)不需要连接服务器或客户端设备,免驱动,因此可兼容各种项目类型(Web项目、桌面程序、手机端等)。

3)分发令牌手续便利,更换方便。

 

三、背景知识

1、每个动态令牌都有唯一的编号,类似网卡的MAC地址。一般在令牌的背面可以查看到。

令牌号

另外每个令牌都有一个密钥(种子码),一般厂家会随产品发电子文档。

2、动态令牌根据自身编号、当前时间等信息,按一定的算法得到6位长度的口令。口令有效时长1分钟,1分钟内口令不会变化,超过1分钟自动更换新口令。

3、因动态令牌的时间是由电池供电保存在硬件中的,所以令牌中的时间与现实中的时间可能误差。口令认证时不仅仅是验证口令值是否正确,还会后台验证设备时间和现实时间是否相同。为解决时间误差问题,开发时引入了“同步窗口”和“漂移值”两个概念。

4、“同步窗口”含义是时间误差范围,比如设置误差范围为10分钟,则当前时间前后10分钟内都认为是有效时间,超出10分钟则认为时间不符,口令认证失败。其内部工作原理是,程序计算出当前时间前后10分钟的所有动态口令,只要硬件生成的口令在这个范围内就视为有效。

5、“漂移值”含义是设备上的时间与现实时间的误差值,在每次成功验证口令后会返回给系统,目的是给下次验证提供误差纠正标准,减少计算量。

6、每次认证成功时,会返回“成功值”和“漂移值”两个数据,这两个数据需同步更新到该令牌对应的信息中(一般为数据库中)。下一次进行认证时,需要将这两个数据先取出来,再作为参数传递给认证方法。首次认证时这两个数据值可设为0。

 

四、开发思路及步骤

1、数据库中建立令牌信息表,用于存储令牌信息,包括字段:令牌号(string)、密钥(string)、成功值(bigint)、漂移值(int)。

2、数据库中用户表增加令牌号字段,用于关联用户身份与令牌信息。

3、VS项目中引用ET_OTPVerify.dll。

4、用户登录时输入用户名、密码和动态口令,程序根据用户名查询对应的令牌信息,然后进行口令认证,认证成功后进入系统。

 

五、程序开发

1、建立数据库表

2、将开发包ET_OTPVerify.dll放到bin目录下,在项目中以非托管方式调用。开发包有两个方法,分别是认证和同步。

[DllImport("ET_OTPVerify.dll")]
public static extern int ET_CheckPwdz201(string authkey, UInt64 t, UInt64 t0, uint x, int drift, int authwnd, UInt64 lastsucc, string otp, int otplen, ref UInt64 currsucc, ref int currdft);

[DllImport("ET_OTPVerify.dll")]
public static extern int ET_Syncz201(string authkey, UInt64 t, UInt64 t0, uint x, int drift, int syncwnd, UInt64 lastsucc, string otp1, int otp1len, string otp2, int otp2len, ref UInt64 currsucc, ref int currdft);

各参数含义如下:

/* =============================================================================
* Function : ET_CheckPwdz201
* Description: OTP Z201(TOTP) 认证接口
* Parameter :
* authkey 令牌密钥(令牌提供商提供) //应存入数据库中,使用时select
* t 当前时间相对UTC Epoch秒数
* t0 起始参考时间相对UTC Epoch秒数(默认为0)
* x TOTP变化周期(默认为60秒)
* drift 漂移值(用于时间校准) //数据库中取,第一次给0.
* authwnd 认证范围, 通常是0-20
* lastsucc 前一次认证成功的相对UTC Epoch秒数(为防止重放攻击) //数据库中取,第一次给0.
* otp 需要认证的动态口令
* otplen 需要认证的动态口令长度, 通常是6
* currsucc 认证成功后的相对UTC Epoch秒数 //认证成功后应写入数据库,供下次调用。
* currdft 认证成功后的当前漂移次数 //认证成功后应写入数据库,供下次调用。
*
* return : 0 - 成功, 其他值为错误.
*
*int __stdcall ET_CheckPwdz201(char *authkey, uint64_t t, uint64_t t0,
* unsigned int x, int drift, int authwnd, uint64_t lastsucc,
* const char *otp, int otplen, uint64_t *currsucc, int *currdft);
=============================================================================
* Function : ET_Syncz201
* Description: OTP Z201(TOTP) 同步接口
* Parameter :
* authkey 令牌密钥,已经加密过的,需要对其进行解密
* t 当前时间相对UTC Epoch秒数
* t0 起始参考时间相对UTC Epoch秒数(默认为0)
* x TOTP变化周期(默认为60秒)
* drift 漂移值
* syncwnd 同步范围, 通常是0-40
* lastsucc 前一次认证成功的相对UTC Epoch秒数(为防止重放攻击)
* otp1 需要同步的第一个动态口令
* otp1len 需要同步的第一个动态口令长度, 通常是6
* otp2 需要同步的第二个动态口令
* otp2len 需要同步的第二个动态口令长度, 通常是6
* currsucc 认证成功后的相对UTC Epoch秒数 //同步成功后应写入数据库,供下次调用。
* currdft 认证成功后的当前漂移次数 //同步成功后应写入数据库,供下次调用。
*
* return : 0 - 成功, 其他值为错误.

*/

3、用户输入账号、密码、口令,点击“登录”按钮时执行以下代码:

string authkey = "";  //秘钥
UInt64 t = (ulong)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; //时间戳
UInt64 t0 = 0; //起始参考时间相对UTC
uint x = 60; //口令变化周期,默认60秒
int drift = 0; //上次漂移值
int authwnd = 20; //认证范围
UInt64 lastsucc = 0; //上次成功值
string opt = tbCode.Text; //用户输入的口令
int optlen = 6; //口令长度
UInt64 currsucc = 0; //默认的成功值
int currdft = 0; // 默认的漂移值

//首先验证用户登录密码,验证成功后将用户信息放到userModel中,然后验证口令
Model.TokenModel tokenModel = GetTokenModel(userModel.token_sn); //根据用户表中的令牌序列号查询令牌表中的内容
authkey = tokenModel.token_authkey;
lastsucc = tokenModel.token_currsucc;
drift = tokenModel.token_currdft;

int ret = ET_CheckPwdz201(authkey, t, t0, x, drift, authwnd, lastsucc, opt, optlen, ref currsucc, ref currdft);
if(ret == 0)
{
    更新数据库("update [令牌表] set currsucc='" + currsucc + "',currdft='" + currdft + "' where token_sn='" + tokenModel.token_sn + "'"); //认证成功时需回写该令牌的成功值和漂移值
    Response.Write("认证成功!(成功值:" + currsucc + ",漂移值:" + currdft + "]");
}
else
{
    Response.Write("认证失败,错误码:" + ret);
}

返回值ret含义:

0:操作成功
1 :参数无效
2:认证失败
3:同步失败
4:动态口令被重放

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值