zoukankan      html  css  js  c++  java
  • Google Authenticator

    Google Authenticator

    现在越来越多的网站采用两步验证,实现方式可能有所区别,一般来说是 1+? (1 即 普通的用户名和密码, ?可能是实物如U盾、手机短信验证码或其他)。?的重点是它是一次性的(One-Time Password OTP, 即动态密码). RFC提出了针对OTP的RFC4226, 后对其进行扩展形成了RFC6328协议(增加了 HMAC-based One-Time Password (HOTP)).

    Google Authenticator就是基于RFC6328的实现, 该标准名称为 Open Authentication (OATH), 与OAuth没关系.

    Google Authenticator APP支持Android, iOS, BlackBerry (WindowPhone不清楚).

    APP 在线 Demo:
    https://daplie.github.io/browser-authenticator/ (该Demo使用Google chat服务生成二维码图片, 中国可能无法显示二维码图片)

    APP & HOTP

    Use steps

    1. 用户在手机上安装Google Authenticator APP
    2. 用户认证的网站提供一个二维码(即一个URL信息), 让用户扫描添加该账号
    3. 用户登录后即可输入该APP上显示的动态密码,网站验证该动态密码
      APP生成动态密码 是独立进行的,无需联网. 网站验证过程也是独立的

    二维码或URL的格式(内容)

    关键是secret,其他都是一些提示信息

    otpauth://TYPE/issuer:user?PARAMETERS
    
    TYPE: hotp or totp
    issuer: 发行方 <和后面的参数一致>
    user: 用户账号
    Parameters:
        secret: 密钥
        issuer: 发行方
        其他可选参数, 以及各个细节内容 参见下面Google连接
        
    
    该URL可以将其生成一个二维码, 用户通过APP扫描输入, 也可以手动输入user和secret
    
    例如:
    otpauth://totp/xiaowei:xiaowei@gmail.com?secret=UNYFYWFE7IN6MOAW&issuer=xiaowei
    

    Algorithm

    下面的代码采用 python3 描述

    0. 生成URL上的secret

        # 首先选择一个原始密钥 key, 长度在
        # 然后使用base32进行编码即可, 可以省略padding符(即后面的=)
        # 由于base32结果以%8对齐, 我们也可以截取编码后的8n个长度的字符作为secret
    

    1. 生成动态密码

        # 参数:  secret, input = None
        # 通过 secret 得到 原始密钥 key
        key = b32decode(secret) # 需要对padding符进行处理
        if input == None:
            input = int(time.time()) // 30 # input 为次数, 30为默认密码刷新间隔值
        # 然后使用 HMAC-SHA1算法计算hash
        hsh = hmac.new(key, input, hashlib.sha1).digest()
        # 将hsh转换成数字(默认为6位)
        i = hsh[-1] & 0xf # 以最后一个字节的后4个bits为数字,作为接下来的索引
        f = hsh[i:i+4] # 以i为索引, 取hsh中的4个字节
        n = struct.unpack('>I', f)[0] & 0x7fffffff# 将4个字节按big-endian转换为无符号整数, 转换时去掉最高位的符号位
        # 等价于 n = ((f[0] & 0x7f) << 24) | ((f[1] & 0xff) << 16) | ((f[2] & 0xff) << 8) | (f[3] & 0xff)
        # 将 n % 1000000 得到6位数字, 不足补零
        r = '%06d' % (n % 1000000) # r 即为 生成的动态密码
    

    2. 校验动态密码

        # 参数:  secret, n, window=1
        #                      window为时间窗口, 也就是动态密码有效的时间期限
        
        cur_input = int(time.time()) // 30
        for i in range(cur_input-(window-1)//2, cur_input + window//2 + 1): # [cur_input-(window-1)//2, cur_input + window//2]
            d = generate_dynamic_code(secret, i)
            if d == n:
                return True
        return False
    

    3. 备注

    调试时,可以使用online qrcode将URL转换为二维码

    Ref:

    Github上一个python2实现: rentshare

    Google开源的Authenticator:Google

    协议:rfc6328

    CSDN上的一个中文原理描述:csdn

  • 相关阅读:
    python中普通函数调用协程
    python骚操作之内建方法的使用
    Python常量类
    python实用技巧之任务切分
    容易被忽视的python装饰器的特性
    C语言学习笔记
    python mongo存在插入不存在更新,同时指定如果不存在才插入的字段
    python使用ThreadPoolExecutor每秒并发5个
    mac使用crawlab
    线性表的顺序存储结构
  • 原文地址:https://www.cnblogs.com/i2u9/p/google-authenticator.html
Copyright © 2011-2022 走看看