python与Google Authenticator令牌代码实现【案例】

传统的用户名密码方式,容易泄漏,并不安全。
你说,加上短信验证码不就安全了,其实短信验证码也是不安全的,容易被拦截和伪造,SIM 卡也可以克隆,已经有案例,先伪造身份证,再申请一模一样的手机号码,把钱转走。
因此就有了 Two-factor authentication,简称 2FA,也就是双因素验证。最常见的就是用户名密码,再加一个动态码。动态码通常由随身携带的移动设备上生成,比如 U 盾、手机。
动态码最常见的实现算法就是 One-Time Password(OTP),是基于时间的一次性密码,它是公认的可靠解决方案,已经写入国际标准 RFC6238。比如我们最常用的 Google Authenticator,就是 OTP。
那么,知道了 2FA,接下来应该考虑的事,就是如何让你用 Python 写的网站实现 2FA。
轮子其实已经有了,那就是 PyOTP,结合自己的理解,分享一下它的用法。
pip 安装,不多说。
pip install pyotp
码封装实现:
逻辑包括但不限于:生成二维码、生成密钥、校验动态口令
# -*- coding: utf-8 -*-
import base64
from io import BytesIO
import pyotp  # pyotp==2.3.0
from qrcode import QRCode, constants  # qrcode==6.1

class GoogleAuthenticatorClient:
    def __init__(self, secret_key=None):
        self.secret_key = secret_key

    def create_secret(self, key_length):
        """
        generate google auth secret
        :param: key_length
        :return:
        """
        self.secret_key = pyotp.random_base32(key_length)
        return self.secret_key

    def create_secret_qrcode(self, secret_key, name=None, issuer_name=None):
        """
        make qrcode
        :param name:user account
        :param issuer_name:
        """
        data = pyotp.totp.TOTP(secret_key).provisioning_uri(name=name, issuer_name=issuer_name)
        qr = QRCode(
            version=1,
            error_correction=constants.ERROR_CORRECT_L,
            box_size=6,
            border=4, )

        qr.add_data(data)
        qr.make(fit=True)
        img = qr.make_image()

        # img.save('./secret.jpeg')

        buf = BytesIO()
        img.save(buf, "JPEG", quality=70)
        buf_str = buf.getvalue()
        buf_str = base64.b64encode(buf_str)
        return buf_str

    def verify_2fa_code(self, secret_key, code):
        """
        verify code
        """
        totp = pyotp.TOTP(secret_key)
        verify_flag = totp.verify(code)
        return verify_flag

google_auth_client = GoogleAuthenticatorClient()

# if __name__ == "__main__":
    google_auth_client = GoogleAuthenticatorClient()
    secret_key = google_auth_client.create_secret(32)
    print(secret_key, len(secret_key))
    qr_base64 = google_auth_client.create_secret_qrcode(secret_key, name='admin')
    print(qr_base64)

    res = google_auth_client.verify_2fa_code("BX5URJEOIEFRQTU2UPGF7YOZJJ5LZ6AR", '971367')
    print(res)

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

:bowtie:

  • 我们往往会在不同的网站上使用相同的密码,这样一旦一个网站账户的密码泄露,就会危及到其他使用相同密码的账户的安全,这也是最近的密码泄露事件造成如此大影响的原因。为了解决这个问题,一些网站在登录时要求除了输入账户密码之外,还需要输入另一个一次性密码。银行常用的动态口令卡就是这种一次性密码的例子,在线支付网站的一次性短信密码则是另一种实现。我们往往会在不同的网站上使用相同的密码,这样一旦一个网站账户的密码泄露,就会危及到其他使用相同密码的账户的安全,这也是最近的密码泄露事件造成如此大影响的原因。为了解决这个问题,一些网站在登录时要求除了输入账户密码之外,还需要输入另一个一次性密码。银行常用的动态口令卡就是这种一次性密码的例子,在线支付网站的一次性短信密码则是另一种实现。

  • Google现在也推荐用户启用两步验证(Two-step verification)功能(Youtube上的视频介绍),并且除了以短信或者电话的方式发送一次性密码之外,还提供了另一种基于时间的一次性密码(Time-based One-time Password,简称TOTP),只需要在手机上安装密码生成应用程序,就可以生成一个随着时间变化的一次性密码,用于帐户验证,而且这个应用程序不需要连接网络即可工作。仔细看了看这个方案的实现原理,发现挺有意思的。下面简单介绍一下。

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

  • 客户端和服务器事先协商好一个密钥K,用于一次性密码的生成过程,此密钥不被任何第三方所知道。此外,客户端和服务器各有一个计数器C,并且事先将计数值同步。

  • 进行验证时,客户端对密钥和计数器的组合(K,C)使用HMAC(Hash-based Message Authentication Code)算法计算一次性密码

网站声明: 1.本站大部分资源搜集于网络,仅代表作者观点,如有侵权请提交修改。 2.网站内容仅网站站长做个人学习摘记,任何人不得用于其他商业用途,网站发表的内容全权归原作者所有。 3.有任何疑问,可以点击右侧边栏的联系QQ进行咨询 4.本网站部分内容来自于其他网站平台的,版权归原网站所有,本网站只作信息记录,自己学习使用,特此申明,本站用户也不得使用此信息内容做其他商业用途。
白丁学者 » python与Google Authenticator令牌代码实现【案例】

发表回复

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据