2019独角兽企业重金招聘Python工程师标准>>>

由于传统的静态口令存在容易泄露(输入型泄密、传输型泄密、共享型泄密、记录型泄密、时间越长泄密危险性越高)且一旦泄露全线崩溃、不能抵御重放攻击的缺点,更安全的动态口令方案应运而生。动态口令被广泛应用于手机支付网银防盗链等场景。基于共享密钥的动态口令方案几乎算得上是最简单的一种动态口令方案,但由于其简单也是很常用的一种方案,当然也有它的局限性。本文结合我在实际工作中的一些心得梳理下这种方案的实现和注意事项。

一般动态口令的特点有下面这些:

  • 动态性或者时效性,即动态口令产生后经过一段时间就会失效

  • 随机性,动态口令是随机生成的,不可预测

  • 一次性,每个动态口令使用一次后,不可再连续重复使用(这条在某些场景下不一定要满足,某些场景只需要满足第一条的时效性即可。但对于涉及支付、金融、机密信息等场景,这一条必须严格满足)

  • 抗窃听性,由于动态口令的时效性和一次性,即使某个动态口令被窃取了,也由于动态口令的时效性和一次性,而无法被再次使用。这样能避免“重放攻击”

  • 抗暴力猜解,由于动态口令的时效性,要在动态口令有效期内穷暴力猜解出动态口令是比较困难的,再加上可以限制单位时间内猜解出错次数,从而能够更有效地杜绝这种攻击

为了描述更方便,先抽象一个虚拟的业务场景:

A公司是一家在线旅游公司,网站地址是travel.com,它提供了大量的国内外长短途旅游信息。
为拓展公司业务,A公司决定与B公司(一家国际五星级酒店连锁公司)合作,将自己的一些旅游
相关数据开放给B公司,让B公司的Android客户端和IOS客户端可以直接访问获取A公司的旅游数
据(用户不需要登录即可访问)。技术上,A公司提供两套SDK(Android SDK和IOS SDK)给B
公司,SDK内封装了访问旅游数据HTTP API的业务逻辑和动态口令在客户端的相关逻辑。

首先注意上面客户端获取旅游数据不需要用户登录,算是一定程度的简化,这样也能更方便地说明动态口令场景。而现实生活中的一些场景一般是需要用户登录的,通常采用静态口令认证与动态口令认证相结合的方案,典型的如两阶段认证(2-Phase Authentication),比如这里列举一个网游服务器登录场景:

  1. 我在登录界面输入用户名和静态口令,点击登录跳转到下一个界面要求我输入短信验证码(即相当于动态口令)

  2. 60s内我将我收到的短信验证码填入,再点击确认,这时才算真正登录成功;如果60s内我还没有输入那个验证码,则验证码自动失效并且登录失败

借助手机短信或者邮箱发送验证码是动态口令的一种变形方案,它基于的假设是:手机或者邮箱没有丢失,并且即使丢失,静态口令也同时泄露的可能性非常小(当然并不是说可能性非常小就不需要考虑这些极端情况,实际工作中是需要考虑能想到的各种极端情况的,比如为这种极端场景提供手机、邮箱解绑功能或者人工客服协助功能,或为游戏内的贵重道具设置二次口令等)。这种方案可能比较适用于手机支付、登录(比如Gmail登录、微信登录)、修改密码等场景。但它显然不适用于上面的虚拟业务场景。而本文的主角——基于共享密钥的动态口令方案却恰好能很好应对这类业务场景。

下面是具体流程。

A、共享密钥的离线分发和存储

“基于共享密钥的动态口令”,顾名思义我们得先生成一个共享密钥,所谓共享密钥指的是服务端和客户端都需要存储这个密钥。共享密钥生成后一般采用离线分发的形式告知客户端接入方,比如工行网银用的U盾里就内置了一个这样的共享密钥。生成共享密钥一般注意这么几点:

  • 共享密钥是随机生成的不可逆字符串,也就是说即使生成算法和共享密钥同时泄露也无法反推出任何有用信息

  • 为Android客户端和IOS客户端各自生成一份共享密钥,避免将所有鸡蛋全放在一个篮子里的问题

这里提供一个生成共享密钥的伪码,仅供参考(AES Key生成和HMAC-SHA1哈希算法实现可参考:Crypter.java):

/*** 生成共享密钥* @param appKey       为B公司分配的应用唯一Key,Android客户端和IOS客户端共享* @param clientOsType 客户端操作系统类型,1-IOS,2-Android* @return*/
def generateSharedKey(String appKey, int clientOsType):String randKey = getAESSecretKey(now()) // 当前服务器时间作为种子,生成随机AES Key作为下面HMAC-SHA1哈希的keyString rawData = appKey + "|" + clientOsTypereturn hmacSHA1(rawData, randKey) // 进行HMAC-SHA1哈希得到共享密钥

