Adding a delay to HandleURL

Thank you to everyone who has replied with some great ideas.

@Thom_McGrath, thanks for the lead on the haveibeenpwned API. I’ve implemented it in my password requirements for when users are setting their passwords. If it helps anyone else, here is my method for checking a prospective password against the list of known breached passwords:

Private Function IsPasswordCompromised(password as String) As Boolean
  // Checks if a password appears in known data breaches using the haveibeenpwned.com k-anonymity API
  //
  // Parameters:
  //   password - Password to check
  //
  // Returns:
  //   Boolean - True if password found in breaches, False if not found or on error
  //
  // Notes:
  //   - Uses k-anonymity to avoid sending full password hash
  //   - Only first 5 characters of hash are sent to API
  //   - Times out after 4 seconds
  //   - Returns false on any error (network, timeout, etc)
  
  If password.Trim = "" Then
    Return True
  End If
  
  // Calculate SHA1 hash of password
  Var hash As String = EncodeHex(Crypto.SHA1(password))
  hash = hash.Uppercase
  
  // Get first 5 chars of hash for API query
  Var prefix As String = hash.Left(5)
  Var suffix As String = hash.Mid(6, hash.Length - 5)  // Start FROM position 5, not AT position 5
  
  // Set up URL request
  Var url As String = "https://api.pwnedpasswords.com/range/" + prefix
  Var conn As New URLConnection
  
  conn.RequestHeader("Add-Padding") = "true" // Helps prevent timing attacks
  conn.RequestHeader("User-Agent") = "SecurityCheck/1.0"
  
  Var timeout As Integer = 4
  
  Try
    // Make request
    Var response As String = conn.SendSync("GET", url, timeout)
    
    // Check response code
    If conn.HTTPStatusCode <> 200 Then
      Return False
    End If
    
    // Split response into lines
    Var lines() As String = response.ReplaceLineEndings(EndOfLine).Split(EndOfLine)
    
    // Search for our hash suffix in the response
    For Each line As String In lines
      If line.Trim <> "" Then
        Var parts() As String = line.Split(":")
        If parts(0).Trim = suffix Then
          // Found a match - password has been compromised
          Return True
        End If
      End If
    Next
    
    // No match found
    Return False
    
  Catch ex As RuntimeException
    // Return false on any error
    Return False
  End Try
End Function

1 Like