两步验证: 使用Python接入Google Authentiator

article/2025/10/6 14:40:33

Google Authenticator

文章目录

  • Google Authenticator
  • 简介
  • 原理
    • HOTP
    • TOTP
  • 实现
    • 生成密钥
    • 计算时间片
    • HMAC-SHA1运算
    • 生成二维码
    • 校验
  • 使用
  • 参考资料

简介

用户常常会在不同的网站使用相同的密码,一但一个网站账户的密码泄露,就会危及到其它使用相同密码的账户。为了解决这个问题,一些网站在登录时除了要求输入账户密码之外,还需要输入另一个一次性密码。例如银行常用的动态口令卡。

在这里插入图片描述

目前,大部分应用采用 Google Authenticator(谷歌身份认证)来生成认证令牌,只需要手机上安装一个APP,就可以生成一个不断变化的一次性密码,用于账户验证,而这个 APP 无需联网即可工作。

原理

HOTP

Google的两步验证算法源自 HMAC-Based One-Time Password 算法,简称 HOTP。工作原理如下:

  1. 客户端和服务器事先协商好一个密钥 K,用于标识用户;计数器 C,用于生成动态密码

  2. 进行验证时,客户端对密钥和计数器的组合(k,c) 使用 HMAC 算法计算一次性密码,公式如下:

    HOTP(K,C) = Truncate(HMAC-SHA-1(K, C))
    

由于 HMAC 算法得出的值位数比较多,不方便用户输入,因此需要截短(truncate)成为一组不太长的十进制数(例如 6 位)。计算完成之后客户端计数器 C 计数值加 1,服务器端进行同样的计算,并与用户提交的数值进行比较,若一致则通过,服务器端将计数值增加 1。若不相同,则验证失败。

这里有一个问题,如果验证失败或者客户端不小心多进行了一次生成密码操作,那么服务器和客户端之间的计数器 C 将不再同步,因此需要有一个重新同步(Resynchronization)的机制。详情可参考 RFC 4226

TOTP

介绍完 HOTP,TOTP (Time-based One-time Password) 就容易理解了。TOTP 将 HOTP 中的计数器 C 用当前时间 T 来替代,于是就得到了随着时间变化的一次性密码。

虽然原理很简单,但是用时间来替代计数器会有一些特殊的问题,例如:

  1. 时间 T 的值怎么选取?

    时间每时每刻都在变化,如果选择一个变化太快的 T ,那么用户来不及输入密码;如果选择一个变化太慢的 T ,那么第三方就有充足的时间来爆破一次性密码(6 位数字的密码仅有 10^6 种组合);综合以上考虑,Google 采用了 30 秒作为时间片,T 的数组为从 Unix epoch(1990年 1 月 1 日 00:00:00)来经历的 30 秒的个数

  2. 网络延时,用户输入延迟

    由于网络延时,用户输入延迟等因素,可能当服务器端接受到一次性密码时,T 的数值已经改变,这样就会导致验证失败。一个办法是,服务器计算当前时间片以及前面的 n 个时间片内的一次性密码值,只要其中有一个与用户输入的密码相同,则验证通过。当然,n 不能太大,否则会降低安全性。

    此外,如果我们知道客户端和服务器的时钟有所偏差,当服务器通过计算前 n 个时间片的密码并成功验证后,服务器就知道了客户端的时钟偏差。因此,下一次验证时,服务器就可以直接将偏差考虑在内进行计算。

实现

在这里插入图片描述

生成密钥

def generate_secret(obj:str) -> tuple:"""生成密钥:param obj: 生成密钥的字符串:returns: secret: 字符串密钥, 用于生成二维码k     : base32解码的密钥, 用于 HMAC 签名"""base32_obj = base64.b32encode(obj.encode())# 编码后的=, ios端 Authenticator 扫码时会出现问题, 此处将其全部转换为 Asecret = base32_obj.decode().replace('=', 'A')k = base64.b32decode(secret)     return secret, k

计算时间片

def generate_timestamp_bytestring():"""生成字节时间片"""ts = int(time.time()) // 30return struct.pack(">Q", ts

HMAC-SHA1运算

def truncate(hmac_hash:bytes) -> str:"""将 hmac结果 转换为 6位数字"""offset = hmac_hash[19] & 0xfgoogle_code = (struct.unpack(">I", hmac_hash[offset: offset+4])[0] & 0x7fffffff) % 10**6# 若计算后结果不足6位, 则在左侧补0google_code = f'{google_code:>06}'return google_codedef generate_pwd(k:bytes, c:bytes) -> str:"""生成 google 一次性密码:param k: base32解码的密钥:param c: 字节时间片:returns: 6位数字密码"""hmac_hash = hmac.new(k, c, sha1).digest()google_pwd = truncate(hmac_hash)return google_pwd