注意上面提供appKey是出于扩展性考虑,将来A公司可能继续跟其他酒店公司合作,那么可以复用整套动态口令方案,只需要分配不同的appKey,appKey可通过UUID算法生成。将appKey和clientOsType作为哈希运算的数据,可以保证不同appKey、不同的客户端操作系统类型生成的共享密钥是不同的。

生成共享密钥后,服务端存储很简单,只需要存储appKey、clientOsType到共享密钥的映射关系。

关键是客户端该如何存储?

有人可能会选择将共享密钥打包进SDK中,然后将SDK源码混淆。这样做初看起来怪怪的,因为基本上没见过SDK源码还加密的,仔细思考后发现这种做法存在一个明显的大纰漏:如果将共享密钥打包到SDK中,那么未授权的其他公司也可以把这份SDK用于自己的客户端,显然这不是我们想要的结果。

所以共享密钥只能让B公司自己妥善存储,我们建议B公司将共享密钥加密并编译进客户端程序中。

B、客户端用共享密钥签名各参数并构建动态口令生成请求

客户端用共享密钥对app_key(客户端自己管理)、client_os_type(SDK API内部获取)等参数并构建动态口令生成请求发送到服务端,签名的目的是防参数被篡改以及防抵赖。签名算法大概如下:

  1. 将参数key-value对按照key的字典排序,并用&连接,比如app_key=xx&client_os_type=xx

  2. 对上面得到的字符串进行Base64编码,即base64Encode("app_key=xx&client_os_type=xx")

  3. 以共享密钥为key,用HMAC-SHA1算法对上面得到的Base64编码字符串进行签名得到签名参数sig,即:

sig = hmacSHA1(base64Encode("app_key=xx&client_os_type=xx"), sharedKey);

然后将参数连同签名一起发往服务端请求生成动态口令:

curl -X POST -d "app_key=xx&client_os_type=xx&sig=xx" http://open.travel.com/otp

C、服务端校验参数签名并生成动态口令

服务端接收到上面的请求后,简单进行参数是否为空等有效性校验后提取app_key、client_os_type参数,然后根据A步骤存储的映射关系得到服务端存储的共享密钥,然后按照与B步骤相同的方法对参数进行签名,并与传进来的sig参数比对:如果不匹配则返回错误;如果匹配则说明客户端是已授权的客户端,则继续生成动态口令,生成动态口令的伪码如下:

/*** 服务端生成动态口令*/
randKey = getAESSecretKey(now()) // 以当前服务器时间作为种子得到随机AES Key
rawData = "app_key:" + appKey + "|client_os_type:" + clientOsType + "|" + randKey
otp = hmacSHA1(rawData, sharedKey) // sharedKey是服务端存储的共享密钥/*** 服务端存储动态口令并返回给客户端*/
save(otp, 600) // 存储动态口令,并设置600s的失效时间
return otp

注意:

  • randKey是为了增加随机性,这样即使动态口令生成算法被公开,也无所谓

  • 上面共享密钥参与了动态口令的生成过程,这并不是必须的,如果认为共享密钥参与动态口令生成会增大共享密钥被破解的风险,那么可以自行设计,只要保证算法具有足够的随机性不可逆性就好

D、客户端使用动态口令请求数据

客户端接收到动态口令后,就可以使用动态口令请求旅游数据了。一样的用shared_key对参数(包括动态口令otp参数)进行数字签名,签名算法也跟B步骤一样:

curl -X POST -d "app_key=xx&client_os_type=xx&otp=xx&q=海南&sig=xx" http://open.travel.com/hotline

上面q参数是具体数据API调用参数,即请求带有“海南”关键词的热门旅游路线数据。

E、服务端先验证参数签名,再验证动态口令有效性

服务端收到D步骤发来的请求后,首先对参数进行签名验证,跟C步骤差不多。然后验证动态口令是否有效:如果无效则提示错误;如果有效(则让动态口令失效,这里可以不立即失效,但对于支付等场景必须立即失效),并继续调用开放数据API,并返回数据给客户端。

这里可以增加动态口令出错锁定机制:即在某一段时间内动态口令尝试出错次数达到某个值,就锁定相应客户端(如根据IP地址),一段时间接收但不处理那个客户端的请求。

总体来说,共享密钥被用于数字签名、身份认证。期间还尝试过由客户端生成动态口令,而服务端只进行动态口令验证,但仔细推敲后,认为那种方案不利于服务端进行监控管理并可能给动态口令的时效性带来破坏(比如基于客户端系统时间生成动态口令,那么客户端可以修改系统时间来让动态口令永远不会过期)。

而网银USB Key,一般是将共享密钥内置在硬件中,并且每个USB Key的共享密钥都不一样,所以网银的动态口令可以在客户端生成,然后在服务端验证。我们应该具体业务场景具体分析。

最后记住一点,基于共享密钥的动态口令方案的核心安全前提是:

共享密钥能够被客户端妥善安全存储

如果不满足这个前提,那么就不能使用这种动态口令方案。

