访问控制

企业需求 🔐

一个周一的上午,我收到一封企业客户的邮件:

“你好,我们的内部文档链接,不想让外部人员访问。能不能加个密码?”

另外,有些链接只想让公司内部的人访问,可以按IP限制吗?

我意识到,短链接服务已经不能只是简单的”点击即跳转”了。企业用户有强烈的安全需求——他们需要访问控制

访问控制(Access Control)是保护资源不被未授权用户访问的机制。在短链接场景中,我需要实现多层防护:

  • 密码保护:只有知道密码的人才能访问
  • IP白名单:只允许特定IP地址访问
  • 访问次数限制:只允许前N个人访问
  • 时间窗口限制:只在特定时间段内可访问

让我逐一实现这些功能。

当前架构
第 6 版:安全治理平台
短链公开传播后,审核、封禁、申诉和缓存刷新必须形成闭环。
创建
URL 审核
用户风控
访问
风险拦截
封禁页
302 跳转
治理
人工复核
申诉
审计日志
数据
链接状态
黑名单
风险证据
Url Mapping
安全治理字段
secure
字段类型说明
idBIGINT全局 ID
short_codeVARCHAR(16)短码,唯一索引
long_urlVARCHAR(2048)原始 URL
statusVARCHAR(20)跳转状态
risk_levelVARCHAR(20)风险等级
audit_statusVARCHAR(20)审核状态
blocked_reasonTEXT封禁原因
访问控制上线后的治理指标
secure
拦截量
3.4k/h
恶意链接和异常来源
误杀申诉
7
进入人工复核队列
缓存刷新
< 10s
封禁后尽快影响跳转

密码保护 🔑

为什么需要密码保护?

密码保护是最基础也是最常用的访问控制方式。企业客户用它来保护:

  • 内部文档链接
  • 限时优惠链接
  • 私密分享的文件
  • 测试环境的入口

我面临的第一个问题是:如何安全地存储密码?

数据库设计

我需要在 urls 表中添加密码相关字段:

数据设计要点

  • 这是一次表结构演进:随着链接管理能力增加,把新状态、新时间点或新归属关系补进数据模型。

密码哈希:为什么不用 MD5?

在实现密码存储时,我需要考虑安全性。很多人会用 MD5 或 SHA1 来哈希密码:

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

为什么不这样做?

MD5 和 SHA1 是快速哈希算法,设计初衷是快速计算校验和,而非安全存储密码。攻击者可以:

  1. 彩虹表攻击:预先计算常见密码的哈希值(如 “123456”、“password”),然后用查表方式破解
  2. 暴力破解:因为计算速度快,一秒钟可以尝试数十亿次

使用 bcrypt:正确的做法

我选择了 bcrypt——专门为密码哈希设计的算法:

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

bcrypt 的优势:

  1. 自动加盐:每次生成的哈希都不同,防止彩虹表攻击
  2. 计算成本可调:通过 work factor 参数控制计算时间,增加暴力破解成本
  3. 抗GPU攻击:算法设计使得GPU并行计算优势不明显

创建带密码的短链接

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

访问流程:密码验证

当用户访问带密码的短链接时,我需要:

  1. 检查链接是否设置了密码
  2. 检查用户是否已经通过验证(Session)
  3. 如果未验证,显示密码输入页面
  4. 验证密码正确性,防止暴力破解

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

密码输入页面

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

IP 白名单 🌐

需求场景

密码保护可以防止未授权访问,但企业客户有更高的安全需求:

“我们的内部链接,只允许公司网络访问。能不能按IP限制?”

IP 白名单是更严格的访问控制方式,常用于:

  • 内网资源保护:只允许公司内网IP访问
  • 地域限制:只允许特定国家/地区的IP访问
  • API访问控制:只允许合作伙伴服务器的IP调用

IP 地址的挑战