生成二维码

def generate_qrcode(secret:str, label:str=None, account:str=None) -> str:"""生成 TOTP 配置 URI, 将其转换为二维码;可通过 Google Authenticator 扫码添加:param secret: 字符串密钥:param label: [可选]标识平台:param account: [可选]标识账号:returns: 二维码图片url"""base_uri = 'otpauth://totp/{prefix}?{ends}'prefix = ''ends = {'secret': secret,}if label:prefix += labelends['issuer'] = labelif account:prefix += f':{account}'totp_uri = base_uri.format(prefix=prefix, ends=urlencode(ends))# 草料二维码 apiqrcode_url = f'https://api.pwmqr.com/qrcode/create/?url={quote(totp_uri)}'return qrcode_url

校验

  • 在线校验: https://rootprojects.org/authenticator/
  • APP 校验:
    • Android: https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en_US&gl=US
    • Ios: https://apps.apple.com/cn/app/google-authenticator/id388497605

使用

项目源码: https://github.com/zzzzls/python_authentiator

  1. 使用 pip 安装

    pip install python-authentiator
    
  2. 使用

    from python_authentiator import TOTPg_auth = TOTP(origin_secret='123456',label='demo',account='example@gmail.com'
    )# 生成密钥
    secret = g_auth.generate_secret()
    # 生成一次性密码
    print(g_auth.generate_code(secret))
    # 生成二维码
    print(g_auth.generate_qrcode(secret))
    

参考资料

  1. HOTP: An HMAC-Based One-Time Password Algorithm,

    RFC 4226: https://datatracker.ietf.org/doc/html/rfc4226

  2. TOTP: Time-based One-time Password Algorithm,

    RFC Draft: https://tools.ietf.org/id/draft-mraihi-totp-timebased-06.html

  3. Google Authenticator project: https://github.com/google/google-authenticator

  4. Google账户两步验证的工作原理:

    IMCT: https://blog.seetee.me/post/2011/google-two-step-verification/

  5. Google Authenticator TOTP原理详解

    https://blog.51cto.com/xsboke/2363746


http://chatgpt.dhexx.cn/article/FyAQOZ8r.shtml

相关文章

用Abp实现两步验证(Two-Factor Authentication,2FA)登录(三):免登录验证

文章目录 原理修改请求报文配置JwtBearerOptions生成Token校验Token修改认证EndPoint修改前端登录登出 最终效果项目地址 免登录验证是用户在首次两步验证通过后,在常用的设备(浏览器)中,在一定时间内不需要再次输入验证码直接登录…

两步教你在Vue中设置登录验证拦截!

Hello,你好呀,我是灰小猿,一个超会写bug的程序猿! 今天在做vue和springboot交互的一个项目的时候,想要基于前端实现一些只有登录验证之后才能访问某些页面的操作,所以在这里总结一下实现该功能的一个解决方…

HTTPS实战之单向验证和双向验证

(全文太长,太懒不想看,-_-b 那就直接拉到底部看总结 ) 前面的文章中,提到了,https是在TCP协议与http之间加了一个控制安全传输的SSL协议,也就是说,直接运行在TCP之上的HTTP是普通的…

验证基础-验证方法

目录 动态仿真 静态检查 虚拟模型 硬件加速 效能验证 UVM简介 验证的方法主要分为六种: ※ 动态仿真(dynamic simulation) ※ 静态检查(formal check) ※ 虚拟模型(virtual prototype) ※…

用Abp实现两步验证(Two-Factor Authentication,2FA)登录(一):认证模块

文章目录 原理用户验证码校验模块双因素认证模块改写登录项目地址 在之前的博文 用Abp实现短信验证码免密登录(一):短信校验模块 一文中,我们实现了用户验证码校验模块,今天来拓展这个模块,使Abp用户系统支…

用Abp实现两步验证(Two-Factor Authentication,2FA)登录(二):Vue网页端开发

文章目录 发送验证码登录退出登录界面控件获取用户信息功能项目地址 前端代码的框架采用vue.js elementUI 这套较为简单的方式实现,以及typescript语法更方便阅读。 首先添加全局对象: loginForm: 登录表单对象 twoFactorData: 两步验证数据&#xff0…

快速接入Google两步认证Google Authenticator

