返回

密码验证表单:如何强制包含特殊字符 (HTML & JS)

javascript

为密码验证表单添加特殊字符约束

密码的安全性是应用程序中至关重要的部分。确保用户创建高强度密码的一种常见方法是实施密码复杂性规则。规则之一可能涉及要求密码包含至少一个特殊字符。本篇文章深入探讨了如何向密码验证表单添加这种特殊字符约束,并通过JavaScript代码与HTML pattern属性结合使用的方式,来实现对密码复杂度的有效控制。

理解问题:现有校验逻辑的局限性

在大多数情况下, 开发者在实现密码强度检查时,通常会遇到这样的困境:验证代码会“检查”是否存在特殊字符,并相应地更新界面,比如改变提示文字颜色为绿色,但这仅仅表示密码 包含 特殊字符,并没有真正 强制要求 必须包含一个特殊字符。 使用类似 (?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,} 的HTML pattern属性,配合JavaScript做验证是一个通用的办法, 但上面的pattern 只关注数字、小写字母、大写字母和长度要求。它仅仅 确保存在 这些字符,而不是强制要求必须存在,这就让很多密码验证器存在绕过的风险,也直接导致用户有可能创建出安全强度不足的密码。 HTML pattern 和 JS 的结合使用才是完整且安全的解决方案。

解决方案一: 使用HTML pattern强制执行特殊字符规则

HTML pattern 属性本身非常强大,使用正则表达式可以直接实现强制密码规则。我们需要调整正则表达式以包含至少一个特殊字符的要求。