实现 IP 白名单有几个技术难点:

  1. 获取真实IP:需要处理代理、负载均衡器的情况
  2. IP范围匹配:单个IP不够,需要支持CIDR格式(如 192.168.1.0/24
  3. IPv4和IPv6兼容:需要同时支持两种协议

获取真实 IP

在 Flask 中,直接使用 request.remote_addr 可能不准确:

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

正确做法是检查 X-Forwarded-For 头:

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

CIDR 匹配算法

企业客户不会只允许单个IP,而是整个IP段。CIDR(无类别域间路由)是标准表示法:

  • 192.168.1.0/24:表示 192.168.1.0 到 192.168.1.255(256个IP)
  • 10.0.0.0/8:表示 10.0.0.0 到 10.255.255.255(1600万个IP)

我需要实现CIDR匹配算法:

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

数据库设计

数据设计要点

  • 核心是在 urls 里保存业务事实,而不是把规则散落在应用逻辑里。
  • 这是一次表结构演进:随着链接管理能力增加,把新状态、新时间点或新归属关系补进数据模型。
  • 索引服务于高频查询,重点关注 AUTOINCREMENTidx_ip_logs_short_codeidx_ip_logs_time
  • 关键字段包括 idshort_codeip_addressaccess_timeallowed,它们决定了后续查询和管理能力。

IP 白名单实现

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

创建带IP限制的短链接

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

IP 访问统计

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

访问次数限制 🎫

需求场景

一个营销客户找到我:

“我们要发限时优惠券,只给前100名用户。能不能实现’前100人可以访问,其他人不行’?”

这就是访问次数限制的需求:

  • 限量抢购:只允许前N人访问
  • 试用期限制:免费版只能访问100次
  • 配额管理:防止资源被过度消耗

数据库设计

我在密码保护部分已经添加了相关字段:

数据设计要点

  • 这是一次表结构演进:随着链接管理能力增加,把新状态、新时间点或新归属关系补进数据模型。

访问次数限制实现

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

限制页面模板

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

创建限次访问的短链接

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

实时访问计数查询

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

时间窗口限制 ⏰

需求场景

又有一个企业客户提出需求:

“我们的内部链接,只在工作时间可以访问,下班后不行。”

这就是时间窗口限制

  • 工作时间限制:只在周一到周五的9:00-18:00可访问
  • 活动时间限制:限时促销,只在一个日期范围内有效
  • 试用期限制:新用户注册后7天内可访问

数据库设计

数据设计要点

  • 这是一次表结构演进:随着链接管理能力增加,把新状态、新时间点或新归属关系补进数据模型。

时间范围限制

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

每周时间段限制

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

创建时间限制的短链接

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

完整的时间检查流程

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

访问控制方案对比 📊

我已经实现了四种访问控制方案,每种都有其适用场景:

方案实现难度安全性性能影响适用场景
密码保护⭐⭐ 中等⭐⭐⭐ 中等⭐⭐ 低内部文档、私密分享
IP白名单⭐⭐ 中等⭐⭐⭐⭐ 高⭐⭐ 低企业内网、地域限制
访问次数限制⭐ 简单⭐⭐ 低⭐ 低限量抢购、试用版
时间窗口限制⭐⭐⭐ 较难⭐⭐ 低⭐ 低限时活动、工作时间

组合使用

这些方案可以组合使用:

落地思路

  • 这里省略具体语法,只保留设计层面的职责边界。
  • 读这段时重点看:输入是什么、系统做哪些判断、状态如何变化、失败时如何兜底。

性能考虑

访问控制会增加响应延迟,我做了优化:

  1. 数据库索引:在 short_code 上建索引,快速查询
  2. 缓存Session:密码验证后缓存,避免重复查询
  3. IP匹配优化:使用高效的CIDR匹配算法
  4. 异步日志:访问日志异步写入,不影响主流程

下一步:批量管理 ⏭️

单个链接的访问控制已经实现了。但企业客户又提出新问题:

“我们有1000个内部链接,能不能批量设置IP白名单?” “每个月都要更新密码,能不能批量操作?”

单个链接管理已经不够了,我需要实现批量管理功能。

下一节,我会实现:

  • 批量设置访问控制
  • 批量更新密码
  • 批量导入导出
  • 权限组管理

(继续下一节:批量操作)