(一)介绍 既然来看该文章就应该知道Google的两步认证是干什么的,这边再提供一次app的下载链接 (apkpure搜索谷歌身份验证器) 验证原理讲解: 在数据库中查找该登陆用户之前绑定的32位随机码(该码一般会存入数据库)调用API传入32位…

两步验证 非双重认证

Two-factor authentication must be turned on for your Apple ID. After you turn it on, signing into your developer account will require both your password and access to your trusted devices or trusted phone number. 今天Xcode 真机调试, 突然不正常了. 本着热爱…

google账号异步新设备登录需要两次两步验证问题

备注:华为手机,在谷歌三件套插件已经下载的情况下,还是无法收到数字点击验证 先说下现象,比如你的谷歌账号从别人那购买的,然后辅助电话与邮箱已经全部替换成了自己的信息,一般为了安全我们会开启两步验证&…

谷歌两步验证器身份怎么开Authenticator安卓app下载安装方法教程

国内互联网公司一般采取手机收验证码的方式对账号进行身份验证,增强账号的安全性。但是在国外通常采取使用谷歌两步身份验证器 (Google Authenticator),谷歌谷歌两步身份验证器的方便之处主要体现在: 1.在无网络的情况下也可以使用…

如何开发两步验证功能

什么是两步验证 两步验证,是指用户登录账户的时候,除了要输入用户名和密码,还要求用户输入一个动态密码,为帐户添加了一层额外保护。这个动态密码要么是专门的硬件,要么由用户手机APP提供。即使入侵者窃取了用户密码&a…

兩步验证的原理

被盗号 “您的账号密码有误,请重新输入” 小卢盯着电脑屏幕看了5分钟,心里纳闷,昨天还能登录,怎么今天就密码错误了,难不成我被盗号了?想到这里,小卢赶紧给自己的程序员好友小王打电话。 小卢:“小王,我在XX网站的账号被盗了!” 小王:“确定被盗了?赶紧把密码找…

(01)Webrtc::Fec与Nack的二三事

写在前面:要理解Fec与Nack逻辑,我喜欢先从接受端看, 理解了Fec与Nack是如何被使用的,才能更好的明白不同的机制应该怎么用,在什么场合用。 更新丢包逻辑 void PacketBuffer::UpdateMissingPackets(uint16_t seq_num)…

Channel closed; cannot ack/nack

再一次用rabbmitmq的时候遇到了 Channel closed; cannot ack/nack的异常信息,这个可能是因为rabbmitmq默认的模式是自动ack,我没有配置手动ack 然后在代码里又basicack了。 MessageProperties properties message.getMessageProperties();l…

简述WebRTC中的丢包重传Nack的实现

一 简述 接收端发现序列号不连续,发送RTCP FB Nack包,发送端从历史队列中查找该包,再发送RTP包,但WebRTC用的RTX重发该包,ssrc和原视频流不同,pt也不同。 artpmap:96 H264/90000 artcp-fb:96 goog-remb a…

WEBRTC浅析(五)视频Nack包的发送判断逻辑以及数据流

这篇文章是对webrtc 中Nack包发送机制的梳理,主要包括三个部分: 第一部分,介绍RTCP包中,Nack包的规范。 第二部分,介绍在WEBRTC中,Nack发送机制的数据流程图。 第三部分,介绍在WEBRTC中&#xf…

RabbitMQ的ack和nack机制

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、ACK机制二、主动ACK三、手动ACK四、Nack机制五、MQ unack的影响总结 前言 本文主要讨论RabbitMQ消费者的ack和nack机制,并且关注ack和nack使用…

RTCP 协议的 NACK 报文

接收方定时把所有未收到的包序号通过反馈报文通知到发送方进行重传。 相对 ARQ带来的改进:减少的反馈包的频率和带宽占用,同时也能比较及时地通知发送方进行丢包重传。 NACK 报文的定义在 [rfc4585] 文档中定义。 RTCP 的反馈报文包头定义如下&#x…

webrtc nack实现原理

1.nack 简介 webrtc 中nack是最基本的QOS策略,与ack机制不同的地方是nack是接收端检测到丢包时,告知发送端具体丢包的序号,接收端收到nack后从缓存中找到对应的包并发送出去。 2. nack实现 nack rtcp报文格式如上图所示,pt205。P…

webrtc QOS方法一(NACK实现)

一:概述 NACK则在接收端检测到数据丢包后,发送NACK报文到发送端;发送端根据NACK报文中的序列号,在发送缓冲区找到对应的数据包,重新发送到接收端。NACK需要发送端发送缓冲区的支持,RFC5104[2]定义NACK数据包…