2026/9/20 3:29:12

Front-End-Checklist 实战:安全密码输入框(Secure Password Input Fields)完整实现指南

Front-End-Checklist 实战:安全密码输入框(Secure Password Input Fields)完整实现指南 Front-End-Checklist 实战安全密码输入框Secure Password Input Fields完整实现指南【免费下载链接】Front-End-Checklist The essential checklist for modern web development, for humans and AI agents项目地址: https://gitcode.com/gh_mirrors/fr/Front-End-Checklist密码输入框是登录、注册等核心表单的入口其实现质量直接决定账号安全与可访问性水平。本文以 Front-End-Checklist 仓库中security分类下的password-field-security规则为骨架系统讲解autocomplete属性语义、显示/隐藏切换、强度指示器、泄露密码检测k-anonymity与验证方法并给出可直接复制的 HTML / React / CSS 实现帮助你在生产级前端项目中落地一套安全 可用 无障碍的密码表单方案。规则概览优先级、难度与适用场景该规则在仓库中属于security安全分类同时覆盖html与accessibility可访问性两个维度子分类为forms元数据定义如下见 password-field-security.mdx 的 frontmatter 与 SKILL.md维度取值分类categoriessecurity、html、accessibility子分类subcategoryforms优先级priorityhigh高难度difficultyintermediate中级预估时间estimatedTime30 分钟一句话概括规则主旨取自规则文档原文Password fields implement security best practices including proper autocomplete, show/hide toggle, and strength indicators.即密码字段应实现安全最佳实践包括正确的 autocomplete、显示/隐藏切换和强度指示器。在 SKILL.md 的 Quick Reference 中还补充了四条快速检查项使用typepassword并搭配正确的autocomplete属性为密码可见性提供可访问的显示/隐藏切换展示带需求列表的密码强度指示器绝不明文存储或传输密码使用正确的 input 名称以支持密码管理器。为什么密码字段需要安全 可用双重要求规则文档 Why It Matters 明确指出合理实现的密码字段通过三点提升安全性与密码管理器协同工作正确的autocomplete属性让 1Password、LastPass、Bitwarden 等管理器能自动填充、自动保存并生成强密码帮助用户创建强密码通过强度指示器与即时校验引导用户使用更长的、组合更丰富的密码为所有用户提供可访问控制显示/隐藏切换、错误提示、键盘操作等无障碍细节让视障用户与键盘用户同样顺畅完成认证流程。从源码看绝不明文存储密码如何被自动化保障Never store or transmit passwords in plain text 不只是文档口号。仓库中的安全校验器 validate-security.ts 会在 CI/代码评审阶段扫描源码把硬编码密码当作critical 级漏洞拦截// packages/validators/src/validate-security.ts const SECRET_PATTERNS [ ... { pattern: /password\s*[:]\s*[][^]/i, type: Password }, ... ]该模式匹配password ...之类的赋值语句命中后进一步检查是否引用了process.env/import.meta.env若没有使用环境变量就会上报severity: critical的违规记录validateFile→checkHardcodedSecrets。同时它还扫描eval()、innerHTML、document.write、SQL 注入拼接等不安全操作并对process.env的使用强制要求提供 fallback。这意味着密码安全不仅是表单前端的职责也是全链路前端代码、服务端配置、环境变量的工程约束相关配置可对照仓库根目录下的 packages/auth/src/auth.ts认证服务使用BETTER_AUTH_SECRET等环境变量、并强制 HTTPS 协议与 packages/validators 包进一步了解。基础实现登录与注册表单的 HTML 骨架规则文档提供了两段开箱即用的 HTML 示例分别对应登录与注册场景。登录表单Login form!-- Login form -- form methodPOST action/login div label foremailEmail/label input typeemail idemail nameemail autocompleteemail required / /div div label forpasswordPassword/label input typepassword idpassword namepassword autocompletecurrent-password required minlength8 / /div button typesubmitSign In/button /form要点拆解typepassword输入内容以掩码显示避免旁观者窥屏autocompletecurrent-password告知浏览器/密码管理器这是既有账号的密码用于自动填充minlength8HTML 原生最小长度校验登录场景下限可适当放宽注册场景建议 12label与for严格配对保证可访问性与点击聚焦。注册表单Registration form!-- Registration form -- form methodPOST action/register div label foremailEmail/label input typeemail idemail nameemail autocompleteemail required / /div div label fornew-passwordCreate Password/label input typepassword idnew-password namepassword autocompletenew-password required minlength12 aria-describedbypassword-requirements / p idpassword-requirements At least 12 characters with uppercase, lowercase, and numbers. /p /div button typesubmitCreate Account/button /form注册场景的三个关键差异autocompletenew-password告诉密码管理器这是新密码可触发生成强密码建议minlength12注册场景强制更长密码aria-describedbypassword-requirements将密码需求说明与输入框关联屏幕阅读器聚焦时即会播报需求。Autocomplete 属性语义表务必对照使用autocomplete是密码字段与密码管理器协作的通信协议规则文档给出以下对照表场景Scenario属性Attribute用途Purpose登录表单autocompletecurrent-password填充已有密码注册/改密autocompletenew-password建议/生成强密码用户名autocompleteusername与密码关联邮箱登录autocompleteemail基于邮箱的认证错误使用例如登录表单写成new-password会导致密码管理器反复提示保存新密码或无法自动填充直接影响转化率与用户体验反之注册表单若误用current-password则可能让浏览器在用户尚未有账号时就尝试填充旧凭据。两个取值必须与表单语义严格一致。React 实现带显示/隐藏切换的密码输入组件规则文档提供了完整的 React 组件方案。下面代码是仓库中完整可运行版本已补全import与 SVG 图标组件在 React 18 的客户端组件use client中使用useId生成唯一 ID避免多实例冲突import { useState, useId } from react interface PasswordFieldProps { label: string name: string autocomplete: current-password | new-password value: string onChange: (value: string) void error?: string minLength?: number } export function PasswordField({ label, name, autocomplete, value, onChange, error, minLength 8, }: PasswordFieldProps) { const [showPassword, setShowPassword] useState(false) const inputId useId() const errorId useId() return ( div classNamepassword-field label htmlFor{inputId} classNamepassword-label {label} /label div classNamepassword-input-wrapper input type{showPassword ? text : password} id{inputId} name{name} value{value} onChange{(e) onChange(e.target.value)} autoComplete{autocomplete} minLength{minLength} required aria-invalid{error ? true : false} aria-describedby{error ? errorId : undefined} classNamepassword-input / button typebutton onClick{() setShowPassword(!showPassword)} aria-label{showPassword ? Hide password : Show password} aria-pressed{showPassword} classNamepassword-toggle {showPassword ? ( EyeOffIcon aria-hiddentrue / ) : ( EyeIcon aria-hiddentrue / )} /button /div {error ( p id{errorId} rolealert classNamepassword-error {error} /p )} /div ) } function EyeIcon(props: React.SVGPropsSVGSVGElement) { return ( svg viewBox0 0 24 24 width{20} height{20} {...props} path fillcurrentColor dM12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z / /svg ) } function EyeOffIcon(props: React.SVGPropsSVGSVGElement) { return ( svg viewBox0 0 24 24 width{20} height{20} {...props} path fillcurrentColor dM12 7c2.76 0 5 2.24 5 5 0 .65-.13 1.26-.36 1.83l2.92 2.92c1.51-1.26 2.7-2.89 3.43-4.75-1.73-4.39-6-7.5-11-7.5-1.4 0-2.74.25-3.98.7l2.16 2.16C10.74 7.13 11.35 7 12 7zM2 4.27l2.28 2.28.46.46C3.08 8.3 1.78 10.02 1 12c1.73 4.39 6 7.5 11 7.5 1.55 0 3.03-.3 4.38-.84l.42.42L19.73 22 21 20.73 3.27 3 2 4.27zM7.53 9.8l1.55 1.55c-.05.21-.08.43-.08.65 0 1.66 1.34 3 3 3 .22 0 .44-.03.65-.08l1.55 1.55c-.67.33-1.41.53-2.2.53-2.76 0-5-2.24-5-5 0-.79.2-1.53.53-2.2zm4.31-.78l3.15 3.15.02-.16c0-1.66-1.34-3-3-3l-.17.01z / /svg ) }组件设计中的无障碍要点也是规则 Verification 部分的要求切换按钮typebutton避免误触发表单提交aria-label随状态切换为 Show password / Hide passwordaria-pressed同步播报当前按压状态输入框aria-invalid{error ? true : false}标记校验失败aria-describedby指向错误提示切换为typetext时仍保持相同语义属性错误提示rolealert让屏幕阅读器在出现错误时立即播报useId保证 ID 全局唯一规则要求Check focus management on error state键盘操作切换按钮原生支持 Enter 与 Space 触发自动化检查的第一项。密码强度指示器需求清单 实时评分规则文档提供了一套轻量、无第三方依赖的强度计算方案先定义 5 项需求长度、小写、大写、数字、特殊字符统计满足项数后映射为 0–4 分。interface PasswordStrengthProps { password: string } interface StrengthResult { score: 0 | 1 | 2 | 3 | 4 label: string requirements: { met: boolean text: string }[] } function calculateStrength(password: string): StrengthResult { const requirements [ { met: password.length 12, text: At least 12 characters }, { met: /[a-z]/.test(password), text: One lowercase letter }, { met: /[A-Z]/.test(password), text: One uppercase letter }, { met: /[0-9]/.test(password), text: One number }, { met: /[^a-zA-Z0-9]/.test(password), text: One special character }, ] const metCount requirements.filter((r) r.met).length const scoreMap: Recordnumber, { score: StrengthResult[score]; label: string } { 0: { score: 0, label: Very weak }, 1: { score: 1, label: Weak }, 2: { score: 1, label: Weak }, 3: { score: 2, label: Fair }, 4: { score: 3, label: Good }, 5: { score: 4, label: Strong }, } return { ...scoreMap[metCount], requirements, } } export function PasswordStrength({ password }: PasswordStrengthProps) { const strength calculateStrength(password) if (!password) return null return ( div classNamepassword-strength aria-livepolite div classNamestrength-bar div className{strength-fill strength-${strength.score}} style{{ width: ${(strength.score 1) * 20}% }} / /div span classNamestrength-label{strength.label}/span ul classNamestrength-requirements {strength.requirements.map((req, index) ( li key{index} className{req.met ? met : unmet} span aria-hiddentrue{req.met ? ✓ : ○}/span span className{req.met ? sr-only : undefined} {req.met ? Complete: : Incomplete: } /span {req.text} /li ))} /ul /div ) }实现要点说明评分映射满足 0 项 → 0 分Very weak1–2 项 → 1 分Weak3 项 → 2 分Fair4 项 → 3 分Good5 项 → 4 分Strong进度条宽度(score 1) * 20%最小 20% 保证弱密码也有可见反馈实时性aria-livepolite让屏幕阅读器在强度变化时温和播报对应手册检查项 Verify strength indicator updates in real-time可读性已满足/未满足项用sr-only文本Complete: / Incomplete: 为读屏用户补充语义视觉符号✓/○则标记aria-hidden避免重复朗读。完整注册表单组件组装与客户端校验将以上两个组件组合成完整的注册表单use client客户端组件在提交前完成长度与二次确认校验use client import { useState } from react import { PasswordField } from ./password-field import { PasswordStrength } from ./password-strength export function RegistrationForm() { const [email, setEmail] useState() const [password, setPassword] useState() const [confirmPassword, setConfirmPassword] useState() const [errors, setErrors] useStateRecordstring, string({}) const handleSubmit async (e: React.FormEvent) { e.preventDefault() const newErrors: Recordstring, string {} if (password.length 12) { newErrors.password Password must be at least 12 characters } if (password ! confirmPassword) { newErrors.confirmPassword Passwords do not match } if (Object.keys(newErrors).length 0) { setErrors(newErrors) return } // Submit form // await register({ email, password }) } return ( form onSubmit{handleSubmit} classNameregistration-form div classNameform-group label htmlForemailEmail/label input typeemail idemail nameemail value{email} onChange{(e) setEmail(e.target.value)} autoCompleteemail required / /div div classNameform-group PasswordField labelCreate Password namepassword autocompletenew-password value{password} onChange{setPassword} error{errors.password} minLength{12} / PasswordStrength password{password} / /div div classNameform-group PasswordField labelConfirm Password nameconfirmPassword autocompletenew-password value{confirmPassword} onChange{setConfirmPassword} error{errors.confirmPassword} minLength{12} / /div button typesubmit classNamesubmit-button Create Account /button /form ) }设计要点确认密码字段同样使用autocompletenew-password避免浏览器把两个字段都误判为可填充项客户端校验仅是第一道防线服务端必须再次校验示例中以注释await register({ email, password })标出提交点校验失败时通过errors状态驱动PasswordField的error属性错误信息自动接入rolealert与aria-invalid。样式实现状态可见的密码输入视觉方案规则文档同时给出了配套 CSS覆盖输入框、切换按钮、错误态、焦点态与强度条.password-field { margin-bottom: 1rem; } .password-label { display: block; margin-bottom: 0.5rem; font-weight: 500; } .password-input-wrapper { position: relative; display: flex; align-items: center; } .password-input { width: 100%; padding: 0.75rem 3rem 0.75rem 1rem; border: 1px solid #ddd; border-radius: 4px; font-size: 1rem; } .password-input:focus { outline: none; border-color: #0066cc; box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.2); } .password-input[aria-invalidtrue] { border-color: #dc2626; } .password-toggle { position: absolute; right: 0.75rem; padding: 0.25rem; background: none; border: none; color: #666; cursor: pointer; } .password-toggle:hover { color: #333; } .password-toggle:focus-visible { outline: 2px solid #0066cc; outline-offset: 2px; border-radius: 2px; } .password-error { margin-top: 0.5rem; color: #dc2626; font-size: 0.875rem; } /* Strength indicator */ .password-strength { margin-top: 0.75rem; } .strength-bar { height: 4px; background: #e5e5e5; border-radius: 2px; overflow: hidden; } .strength-fill { height: 100%; transition: width 0.3s, background-color 0.3s; } .strength-0 { background: #dc2626; } .strength-1 { background: #f97316; } .strength-2 { background: #eab308; } .strength-3 { background: #84cc16; } .strength-4 { background: #22c55e; } .strength-label { display: block; margin-top: 0.25rem; font-size: 0.75rem; color: #666; } .strength-requirements { list-style: none; padding: 0; margin: 0.5rem 0 0; font-size: 0.875rem; } .strength-requirements li { display: flex; align-items: center; gap: 0.5rem; padding: 0.25rem 0; } .strength-requirements .met { color: #22c55e; } .strength-requirements .unmet { color: #666; } .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); border: 0; }样式设计亮点焦点可见性focus用高对比边框 外发光focus-visible为切换按钮提供键盘专属焦点环兼顾鼠标与键盘体验错误态通过属性选择器[aria-invalidtrue]驱动红色边框样式与无障碍状态单一数据源避免 class 与 aria 状态不同步强度色阶红0→ 橙1→ 黄2→ 黄绿3→ 绿4并带 0.3s 宽度/颜色过渡.sr-only标准视觉隐藏但读屏可读工具类用于强度需求项的文本前缀。服务端与传输层安全清单规则文档用一张表格总结了密码安全的全栈最佳实践实践Practice实现Implementation绝不记录密码从日志、监控中排除密码字段密码哈希存储使用 bcrypt、Argon2 或 scrypt强制最小长度至少 12 个字符泄露密码检查使用 Have I Been Pwned API登录限流防止暴力破解攻击全程 HTTPS加密传输链路仓库中的认证实现可佐证传输层约束在 packages/auth/src/auth.ts 中better-auth 的baseURL.protocol在生产环境强制为httpsprocess.env.NODE_ENV development ? http : https且allowedHosts白名单限定了可信任域名BETTER_AUTH_SECRET、GITHUB_CLIENT_SECRET等敏感配置一律从环境变量读取配合 validate-security.ts 的硬编码扫描形成双保险。前端表单只是密码安全链路的起点服务端哈希、限流与传输加密缺一不可。泄露密码检测基于 k-anonymity 的 Breach Check规则文档给出了一个可在浏览器端安全运行的泄露密码检查函数。其原理是k-anonymityk 匿名绝不把完整密码或完整哈希发送给第三方只发送 SHA-1 哈希的前 5 个十六进制字符由服务端返回所有以该前缀开头的哈希后缀列表再在本地比对。// Check password against known breaches (k-anonymity safe) async function checkPasswordBreach(password: string): Promiseboolean { const encoder new TextEncoder() const data encoder.encode(password) const hashBuffer await crypto.subtle.digest(SHA-1, data) const hashArray Array.from(new Uint8Array(hashBuffer)) const hashHex hashArray.map(b b.toString(16).padStart(2, 0)).join().toUpperCase() const prefix hashHex.slice(0, 5) const suffix hashHex.slice(5) // Only send first 5 chars (k-anonymity) const response await fetch(https://api.pwnedpasswords.com/range/${prefix}) const text await response.text() // Check if suffix is in response return text.includes(suffix) }实现要点用 Web Crypto APIcrypto.subtle.digest(SHA-1, ...)在本地计算密码的 SHA-1 哈希并转大写截取前 5 个字符prefix作为查询 key其余作为suffix只把prefix发送给api.pwnedpasswords.com/range/{prefix}即使请求被截获攻击者也无法逆向出密码返回的哈希后缀列表包含所有匹配该前缀的泄露密码本地text.includes(suffix)即可判断命中。该检查适合在注册/改密时作为软性阻断命中则要求更换密码且应在HTTPS环境下调用注意这里仅演示前端流程高安全场景更推荐在服务端完成检查以避免在客户端处理原始密码。例外情况Exceptions规则文档明确列出三条例外判定标准用于界定何时可以放宽密码控件强度只有在业务需求与补偿性控制被显式记录在案时才可接受较弱的表单控件如果流程本身已处于传输不安全、不可访问或外部嵌入等改变威胁模型的状态应先修复更严重的问题对应同分类的 form-https 等规则演示、沙盒或刻意受限的流程中误报很常见但仍应限制范围并明确标注。验证与测试自动化 手动检查清单规则文档的 Verification 部分给出了可执行的验收标准自动化检查Automated Checks使用键盘Enter 和 Space测试显示/隐藏切换按钮测试带校验错误的表单提交流程错误提示出现、焦点管理正确在1Password、LastPass、Bitwarden等主流密码管理器中实测自动填充。手动检查Manual Checks验证autocomplete属性在各密码管理器中正常工作确认屏幕阅读器能播报切换按钮的状态显示/隐藏验证强度指示器随输入实时更新检查错误状态下的焦点管理聚焦到出错字段、读屏可感知错误。这些检查项可与仓库中 e2e 与组件测试基础设施结合落地参见 apps/e2e 与 apps/web/components 目录下的测试组织方式。关联规则与进一步阅读在仓库规则体系中password-field-security属于security/forms领域其relatedRulesfrontmatter 声明建议与以下规则一同评审form-captcha表单防机器人两者常在认证流程中一并出现form-https表单提交链路必须 HTTPS是密码传输安全的前提search-input 与 input-image-alt同属security/forms的相邻评审项。如需在 AI Agent / 代码评审场景使用本规则可参考配套的 SKILL.md它把规则拆解为 Check检查、Fix修复、Explain解释、Code Review评审四个动作其aiContext字段明确在评审 headers、forms、cookies 或第三方集成时使用本规则并在类生产环境中验证实际的浏览器与 HTTP 行为。完整实现细节与代码示例即本文所依据的 references/rule.md规则内容源文件位于 packages/content/rules/en/security/password-field-security.mdx。小结安全密码输入框 正确的autocomplete语义current-password/new-password 可访问的显示/隐藏切换aria-label、aria-pressed 实时强度反馈aria-live 泄露密码检测k-anonymity 服务端哈希与 HTTPS 兜底。按本规则文档与仓库源码落地后你的登录/注册表单将同时通过安全、可访问性与密码管理器兼容性三重检查。【免费下载链接】Front-End-Checklist The essential checklist for modern web development, for humans and AI agents项目地址: https://gitcode.com/gh_mirrors/fr/Front-End-Checklist创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考