2023-11-17 程式更新:修正密碼英文未正確識別大小寫問題

Have I Been Pwned (HIBP) 是澳洲安全專家 Troy Hunt 在 2013 年建立的外洩密碼查詢平臺,連美國 FBI 跟英國 NCA (國家犯罪調查局)都會將蒐集到的外洩密碼貢獻給 HIBP 收藏 (參考:繼美國之後,英國也加入提供外洩密碼予Have I Been Pwned的行列 by iThome),說 HIBP 是全世界最權威的外洩密碼資料庫絕不為過。

HIBP 有個介面可輸入 Email 查詢,檢查該 Email 是否在外洩事件出現過,但這只對已發生過的外洩事件有效。從另個角度想,這批外洩密碼會是駭客猜密碼的首選,先把已知密碼試過一輪再跑吃力不討好的暴力破解。換言之,若你使用的密碼已在 HIBP 資料庫出現過,以昨提到的 NVIDIA RTX 4070 算力預估,每秒 218 億次 SHA256、509 億次 SHA1,現有六億多筆已知密碼試過一次只要 0.03s,就算密碼長達 20 位,照樣會被秒殺。(註:駭客未必能拿到外洩密碼明文,非連續性資料的每秒計算次數照理要低一些,但料敵從寬,就當一秒吧)

要避免自己的密碼在駭客暖身階段被猜中,最好的做法是先確認它沒有出現在 HIBP 資料庫。HIBP 有密碼資料檔可下載,但資料量龐大還要自己寫程式處理。透過 HIBP 提供的 API 查詢是較便捷的做法。

等等,在網站上輸入密碼檢查有沒有外洩聽起來超蠢,原本沒外流的密碼在輸入過程外流怎麼辦?這根本是在送頭吧? (我想起「誘使失主開保險箱檢查東西還在不在,小偷在旁觀察伺機下手」的橋段,以及「上網查自己有沒有在教召名單就收到教召令」的都市傳說)

HIBP 身為資安相關網站,提供 API 時自然不會犯下這類低級錯誤,它想了一個巧妙做法:要使用者自己先算好密碼的 SHA1 雜湊,用雜湊前五碼當查詢條件,API 傳回所有前五碼相符的密碼雜湊,以及該筆密碼在資料庫出現次數。查詢者取回清單自行比對後 35 碼,若找到就代表該筆密碼已被收錄,次數愈高代表愈多人用,認證為菜市場密碼無誤。

如此,使用者可確認密碼是否在資料庫中,而 HIBP 站方只知前五碼,無從得知使用者想查的密碼雜湊是哪一筆,兼顧方便與安全,好個聰明做法。

發現這麼用好的服務,我馬上想寫個小工具呼叫 API 快速比對密碼雜湊,讓 SHA1 計算、資料下載、比對全在自家完成,將密碼外流風險降到最低。為證明檢查程式光明磊落,不會搞出假查詢真偷看的勾當,坦蕩蕩不怕你看,又通吃 Windows/MacOS/Linux 的 PowerShell,是本次開發語言首選。

