How the flask generate pin

Table of Contents

1 Flask 的 debug 模式

写过 Flask 的人都知道,只要在 run 的参数中增加一个 debug=True 的参数就可以打开 Flask 的 debug 模式

debug 模式下出现错误会返回一个错误界面,在这里可以输入在启动时产生的 PIN 码执行很多操作,弹个 shell 什么的

但是 PIN 码输入 10 次错误后就会导致无法再使用,直到重启 server

2 PIN 的产生

注意: 本文内容仅对 linux 环境负责

代码参考 werkzeug/debug/__init__.py get_pin_and_cookie_name(app)

Flask 中 PIN 是九位数字每三位以 "-" 分割

PIN 是将几个数值拼接在一起然后做一次 md5

数值分为两种 probably_public_bits 与 private_bit

2.1 probably_public_bits

这几个个信息为了保证 cookie 的可靠

2.1.1 username

username 使用了 getpass.getuser()

getuser 会从 LOGNAME USER LNAME USERNAME 这个几个环境变量中依次选择

都没有的话会尝试使用当前的 uid 进行查找当前的用户名

2.1.2 modname

modname 十分简单

getattr(app, "__module__", app.__class__.__module__)

这里面的 app 就是在 Flask 启动时传递的那个通常名称为 "app" 的对象

2.1.3 app class name

getattr(app, "__name__", app.__class__.__name__)

2.1.4 file path

mod = sys.modules.get(modname)
getattr(mod, "__file__", None)

2.2 private_bit

这个两个值为了保证安全

2.2.1 uuid node

uuid.getnode()

getnode 通过硬件地址来生成一个 48 bit 的整数

对于 unix 来说会从 dll(ctypes) ifconfig(ifconfig -av) arp(arp -an) lanscan(lanscan -ai) netstat (netstat -ia)中依次尝试生成

原理是通过各种方式获取到 server 的 mac 地址

如果都不能生成就会在 (0, 1<<48L) 间随机生成一个数然后与 0x010000000000L 进行一次或操作再返回

2.2.2 machine id

machine id 分为 boot 信息与 cgroup 信息

boot 信息会依次尝试读 /etc/machine-id 与 /proc/sys/kernel/random/boot_id 这两个文件

只要读取到了数据,第一部分就确定下来,都没有读到那么这部分数据就是空的

cgroup 信息会先读 /proc/self/cgroup

cgroup 信息就是 第一行以 "/"分割的后面的部分

f.readline().strip().rpartition(b"/")[2]

将两部分信息进行拼接就形成了 machine id

2.3 cookie name

将拿到的 6 个信息依次进行拼接然后在尾部再拼接一个 b"cookiesalt" 进行一次 md5 后取 16 进制的前 20 位

在前面加上 "__wzd" cookie 的名字就生成好了

2.4 pin num

将上一步生成的字符串(没有 __wzd)后拼接 b"pinsalt" 后做一次 md5

将获得的十六进制数转为十进制然后取前九位就是我们要的 PIN

3 PIN 的存储与检查

PIN 值存储到 cookie 中又经过了一点处理,总不能明文保存

"%s|%s" % (int(time.time()), hash_pin(self.pin))
def hash_pin(pin):
    if isinstance(pin, text_type):
        pin = pin.encode("utf-8", "replace")
    return hashlib.md5(pin + b"shittysalt").hexdigest()[:12]

这里的 pin 是带横线的 *-***-*** 的结构

在检查 cookie 时会分别对两部分检查

前一部分检查时间是否超过了 7 天,第二部分检查 pin 的正确性

Created: 2021-01-10 Sun 16:12

Emacs 25.2.2 (Org mode 8.2.10)

Validate