rnewson commented on code in PR #4814:
URL: https://github.com/apache/couchdb/pull/4814#discussion_r1378872713


##########
src/couch/src/couch_passwords_cache.erl:
##########
@@ -0,0 +1,65 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+%
+% password hashes on disk can take a long time to verify. This is by design, to
+% guard against offline attacks. This module adds an in-memory cache for 
password
+% verification to speed up verification after a successful slow verification 
from
+% the hash stored on disk, in order not to transfer the deliberate offline 
attack
+% protection to database requests.
+%
+% In memory we record a PBKDF_SHA256 derivation using a low number of 
iterations
+% and check against this if present. Entries in couch_passwords_cache expire 
automatically
+% and the maximum number of cached entries is configurable.
+
+-module(couch_passwords_cache).
+
+-define(CACHE, couch_passwords_cache_lru).
+
+-export([start_link/0]).
+
+% public api
+-export([authenticate/4, insert/4]).
+
+start_link() ->
+    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+
+% public functions
+-spec authenticate(
+    AuthModule :: atom(), UserName :: binary(), Password :: binary(), Salt :: 
binary()
+) ->
+    not_found | boolean().
+authenticate(AuthModule, UserName, Password, Salt) ->
+    case config:get_boolean("couch_passwords_cache", "enable", true) of
+        true ->
+            authenticate_int(AuthModule, UserName, Password, Salt);
+        false ->
+            not_found
+    end.
+
+authenticate_int(AuthModule, UserName, Password, Salt) ->
+    % salt in key to ensure entry is not a match if user changes their password
+    % (as salt is re-randomised in that event)
+    case ets_lru:lookup_d(?CACHE, {AuthModule, UserName, Salt}) of
+        not_found ->
+            not_found;
+        {ok, ExpectedHash} ->
+            ActualHash = hash(Password, Salt),
+            couch_passwords:verify(ExpectedHash, ActualHash)
+    end.
+
+-spec insert(AuthModule :: atom(), UserName :: binary(), Password :: binary(), 
Salt :: binary()) ->
+    ok.
+insert(AuthModule, UserName, Password, Salt) ->
+    ets_lru:insert(?CACHE, {AuthModule, UserName, Salt}, hash(Password, Salt)).
+
+hash(Password, Salt) ->
+    fast_pbkdf2:pbkdf2(sha256, Password, Salt, _Iterations = 5, _KeyLen = 32).

Review Comment:
   This was my way of showing that the in-memory hashing is not configurable by 
design.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@couchdb.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to