基于表单的网站身份验证权威指南

基于表单的网站身份验证权威指南

技术背景

在当今数字化时代,网站的安全性至关重要,而基于表单的身份验证是网站安全的重要组成部分。它涉及用户登录、密码存储、会话管理等多个方面,旨在确保只有授权用户能够访问网站的敏感信息。然而,实现安全可靠的表单身份验证并非易事,需要开发者了解各种安全漏洞和防范措施。

实现步骤

登录流程

  1. HTTPS的使用:除非连接已经通过SSL/TLS进行加密(即使用HTTPS),否则登录表单的值将以明文形式传输,这会使登录信息容易被窃听。因此,应始终使用HTTPS或其他基于证书的加密方案(如TLS)或经过验证的挑战 - 响应方案(如基于Diffie - Hellman的SRP)来保护登录过程。
  2. 避免自定义JavaScript加密/哈希:一些开发者可能会尝试在浏览器中实现自定义的哈希或加密方案,以避免在未加密的线路上传输明文登录信息。但这种方法通常是无效的,甚至可能成为安全漏洞,除非与强大的加密或经过验证的挑战 - 响应机制结合使用。
  3. CAPTCHA的使用:CAPTCHA旨在阻止自动化的字典/暴力破解攻击,但它有很多局限性,如对人类不友好、对机器人无效、可能在某些国家不合法等。建议仅在用户多次登录失败且节流延迟达到最大值时作为最后手段使用,例如使用Google的reCAPTCHA。
  4. 密码存储与验证:绝对不要在数据库中以明文形式存储密码。应使用密钥派生函数(KDF),如Argon2、bcrypt、scrypt或PBKDF2对密码进行哈希处理。在验证登录时,对输入的密码执行相同的哈希函数,并与数据库中存储的哈希值进行比较。同时,使用盐来保护哈希值免受彩虹表攻击。
  5. 会话数据管理:服务器验证登录和密码后,需要一种方式来记住浏览器已通过身份验证。这个信息应仅存储在服务器端的会话数据中。会话数据通过一个随机生成的字符串存储在过期的cookie中,并用于引用存储在服务器上的会话数据。确保会话cookie在发送到浏览器时设置了secureHttpOnly标志,以防止XSS攻击和网络嗅探攻击。

保持登录状态

  1. “记住我”功能的风险:持久登录cookie(“记住我”功能)是一个危险区域。对于了解如何安全处理它们的用户来说,它们与传统登录一样安全;但对于粗心的用户来说,这可能是一个巨大的安全风险。
  2. 实现持久登录cookie:如果决定实现持久登录cookie,不要将持久登录cookie(令牌)存储在数据库中,只存储其哈希值。同时,参考Paragon Initiative的相关文章,确保实现的各个环节正确。

使用安全问题

安全问题是一种安全反模式,不建议在身份验证方案中使用。因为大多数用户会选择容易被猜到的问题,如母亲的娘家姓或最喜欢的宠物,这使得账户容易受到攻击。

忘记密码功能

  1. 避免常见陷阱:不要将忘记的密码重置为自动生成的强密码,因为这样的密码很难记住。应让用户直接选择新密码。
  2. 哈希处理丢失密码代码:在数据库中始终对丢失密码代码/令牌进行哈希处理。当用户请求丢失密码代码时,将明文代码发送到用户的电子邮件地址,然后对其进行哈希处理并存储在数据库中,同时丢弃原始代码。
  3. 确保界面安全:确保输入“丢失密码代码”的界面至少与登录表单本身一样安全,例如生成较长的“丢失密码代码”,并考虑添加与登录表单相同的节流方案。

检查密码强度

计算密码的熵并应用阈值,结合字典和键盘布局分析,拒绝选择不佳的密码。可以参考NIST Special Publication 800 - 63的建议,同时利用Troy Hunt的Have I Been Pwned API检查用户密码是否在公共数据泄露中被泄露。

防止快速连续登录尝试

  1. 选择有效的方法:可以选择在N次失败尝试后显示CAPTCHA、锁定账户并要求电子邮件验证或设置登录节流(即设置尝试之间的时间延迟)。
  2. 最佳实践
    • 短时间延迟递增:如1次失败尝试无延迟,2次失败尝试延迟2秒,3次失败尝试延迟4秒,以此类推。
    • 中等长度延迟:如1 - 4次失败尝试无延迟,5次失败尝试延迟15 - 30分钟。
    • 结合两种方法:如1 - 4次失败尝试无延迟,5次以上失败尝试延迟20秒;或1次失败尝试延迟5秒,2次失败尝试延迟15秒,3次以上失败尝试延迟45秒。

分布式暴力破解攻击防范

记录系统范围内的失败登录次数,并使用网站的不良登录频率的运行平均值作为上限,对所有用户施加该限制。当失败尝试总数超过该限制时,激活系统范围的登录节流。

双因素身份验证和身份验证提供商

使用双因素身份验证(如通过电话、短信、应用程序或加密狗接收一次性代码)可以进一步保护登录。也可以将身份验证完全委托给单点登录服务,如Google、Twitter或Facebook提供的服务。

核心代码

以下是一个简单的Python Flask示例,展示如何使用bcrypt进行密码哈希和验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from flask import Flask, request
import bcrypt

app = Flask(__name__)

@app.route('/register', methods=['POST'])
def register():
password = request.form.get('password').encode('utf-8')
hashed = bcrypt.hashpw(password, bcrypt.gensalt())
# 这里可以将hashed存储到数据库
return 'User registered successfully'

@app.route('/login', methods=['POST'])
def login():
password = request.form.get('password').encode('utf-8')
# 从数据库中获取存储的哈希密码
stored_hash = get_stored_hash_from_db()
if bcrypt.checkpw(password, stored_hash):
return 'Login successful'
else:
return 'Login failed'

if __name__ == '__main__':
app.run(debug=True)

最佳实践

  1. 使用成熟的加密算法:如Argon2、bcrypt、scrypt或PBKDF2进行密码存储。
  2. 实施登录节流:防止暴力破解攻击。
  3. 定期更新安全措施:随着技术的发展,新的安全漏洞和攻击方法不断出现,因此需要定期更新身份验证系统。
  4. 使用双因素身份验证:增加账户的安全性。

常见问题

  1. 使用HTTP发送登录表单的风险:如果登录表单通过HTTP发送,登录信息将以明文形式传输,容易被窃听。攻击者可以获取用户的登录信息并用于非法目的。
  2. 自定义JavaScript加密/哈希的问题:这种方法通常无效,因为攻击者可以通过中间人攻击修改JavaScript代码,绕过加密/哈希过程。
  3. 安全问题的不安全性:大多数用户选择的安全问题容易被猜到,使得账户容易受到攻击。
  4. 忘记密码功能的常见陷阱:如重置为难以记住的密码、未对丢失密码代码进行哈希处理等,可能导致账户安全问题。

基于表单的网站身份验证权威指南
https://119291.xyz/posts/2025-04-17.form-based-website-authentication-guide/
作者
ww
发布于
2025年4月17日
许可协议