$ProgressPreference = 'SilentlyContinue'
while ($true) {
    $secString = Read-Host "請輸入要檢查的密碼" -AsSecureString
    if ($secString.Length -eq 0) {
        Write-Host "Bye~"
        break
    }
    # https://github.com/PowerShell/PowerShell/issues/13494#issuecomment-678150857
    $ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($secString)
    $passwd = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($ptr)
    [System.Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($ptr)
    $pwdBytes = [System.Text.Encoding]::UTF8.GetBytes($passwd)
    $hash = [System.BitConverter]::ToString([System.Security.Cryptography.SHA1]::Create().ComputeHash($pwdBytes)).Replace('-', '')
    $prefix = $hash.Substring(0, 5)
    $remaining = $hash.Substring(5)
    Write-Host "$prefix - $remaining" -ForegroundColor Cyan
    $found = (Invoke-WebRequest "https://api.pwnedpasswords.com/range/$prefix").Content.Split("`n") | Select-String -Pattern $remaining -CaseSensitive 
    if ($found) {
        $p = $found -split ':'
        Write-Host "警告!此密碼在 HIBP 資料庫出現 " -ForegroundColor Red -NoNewline
        Write-Host (+$p[1]).ToString('n0') -ForegroundColor Yellow -NoNewline
        Write-Host " 次,不建議使用" -ForegroundColor Red
        Write-Host $found -ForegroundColor Cyan
    }
    else {
        Write-Host "呼~ HIBP 資料庫未收錄此密碼" -ForegroundColor Green
        $charPool = 0
        $setNames = @();
        if ($passwd -match '[0-9]') { $charPool += 10; $setNames += '數字' }
        if ($passwd -cmatch '[a-z]') { $charPool += 26; $setNames += '小寫' }
        if ($passwd -cmatch '[A-Z]') { $charPool += 26; $setNames += '大寫' }
        if ($passwd -cmatch '[^0-9a-zA-Z]') { $charPool += 32; $setNames += '符號' }
        $length = $passwd.Length
        [bigint]$count = [bigint]::Pow($charPool, $length)
        $rtx4090Power = 21791700000; #SHA2-256 21791.7 MH/s https://hashcat.net/forum/thread-11277.html
        $secs = [bigint]::Divide($count, $rtx4090Power)
        if ($secs -lt 60) { $time = "$secs 秒" }
        elseif ($secs -lt 3600) { $time = "$([bigint]::Divide($secs, 60)) 分鐘" }
        elseif ($secs -lt 86400) { $time = "$([bigint]::Divide($secs,3600)) 小時" }
        elseif ($secs -lt 86400 * 365) { $time = "$([bigint]::Divide($secs,86400)) 天" }
        else { 
            $time = "$([bigint]::Divide($secs,86400 * 365).ToString('n0')) 年" 
        }
        Write-Host "長度 $length ($($setNames -join '、')) 預估暴力破解時間約:$time (NVIDIA RTX-4090 / SHA256)" -ForegroundColor Magenta
    }
    Write-Host
}

將上述內容存成 Check-PasswdCollision.ps1:(編碼記得選 UTF8 with BOM)

之後從 CMD 呼叫或從檔案總管選「以 PowerShell 執行」,便可快速查詢密碼是否出現在資料庫中:

我寫了迴圈方便反覆輸入密碼查詢,若沒出現在 HIBP 資料庫,則程式會用長度,字元組合複雜度(數字、大小寫、有無符號)簡單推算,如果密碼用 SHA256 保存,駭客買張 NVIDIA RTX 4090 顯卡,要花多久時間可以破解你的密碼。

實測後你會發現,ABCD1234、qwerasdf 這類簡單拼湊密碼幾乎全部都被人用過了,甚至像「我的密碼」注音符號輸入 - ji32k7au4a83 看似難猜,但它出現 249 次。ABCDEabcde1234 長達 14 碼的簡單組合照樣有人用過。14 碼隨機純數字,就算沒人用過,暴力破解只需一小時。但含大小寫短文字拼接 - TueFriTueSun 的表現挺不錯,用四位數字轉星期,只需 12 碼,好記又難破。(但這招既然說破了,已不再安全 XD)

查詢完成,密碼輸入直接按 Enter 即可結束程式。

最後來驗證 PowerShell 的跨平台特性,在 Linux / MacOS 實測一下。

Linux OK!

MacOS OK!

工具箱再添實用小工具一枚。

A handy PowerShell tool to call HIBP API to check if password exists in breach password database.


Comments

# by icecain

抓個bug 在win10複製好程式後執行,輸入 aabbaa1234 回傳 27208 - 922C30CE2B67AD40D97738DF6AFE783316C 呼~ HIBP 資料庫未收錄此密碼 長度 10 (數字、小寫、大寫) 預估暴力破解時間約:1 年 (NVIDIA RTX-4090 / SHA256) 但輸入沒有大寫字元

# by Jeffrey

to icecain,感謝通報,程式已修正(-match 改 -cmatch),請再試試。

# by icecain

應該可以了,輸入 aabbaa1234 回傳 27208 - 922C30CE2B67AD40D97738DF6AFE783316C 呼~ HIBP 資料庫未收錄此密碼 長度 10 (數字、小寫) 預估暴力破解時間約:1 天 (NVIDIA RTX-4090 / SHA256) 輸入 aabbAA1234 回傳 B8C4A - 0CB473E053CB01ACADB62B8EE5EDB546BA3 呼~ HIBP 資料庫未收錄此密碼 長度 10 (數字、小寫、大寫) 預估暴力破解時間約:1 年 (NVIDIA RTX-4090 / SHA256)

# by Sean

請問將程式碼儲存成Check-PasswdCollision.ps1後,從檔案總管按右鍵選取【用PowerShell執行】,卻只看見DOS視窗一閃即逝,是麼原因呢?

# by Jeffrey

to Sean, 推測是程式執行出錯。開一個 PowerShell 命令視窗 (如果沒開啟過可參考這篇 https://blog.darkthread.net/blog/vscode-cpp-cli-setup/ 但用一般權限即可,不需切管理者),輸入完整 C:\<full-path>\Check-PasswdCollision.ps1 執行,應可看到錯誤訊息。

# by Ken

出現以下錯誤 P:\Users\user\Desktop\Check-PasswdCollision.ps1 : File P:\Users\user\Desktop\Check-PasswdCollision.ps1 cannot be load ed because running scripts is disabled on this system. For more information, see about_Execution_Policies at https:/go. microsoft.com/fwlink/?LinkID=135170. At line:1 char:1 + P:\Users\user\Desktop\Check-PasswdCollision.ps1 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : SecurityError: (:) [], PSSecurityException + FullyQualifiedErrorId : UnauthorizedAccess

# by Jeffrey

to Ken, 你需要先允許 ps1 執行,`Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`,參考:https://learn.microsoft.com/zh-tw/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.3#change-the-execution-policy

Post a comment