2017-08-11 2 views
2

J'aimerais pouvoir utiliser la liste Pwned Passwords fournie par Troy Hunt's have i been pwned service. Le service est décrit dans son article de blog Introducing 306 Million Freely Downloadable Pwned Passwords. L'API utilise un code d'état HTTP Not Found 404 pour indiquer si un mot de passe est introuvable dans la liste et un 200 pour indiquer qu'il a été trouvé dans la liste compromise. Cela rend difficile à consommer via le Invoke-WebRequest PowerShell Cmdlet, ce qui provoque une exception WebException pour 404.Comment puis-je vérifier les mots de passe contre les mots de passe Pwned hasibeenpwned de PowerShell

Je vais répondre à cette question, pour référence future, avec un peu d'exemple de code qui ne nécessite pas d'intercepter l'exception.

+0

Grande question et la réponse, mais pourquoi spécifiquement vouliez-vous pas seulement attraper l'exception? –

+0

Curiosité à propos des API .NET mais aussi lors de tests pour deux résultats, l'un d'entre eux ne se sentant pas "exceptionnel" @MarkWragg –

Répondre

4

Le plus récent HttpClient vous permet de faire des demandes Http à un niveau inférieur et de vérifier le HttpStatusCode sans traiter les exceptions pour 404 comme indiqué ci-dessous.

function Test-CompromisedPassword { 
    param([Parameter(Mandatory=$True)][string]$password) 

    # Force assembly to be loaded 
    Add-Type -AssemblyName 'System.Net.Http'  
    # By default PowerShell would use TLS 1.0 which is not supported by the API 
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 

    $baseUrl = "https://haveibeenpwned.com/api/v2/pwnedpassword/{0}?originalPasswordIsAHash={1}" 
    $url = $baseUrl -f $password,'false' 

    $httpClient = New-Object System.Net.Http.HttpClient 
    # User-Agent header must be set to call the API 
    $httpClient.DefaultRequestHeaders.Add("User-Agent", "PowerShell script $($MyInvocation.MyCommand.Name)") 

    # HttpClient is only Async so use .Result to force the synchronous call 
    $response = $httpClient.GetAsync($url).Result 

    Write-Verbose "$password $([int]$response.StatusCode) $($response.StatusCode)" 

    switch ([int]$response.StatusCode) { 
     200 { $passwordFound = $true; break; } 
     404 { $passwordFound = $false; break; } 
     429 { throw "Rate limit exceeded" } 
     default { throw "Not expected" + $response.StatusCode } 
    } 

    if ($response) { $response.Dispose() } 
    if ($httpClient) { $httpClient.Dispose() } 

    return $passwordFound 
} 

Vous pouvez tester cette funtion comme suit

Test-CompromisedPassword 'password' # Returns true to indicate password found 
Start-Sleep -Milliseconds 1500 # Wait for the Rate limit time to expire 
Test-CompromisedPassword ([Guid]::NewGuid()) # Returns false to indicate password not found