跟帳號有關的系統,不管是網頁、手機App、或是單機桌面應用程式都可能遇上密碼,有些簡單點的會限制使用者的密碼文字長度要多長,複雜一點的還會限制密碼至少要包含某些內容,已達到足夠的複雜強度。本文提供Java、JavaScript與TypeScript的範例,提供檢測密碼是否符合強度的程式碼。

本頁文章顯示的程式碼範例,可隨意複製、修改、合併使用在任何程式碼中,不強制要求保留著作權聲明,且原作者不提供任何責任擔保。

強度說明

先決條件,達到密碼文字達到指定長度,沒有達成此條件直接返回不符合。再來檢查密碼內的文字是否包含以下四個項目,至少達成N個:

  • 包含英文小寫
  • 包含英文大寫
  • 包含阿拉伯數字
  • 包含特殊字元

同時提供前端與後端的檢查是為了增加使用者體驗,前端的使用者輸入密碼後即可透過JavaScript立刻檢查密碼強度,如果不符合就可以及時告知使用者需要加強密碼,不必等使用者Submit資料後才被告知有問題。而後端的密碼強度檢查(Java或NodeJS等)才是真正進行驗證的地方,前端可以不檢查,但至少後端要檢查。

程式範例說明

Java版

這邊做得比較簡單,只用String.matches方法,Java內還有一個Pattern.compile方法可以產生預先優化過的正規表達物件。另外Java中的matches方法必須要完全符合才會返回true,因此只需要檢測是否包含的情況要在正規表達的前後加上.*

public class PasswordTool {
    /**
     * 檢查輸入的密碼強度,先檢查密碼是否達到指定的長度,
     * 再檢查是否有達成包含「英文小寫、英文大寫、阿拉伯數字、特殊符號」四個項目,可透過`strength`設定至少要符合多少項。
     * https://klab.tw/2023/01/check-password-strength-using-java-and-javascript/
     * @param str - 要檢測的密碼文字
     * @param length - 需要的密碼長度
     * @param strength - 需要符合的項目數量,0到4
     * @return 如果符合強度需求返回true
     */
    public static boolean strengthChecke(String str, int length, int strength) {
        if(str == null || str.length() < length) {
            return false;
        }
        int n = 0;
        var regex = new String[] {
            ".*[a-z].*",
            ".*[A-Z].*",
            ".*[0-9].*",
            ".*[`~!@#$%^&*()_+=,<>\\-\\[\\]\\{\\}\\:;\\.'\"\\/\\\\?\\|].*"
        };
        for(var r : regex) {
            if(str.matches(r)) {
                n++;
            }
        }
        return n >= strength;
    }
}

例如需要密碼長度至少八個字,密碼至少包含三種類型的文字(四取三)可以這樣輸入:

PasswordTool.strengthChecke(pwd, 8, 3);

JavaScript版

順便附上有JSDoc的說明,在Visual Studio Code等IDE中可以幫忙檢測JavaScript程式碼是否正確。

/**
 * 檢查輸入的密碼強度,先檢查密碼是否達到指定的長度,
 * 再檢查是否有達成包含「英文小寫、英文大寫、阿拉伯數字、特殊符號」四個項目,可透過`strength`設定至少要符合多少項。
 * https://klab.tw/2023/01/check-password-strength-using-java-and-javascript/
 * @param {string} str - 要檢測的密碼文字
 * @param {number} length - 需要的密碼長度
 * @param {number} strength - 需要符合的項目數量,0到4
 * @returns 如果符合強度需求返回true
 */
function pwdStrengthChecke(str, length, strength) {
    if(!str || str.length < length) {
        return false
    }
    let n = 0
    const regex = [
        /[a-z]/,
        /[A-Z]/,
        /[0-9]/,
        /[`~!@#$%^&*()_+=,<>\-\[\]\{\}\:;\.'"\/\\?\|]/
    ]
    for(const r of regex) {
        if(str.match(r)) {
            n++
        }
    }
    return n >= strength
}

JavaScript舊版(ES5)

前一個版本使用比較近代一點的JavaScript語法,這邊提供一個可用於舊版瀏覽器JavaScript的寫法。

/**
 * 檢查輸入的密碼強度,先檢查密碼是否達到指定的長度,
 * 再檢查是否有達成包含「英文小寫、英文大寫、阿拉伯數字、特殊符號」四個項目,可透過`strength`設定至少要符合多少項。
 * https://klab.tw/2023/01/check-password-strength-using-java-and-javascript/
 * @param {string} str - 要檢測的密碼文字
 * @param {number} length - 需要的密碼長度
 * @param {number} strength - 需要符合的項目數量,0到4
 * @returns 如果符合強度需求返回true
 */
function pwdStrengthChecke(str, length, strength) {
    if(!str || str.length < length) {
        return false
    }
    var n = 0
    var regex = [
        /[a-z]/,
        /[A-Z]/,
        /[0-9]/,
        /[`~!@#$%^&*()_+=,<>\-\[\]\{\}\:;\.'"\/\\?\|]/
    ]
    for(var i = 0; i < regex.length ; i++) {
        if(str.match(regex[i])) {
            n++
        }
    }
    return n >= strength
}

TypeScript版

目前開發上我很喜歡React搭配TypeScript,多了型別檢查可以減少很多奇妙的問題。

/**
 * 檢查輸入的密碼強度,先檢查密碼是否達到指定的長度,
 * 再檢查是否有達成包含「英文小寫、英文大寫、阿拉伯數字、特殊符號」四個項目,可透過`strength`設定至少要符合多少項。
 * https://klab.tw/2023/01/check-password-strength-using-java-and-javascript/
 * @param str - 要檢測的密碼文字
 * @param length - 需要的密碼長度
 * @param strength - 需要符合的項目數量,0到4
 * @returns 如果符合強度需求返回true
 */
function pwdStrengthChecke(str: string, length: number, strength: number): boolean {
    if(!str || str.length < length) {
        return false
    }
    let n = 0
    const regex = [
        /[a-z]/,
        /[A-Z]/,
        /[0-9]/,
        /[`~!@#$%^&*()_+=,<>\-\[\]\{\}\:;\.'"\/\\?\|]/
    ]
    for(const r of regex) {
        if(str.match(r)) {
            n++
        }
    }
    return n >= strength
}