← 精品代码功能 · 可复用实现库

精品功能 11:HMAC 签名链接 + 局域网 IPv4 探测

并自动找出"手机真正能连上的那个局域网 IP"。

把 token 放进 URL 又会写进日志——两难。

  1. 电脑上可能有 VMware/虚拟网卡等一堆假 IP,得挑出手机连通的那个。

核心实现

HMAC 签名 URL(security.py 第 41-67 行):

def _file_signature(filename: str, expires: int) -> str:
    payload = f"{filename}:{expires}".encode("utf-8")
    return hmac.new(settings.token.encode("utf-8"), payload, hashlib.sha256).hexdigest()[:24]

def signed_file_url(filename: str, ttl_seconds: int = SIGNED_URL_TTL) -> str:
    """给静态文件签一个有时效的链接。
    为什么不用 token:`<img>` 发出的请求带不了 Authorization header,走 token 校验必然 401。
    而把 token 塞进查询参数会写进访问日志 —— 不行。
    折中是签名:用 token 当 HMAC 密钥,只有拿到 token 的人能生成,且带过期时间。"""
    expires = int(time.time()) + ttl_seconds
    return f"/api/screenshot/{filename}?exp={expires}&sig={_file_signature(filename, expires)}"

def verify_signed_file(filename: str, exp: int, sig: str) -> bool:
    ...
    if expires < time.time():
        return False
    return hmac.compare_digest(_file_signature(filename, expires), sig)

局域网 IP 探测(config.py 第 59-98 行,节选):

def lan_candidates() -> list[tuple[str, str]]:
    """列出真实网卡上的私有 IPv4,排除虚拟网卡(VMware/Radmin 的地址手机连不上)。"""
    for name, addrs in psutil.net_if_addrs().items():
        low = name.lower()
        is_tailscale = TAILSCALE_NIC_HINT in low        # Tailscale 是有用的虚拟网卡,豁免
        if not is_tailscale and any(hint in low for hint in _VIRTUAL_NIC_HINTS):
            continue
        ...
        usable = (ip.is_private and not ip.is_loopback and not ip.is_link_local) or (ip in TAILSCALE_NETWORK)
        ...
        score = 0 if any(k in low for k in ("wlan", "wi-fi", "wireless", "无线")) else 1
        if not str(ip).startswith("192.168."):
            score += 1
        if is_tailscale:
            score += 5          # 局域网优先,Tailscale 排后面
        found.append((score, str(ip), name))
    found.sort()
    return [(ip, name) for _, ip, name in found]

配对二维码的隐私巧思(pair.py 第 1-24 行):

"""为什么 token 放在 # 后面而不是查询参数:
- URL fragment 不会随 HTTP 请求发给服务端,也就不会写进访问日志
- 前端取到后立刻用 replaceState 抹掉,浏览器历史里也不留
- 代价:这个二维码等同于 token 本身,截图别乱发
"""
return f"http://{host}:{settings.port}/#token={settings.token}"

设计亮点

  1. 签名而非传 token:HMAC(密钥, 文件名:过期时间),链接里没有 token,泄露只影响一张图
  2. 有效期 600 秒:够加载图片,不至于长期有效
  3. <img> 无法带 header 时的通用解法——这就是云存储"预签名 URL"的原理
  4. 网卡打分排序:无线优先、192.168.* 优先、Tailscale 靠后——把现实经验编码成规则
  5. Tailscale 双重豁免:既不是"虚拟网卡黑名单"成员,又要处理

is_private 对 100.64.0.0/10 返回 False 的坑(注释里写明了)

  1. token 放 fragment:不发给服务器、不进日志、前端用完即抹

可复用性评估

开源化建议

对照开源

相关课程

第 16 课(安全设计)