25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-30 16:36:29 +01:00

Add password entropy check (EJAB-1326)

This commit is contained in:
Evgeniy Khramtsov 2010-10-24 17:17:30 +10:00 committed by Badlop
parent 55bd17d6f5
commit 30366dbe98
3 changed files with 77 additions and 17 deletions

View File

@ -3794,6 +3794,10 @@ Options:
from s2s leads to uncontrolled massive accounts creation by rogue users. from s2s leads to uncontrolled massive accounts creation by rogue users.
\titem{\{captcha\_protected, false|true\}} \ind{options!captcha\_protected} \titem{\{captcha\_protected, false|true\}} \ind{options!captcha\_protected}
Protect registrations with CAPTCHA (see section \ref{captcha}). The default is \term{false}. Protect registrations with CAPTCHA (see section \ref{captcha}). The default is \term{false}.
\titem{\{password\_strength, Entropy\}} \ind{options!password\_strength}
This option sets the minimum informational entropy for passwords. The value \term{Entropy}
is a number of bits of entropy. The recommended minimum is 32 bits.
The default is 0, i.e. no checks are performed.
\titem{\{welcome\_message, Message\}} \ind{options!welcomem}Set a welcome message that \titem{\{welcome\_message, Message\}} \ind{options!welcomem}Set a welcome message that
is sent to each newly registered account. The first string is the subject, and is sent to each newly registered account. The first string is the subject, and
the second string is the message body. the second string is the message body.

View File

@ -49,7 +49,8 @@
is_user_exists_in_other_modules/3, is_user_exists_in_other_modules/3,
remove_user/2, remove_user/2,
remove_user/3, remove_user/3,
plain_password_required/1 plain_password_required/1,
entropy/1
]). ]).
-export([start/1 -export([start/1
@ -443,6 +444,29 @@ remove_user(User, Server, Password)
end, end,
R. R.
%% @spec (IOList) -> non_negative_float()
%% @doc Calculate informational entropy.
entropy(IOList) ->
case binary_to_list(iolist_to_binary(IOList)) of
"" ->
0.0;
S ->
Set = lists:foldl(
fun(C, [Digit, Printable, LowLetter, HiLetter, Other]) ->
if C >= $a, C =< $z ->
[Digit, Printable, 26, HiLetter, Other];
C >= $0, C =< $9 ->
[9, Printable, LowLetter, HiLetter, Other];
C >= $A, C =< $Z ->
[Digit, Printable, LowLetter, 26, Other];
C >= 16#21, C =< 16#7e ->
[Digit, 33, LowLetter, HiLetter, Other];
true ->
[Digit, Printable, LowLetter, HiLetter, 128]
end
end, [0, 0, 0, 0, 0], S),
length(S) * math:log(lists:sum(Set))/math:log(2)
end.
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
%%% Internal functions %%% Internal functions

View File

@ -254,7 +254,7 @@ try_register_or_set_password(User, Server, Password, From, IQ_Rec,
SubEl, Source, Lang, CaptchaSucceed) -> SubEl, Source, Lang, CaptchaSucceed) ->
case {exmpp_jid:node_as_list(From), exmpp_jid:prep_domain_as_list(From)} of case {exmpp_jid:node_as_list(From), exmpp_jid:prep_domain_as_list(From)} of
{User, Server} -> {User, Server} ->
try_set_password(User, Server, Password, IQ_Rec, SubEl); try_set_password(User, Server, Password, IQ_Rec, SubEl, Lang);
_ when CaptchaSucceed -> _ when CaptchaSucceed ->
case check_from(From, Server) of case check_from(From, Server) of
allow -> allow ->
@ -273,7 +273,16 @@ try_register_or_set_password(User, Server, Password, From, IQ_Rec,
end. end.
%% @doc Try to change password and return IQ response %% @doc Try to change password and return IQ response
try_set_password(User, Server, Password, IQ_Rec, SubEl) -> try_set_password(User, Server, Password, IQ_Rec, SubEl, Lang) ->
case is_strong_password(Server, Password) of
true ->
try_set_password_strong(User, Server, Password, IQ_Rec, SubEl, Lang);
false ->
%% ErrText = "The password is too weak",
exmpp_iq:error(IQ_Rec, 'not-acceptable')
end.
try_set_password_strong(User, Server, Password, IQ_Rec, SubEl, _Lang) ->
case ejabberd_auth:set_password(User, Server, Password) of case ejabberd_auth:set_password(User, Server, Password) of
ok -> ok ->
exmpp_iq:result(IQ_Rec, SubEl); exmpp_iq:result(IQ_Rec, SubEl);
@ -287,20 +296,7 @@ try_set_password(User, Server, Password, IQ_Rec, SubEl) ->
exmpp_iq:error(IQ_Rec, 'internal-server-error') exmpp_iq:error(IQ_Rec, 'internal-server-error')
end. end.
try_register(User, Server, Password, Source, Lang) -> try_register_strong(User, Server, Password, Source, _Lang, JID) ->
case exmpp_stringprep:is_node(User) of
false ->
{error, 'bad-request'};
_ ->
JID = exmpp_jid:make(User,
Server),
Access = gen_mod:get_module_opt(Server, ?MODULE, access, all),
case acl:match_rule(Server, Access, JID) of
deny ->
{error, 'forbidden'};
allow ->
case check_timeout(Source) of
true ->
case ejabberd_auth:try_register(User, Server, Password) of case ejabberd_auth:try_register(User, Server, Password) of
{atomic, ok} -> {atomic, ok} ->
send_welcome_message(JID), send_welcome_message(JID),
@ -318,6 +314,27 @@ try_register(User, Server, Password, Source, Lang) ->
{error, _Reason} -> {error, _Reason} ->
{error, 'internal-server-error'} {error, 'internal-server-error'}
end end
end.
try_register(User, Server, Password, Source, Lang) ->
case exmpp_stringprep:is_node(User) of
false ->
{error, 'bad-request'};
_ ->
JID = exmpp_jid:make(User, Server),
Access = gen_mod:get_module_opt(Server, ?MODULE, access, all),
case acl:match_rule(Server, Access, JID) of
deny ->
{error, 'forbidden'};
allow ->
case check_timeout(Source) of
true ->
case is_strong_password(Server, Password) of
true ->
try_register_strong(User, Server, Password, Source, Lang, JID);
false ->
%%ErrText = "The password is too weak",
{error, 'not-acceptable'}
end; end;
false -> false ->
ErrText = "Users are not allowed to register " ErrText = "Users are not allowed to register "
@ -492,3 +509,18 @@ process_xdata_submit(El) ->
error error
end end
end. end.
is_strong_password(Server, Password) ->
LServer = jlib:nameprep(Server),
case gen_mod:get_module_opt(LServer, ?MODULE, password_strength, 0) of
Entropy when is_number(Entropy), Entropy >= 0 ->
if Entropy == 0 ->
true;
true ->
ejabberd_auth:entropy(Password) >= Entropy
end;
Wrong ->
?WARNING_MSG("Wrong value for password_strength option: ~p",
[Wrong]),
true
end.