转载于:https://my.oschina.net/feichexia/blog/305850

动态口令设计系列一:基于共享密钥的动态口令方案相关推荐

  1. 《Cinema 4D + After Effects动态图形设计案例解析》——第 1 章 动态图形设计概述 1.1 什么是动态图形...

    本节书摘来自异步社区<Cinema 4D + After Effects动态图形设计案例解析>一书中的第1章,第1.1节,作者 Klet,更多章节内容可以访问云栖社区"异步社区& ...

  2. 《Cinema 4D + After Effects动态图形设计案例解析》——1.2 动态图形的历史和发展...

    本节书摘来自异步社区<Cinema 4D + After Effects动态图形设计案例解析>一书中的第1章,第1.2节,作者 Klet,更多章节内容可以访问云栖社区"异步社区& ...

  3. 《Cinema 4D + After Effects动态图形设计案例解析》——1.3 动态图形的应用领域

    本节书摘来自异步社区<Cinema 4D + After Effects动态图形设计案例解析>一书中的第1章,第1.3节,作者 Klet,更多章节内容可以访问云栖社区"异步社区& ...

  4. 《Cinema 4D + After Effects动态图形设计案例解析》——1.4 动态图形设计师使用什么软件...

    本节书摘来自异步社区<Cinema 4D + After Effects动态图形设计案例解析>一书中的第1章,第1.4节,作者 Klet,更多章节内容可以访问云栖社区"异步社区& ...

  5. html5 怎么写动态图形设计,如何用SVG制作酷炫动态图标?(代码实例)

    本章给大家介绍在html5中如何用SVG制作酷炫动态图标?(代码实例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 一.基本图形元素 svg有一些预定义的形状元素:矩形,圆形,椭圆 ...

  6. 手机WAPI功能检测常见问题分析(系列连载三):预共享密钥功能

    原文地址:http://www.wapia.org/topic/standards/detail_5073.shtml 1 预共享密钥功能测试中常见问题及解决方法 A. 问题一:预共享密钥长度不符合要 ...

  7. 基于量子密钥的经典身份认证系统

    说在前面:2021.4.8,天气晴朗,心情不是很美好,刚刚和老师聊完,老师说不要去轻易否定一篇论文一个人,想起自己平常表现,表示很羞愧,大概这就是自己目前眼光局限性.反正不是很美好的样子,不知道啥时候 ...

  8. 【oracle灾备方案系列】基于DDS的Oracle复制容灾方案(三)

    <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> [oracle ...

  9. oracle灾备同步_【oracle灾备方案系列】基于DDS的Oracle复制容灾方案(三)

    [oracle灾备方案系列]基于DDS的Oracle灾备方案(三) 在基于DataGrid DDS产品实现灾备架构中,不仅能够实现集中交易系统的灾备功能,实现0时间的数据库切换.同时在该架构基础上还能 ...

最新文章

  1. MATLAB可以打开gms文件吗,GMS文件扩展名 - 什么是.gms以及如何打开? - ReviverSoft...
  2. java 时钟 算法分析_java实现时钟方法汇总
  3. 谈一下我对如何设计微服务接口的理解和思考
  4. 一位老工程师的忠告,切记!
  5. Sublime和LaTeX支持
  6. 如何破解linux用户帐号密码二
  7. Stackint stack = new Stackint报错原因
  8. oracle进入rman报错,Oracle学习系列之Rman学习(三)
  9. python函数如何结束_如何在Python中结束函数
  10. Python:下载安装包
  11. 数学建模 相关系数(皮尔逊相关系数和斯皮尔曼相关系数)
  12. access无法 dolby_Win10专业版装不了dolby该怎么办?Win10 dolby音效驱动安装教程
  13. Verilog HDL实现智能药盒
  14. STM32配合火焰传感器的火灾报警
  15. 一文读懂哈希算法SHA256
  16. android 自定义indicator,Android实现自定义Indicator的导航控件
  17. MVC和MVT框架对比
  18. 2023年全国最新交安安全员精选真题及答案1
  19. install4j的使用
  20. 面试结束时应该向面试官提出什么问题

热门文章

  1. 笔记本摄像头怎么打开?几个步骤轻松打开
  2. 【精彩回顾】第五届中国大数据应用论坛隆重举行
  3. 三袋米的故事——可怜天下父母心
  4. 云栖谷楼盘沙盘_云栖谷图片相册,户型图,样板间图,装修效果图,实景图-长沙房天下...
  5. C#毕业设计——基于C#+asp.net+cs的电子邮件收发系统设计与实现(毕业论文+程序源码)——电子邮件收发系统
  6. 时间序列论文常用数据集
  7. BBC news reading 3--前缀 patr
  8. f2pool鱼池服务器不稳定,细数室外鱼池最常见问题及处理办法,很多人都不知道...
  9. 叉积求点到平面距离_OpenCV计算点到直线的距离 数学法
  10. JS中some和every的区别和用法