原理:

  • (?=.*[a-z]): 断言,必须包含至少一个小写字母。
  • (?=.*[A-Z]): 断言,必须包含至少一个大写字母。
  • (?=.*\d): 断言,必须包含至少一个数字。
  • (?=.*[~!@#$%^&*()_-+={}[]|\;:'"<>,.?/])`:断言,必须包含至少一个特殊字符(包括常见的符号,以及空格符)。
  • .{8,}: 要求密码长度至少为 8 个字符。

实现步骤:

  1. 将HTML表单中的密码输入字段的pattern 属性修改为:
    (?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[~!@#$%^&*()_-+={}[]|\;:'"<>,.?/]).{8,}`

代码示例:

<form>
    <input type="password" name="password" placeholder="Password" id="password" required
           minlength="8" maxlength="32"
           pattern="(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[~`!@#$%^&*()_\-+={}[\]|\\;:'&quot;<>,.?\/]).{8,}">
</form>

这样改动后,只有当输入密码符合所有四个条件(包括特殊字符),才会认为该密码为合法,才能提交表单,HTML 的 pattern 属性提供了一种强制措施。
*安全提示: 即使在HTML 端进行了规则设置,在后端(服务端)仍然需要执行类似的验证逻辑,以防止恶意提交。客户端验证的目的只是为用户提供实时的反馈。

解决方案二:JavaScript 与HTML 协同验证

单纯的HTML pattern属性并不能提供细粒度的验证反馈。这时,结合 JavaScript 来提供更友好的用户体验。JavaScript 可以实时检查密码是否符合规则,并在用户输入时显示反馈。

原理:

  1. 事件监听: 使用 onkeyup 事件,每次用户在密码字段中输入或删除字符时,都执行验证代码。
  2. 正则表达式匹配: 对不同类型的字符使用单独的正则表达式,检查是否满足每个条件。例如,使用 /[a-z]/g 检查小写字母。
  3. DOM操作: 通过改变样式类 (invalid/valid),显示验证结果。 例如如果包含特殊字符,移除 invalid 类, 添加 valid 类;否则反之。

实现步骤:

  1. 在JS代码中增加针对特殊字符的正则表达式匹配:
 var specialcharacters = /[~`!@#$%^&*()_\-+={}[\]|\\;:'"<>,.?\/]/g;
    if(myInput.value.match(specialcharacters)) {
        special.classList.remove("invalid");
        special.classList.add("valid");
    } else {
        special.classList.remove("valid");
        special.classList.add("invalid");
    }

同时注意把HTML中密码输入框的 pattern 修改为
(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[~!@#$%^&*()_-+={}[]|\;:'"<>,.?/]).{8,}` 与JS代码保持规则同步。

完整示例:

<style>
  #message {
    display:none;
    background: #EFEFEF;
    color: #000;
    position: relative;
    margin-top: 0px;
    text-align:left;
    width:100%;
  }
  #message p {
    padding: 2px 35px 2px 60px;
    font-size: 18px;
  }
  .valid {
    color: green;
  }
  .valid:before {
    position: relative;
    left: -20px;
    content: "✔";
  }
  .invalid {
    color: red;
  }
  .invalid:before {
    position: relative;
    left: -20px;
    content: "✖";
    color: red;
  }
</style>


<form>
    <input type="password" name="password" placeholder="Password" id="password" required
           minlength="8" maxlength="32"
           pattern="(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[~`!@#$%^&*()_\-+={}[\]|\\;:'&quot;<>,.?\/]).{8,}">
</form>

<div id="message">
    <div style="padding-top:8px;"></div>
    <h2 style="padding-left:40px;font-size:19px;text-decoration:underline;font-weight:650;color:#333;">密码要求:</h2>
    <p id="letter" class="invalid"><span style="font-weight:600;font-size:17px;">一个 小写字母</span></p>
    <p id="capital" class="invalid"><span style="font-weight:600;font-size:17px;">一个 大写字母</span></p>
    <p id="number" class="invalid"><span style="font-weight:600;font-size:17px;">一个 数字</span></p>
     <p id="special" class="invalid"><span style="font-weight:600;font-size:17px;">一个 特殊字符</span></p>
    <p id="length" class="invalid"><span style="font-weight:600;font-size:17px;">至少 8 个字符</span></p>
</div>

<script>
  var myInput = document.getElementById("password");
  var letter = document.getElementById("letter");
  var capital = document.getElementById("capital");
  var number = document.getElementById("number");
  var length = document.getElementById("length");
   var special = document.getElementById("special");

  myInput.onfocus = function() {
    document.getElementById("message").style.display = "block";
  }

  myInput.onblur = function() {
    document.getElementById("message").style.display = "none";
  }

  myInput.onkeyup = function() {
    var lowerCaseLetters = /[a-z]/g;
    if(myInput.value.match(lowerCaseLetters)) {
      letter.classList.remove("invalid");
      letter.classList.add("valid");
    } else {
      letter.classList.remove("valid");
      letter.classList.add("invalid");
    }

    var upperCaseLetters = /[A-Z]/g;
    if(myInput.value.match(upperCaseLetters)) {
      capital.classList.remove("invalid");
      capital.classList.add("valid");
    } else {
      capital.classList.remove("valid");
      capital.classList.add("invalid");
    }

    var numbers = /[0-9]/g;
    if(myInput.value.match(numbers)) {
      number.classList.remove("invalid");
      number.classList.add("valid");
    } else {
      number.classList.remove("valid");
      number.classList.add("invalid");
    }
    if(myInput.value.length >= 8) {
      length.classList.remove("invalid");
      length.classList.add("valid");
    } else {
      length.classList.remove("valid");
      length.classList.add("invalid");
    }

       var specialcharacters = /[~`!@#$%^&*()_\-+={}[\]|\\;:'"<>,.?\/]/g;
    if(myInput.value.match(specialcharacters)) {
      special.classList.remove("invalid");
      special.classList.add("valid");
    } else {
       special.classList.remove("valid");
      special.classList.add("invalid");
    }

  }
</script>

  • 安全提示: 注意,为了满足项目需要,可以根据需要修改特殊字符的范围; 另外,验证规则可以在服务端也强制执行,不应仅仅依赖于客户端验证,以提升安全性。

通过 HTML pattern 属性强制实施复杂密码规则,并使用JavaScript提供实时用户反馈,能够显著提高密码验证过程的安全性和用户体验。 使用这些策略能够有效地减少不安全密码的出现,增强应用程序整体的安全性。