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)算法计算一次性密码
白丁学者 » python与Google Authenticator令牌代码实现【案例】