You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2023/05/26 15:04:54 UTC
[couchdb] 01/01: Add optional logging of security issues when replicating
This is an automated email from the ASF dual-hosted git repository.
rnewson pushed a commit to branch replicator_security_warnings
in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit cb6c65a5016b964498902d94777a95b195288fa6
Author: Robert Newson <rn...@apache.org>
AuthorDate: Fri May 26 15:21:50 2023 +0100
Add optional logging of security issues when replicating
---
.../src/couch_replicator_scheduler.erl | 2 +
.../src/couch_replicator_utils.erl | 68 +++++++++++++++++++++-
2 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/src/couch_replicator/src/couch_replicator_scheduler.erl b/src/couch_replicator/src/couch_replicator_scheduler.erl
index d02256807..7c275737e 100644
--- a/src/couch_replicator/src/couch_replicator_scheduler.erl
+++ b/src/couch_replicator/src/couch_replicator_scheduler.erl
@@ -58,6 +58,7 @@
-include("couch_replicator.hrl").
-include_lib("couch_replicator/include/couch_replicator_api_wrap.hrl").
-include_lib("couch/include/couch_db.hrl").
+-include_lib("ibrowse/include/ibrowse.hrl").
%% definitions
-define(MAX_BACKOFF_EXPONENT, 10).
@@ -627,6 +628,7 @@ start_job_int(#job{pid = Pid}, _State) when Pid /= undefined ->
ok;
start_job_int(#job{} = Job0, State) ->
Job = maybe_optimize_job_for_rate_limiting(Job0),
+ ok = couch_replicator_utils:log_security_warnings(Job0#job.rep),
case couch_replicator_scheduler_sup:start_child(Job#job.rep) of
{ok, Child} ->
Ref = monitor(process, Child),
diff --git a/src/couch_replicator/src/couch_replicator_utils.erl b/src/couch_replicator/src/couch_replicator_utils.erl
index 40d188516..4cceaafed 100644
--- a/src/couch_replicator/src/couch_replicator_utils.erl
+++ b/src/couch_replicator/src/couch_replicator_utils.erl
@@ -27,13 +27,15 @@
get_basic_auth_creds/1,
remove_basic_auth_creds/1,
normalize_basic_auth/1,
- seq_encode/1
+ seq_encode/1,
+ log_security_warnings/1
]).
-include_lib("ibrowse/include/ibrowse.hrl").
-include_lib("couch/include/couch_db.hrl").
-include("couch_replicator.hrl").
-include_lib("couch_replicator/include/couch_replicator_api_wrap.hrl").
+-include_lib("public_key/include/public_key.hrl").
-import(couch_util, [
get_value/2,
@@ -276,6 +278,70 @@ seq_encode(Seq) ->
% object. We are being maximally compatible here.
?JSON_ENCODE(Seq).
+%% Log uses of http protocol and uses of https protocol where verify_peer
+%% would fail.
+log_security_warnings(#rep{} = Rep) ->
+ case config:get_boolean("couch_replicator", "log_security_warnings", false) of
+ false ->
+ ok;
+ true ->
+ ok = check_security(Rep, source),
+ ok = check_security(Rep, target)
+ end.
+
+check_security(#rep{} = Rep, Type) ->
+ Url =
+ case Type of
+ source -> Rep#rep.source#httpdb.url;
+ target -> Rep#rep.target#httpdb.url
+ end,
+ #url{protocol = Protocol} = ibrowse_lib:parse_url(Url),
+ case Protocol of
+ http ->
+ couch_log:warning("**security warning** replication ~s has insecure ~s at ~s", [
+ rep_principal(Rep), Type, Url
+ ]),
+ ok;
+ https ->
+ ibrowse:send_req(Url, [], head, [], [
+ {is_ssl, true}, {ssl_options, [{verify_fun, check_security_fun(Rep, Url)}]}
+ ]),
+ ok;
+ _ ->
+ ok
+ end.
+
+check_security_fun(#rep{} = Rep, Url) ->
+ Fun = fun
+ (_, {bad_cert, Reason}, UserState) ->
+ couch_log:warning("**security warning** bad cert ~s for reason ~p at ~s", [
+ rep_principal(Rep), Reason, Url
+ ]),
+ {valid, UserState};
+ (_, {extension, #'Extension'{critical = true} = Ext}, UserState) ->
+ couch_log:warning(
+ "**security warning** unsupported critical extension ~p ~s for reason ~p at ~s", [
+ Ext#'Extension'.extnID, rep_principal(Rep), Url
+ ]
+ ),
+ {valid, UserState};
+ (_, {extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, UserState};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end,
+ InitialState = [],
+ {Fun, InitialState}.
+
+rep_principal(#rep{db_name = DbName} = Rep) when is_binary(DbName) ->
+ io_lib:format("in database ~s, docid ~s", [
+ mem3:dbname(DbName), Rep#rep.doc_id
+ ]);
+rep_principal(#rep{user_ctx = #user_ctx{name = Name}}) when is_binary(Name) ->
+ io_lib:format("by user ~s", [Name]).
+
-ifdef(TEST).
-include_lib("couch/include/couch_eunit.hrl").