11using Microsoft . AspNetCore . Identity ;
2+ using Microsoft . Extensions . Caching . Memory ;
23
34namespace NzbWebDAV . Utils ;
45
56public static class PasswordUtil
67{
8+ private static readonly MemoryCache Cache = new ( new MemoryCacheOptions ( ) { SizeLimit = 5 } ) ;
79 private static readonly PasswordHasher < object > Hasher = new ( ) ;
810
911 public static string Hash ( string password , string salt = "" )
@@ -13,6 +15,19 @@ public static string Hash(string password, string salt = "")
1315
1416 public static bool Verify ( string hash , string password , string salt = "" )
1517 {
16- return Hasher . VerifyHashedPassword ( null ! , hash , password + salt ) == PasswordVerificationResult . Success ;
18+ // If users forget to add the "--use-cookies" argument to Rclone, then Rclone will not store
19+ // session cookies, which means the Authorization header from HTTP Basic Auth will be sent and
20+ // validated on every single request. This means the password from the Authorization header will
21+ // get hashed on every single request in order to compare it against the hashed password in the
22+ // database. Password hashing is intentionally designed to be super slow in order to slow down brute
23+ // force attacks. Several hundred milliseconds would be added to every single webdav request
24+ // when the "--use-cookies" Rclone argument is not used, if not for the memory cache added here.
25+ return Cache . GetOrCreate ( new CacheKey ( hash , password , salt ) , cacheEntry =>
26+ {
27+ cacheEntry . Size = 1 ;
28+ return Hasher . VerifyHashedPassword ( null ! , hash , password + salt ) ;
29+ } ) == PasswordVerificationResult . Success ;
1730 }
31+
32+ private record CacheKey ( string Hash , string Password , string Salt ) ;
1833}
0 commit comments