From ae8be5d66f362a140971007087d155272762f591 Mon Sep 17 00:00:00 2001 From: zhouzb Date: Wed, 9 Jun 2021 16:53:40 +0800 Subject: [PATCH] feat(authentication): add a 16-byte salt in front of the password before hashing --- .../data/user-credentials.csv | 6 +-- .../data/user-credentials.json | 6 ++- .../src/emqx_authentication_mnesia.erl | 38 ++++++++++++------- .../test/data/user-credentials.csv | 6 +-- .../test/data/user-credentials.json | 6 ++- 5 files changed, 38 insertions(+), 24 deletions(-) diff --git a/apps/emqx_authentication/data/user-credentials.csv b/apps/emqx_authentication/data/user-credentials.csv index 0a0affaa2..108c9f10d 100644 --- a/apps/emqx_authentication/data/user-credentials.csv +++ b/apps/emqx_authentication/data/user-credentials.csv @@ -1,3 +1,3 @@ -user_id,password_hash -myuser3,8d41233e39c95b5da13361e354e1c9e639f07b27d397463a8f91b71ee07ccfb2 -myuser4,5809df0154f3cb4ac5c3a5572eaca0c5f7f9d858e887fc675b2becab9feb19d1 +user_id,password_hash,salt +myuser3,13de23cc872cf8198797914e95b9ec4e123fd7aaea186aea824452ec0f651a91,DztjMHrbVWmzkF1/dKD/ag== +myuser4,5231a927328f24e7254513819e47277feeb379a724f5e784ddbb09db42d322b7,+kGfV4AH+MR3f30zhoPIkQ== diff --git a/apps/emqx_authentication/data/user-credentials.json b/apps/emqx_authentication/data/user-credentials.json index a910a8dc2..1361592da 100644 --- a/apps/emqx_authentication/data/user-credentials.json +++ b/apps/emqx_authentication/data/user-credentials.json @@ -1,10 +1,12 @@ [ { "user_id":"myuser1", - "password_hash":"09343625c6c123d3434932fe1ce08bae5ac00a8f95bd746e10491b0bafdd1817" + "password_hash":"3e4845e5fc818ac1bfe6a3f77ab665e7721700b5803b6f76def5dce6aacdc42c", + "salt": "LvLGNfMjUJhUpuWIubv4Gg==" }, { "user_id":"myuser2", - "password_hash":"8767a7d316ad68cb607c7c805b859ffa78277dda13b7a3e2e8b53cad3cabbc6e" + "password_hash":"54bd059dc88e6dd9158306a638215fdce5545eac351fdf2affc8ee94686711c5", + "salt": "wF1mavOutYiNvwyYw0PmbQ==" } ] diff --git a/apps/emqx_authentication/src/emqx_authentication_mnesia.erl b/apps/emqx_authentication/src/emqx_authentication_mnesia.erl index d671a234d..ce2286c28 100644 --- a/apps/emqx_authentication/src/emqx_authentication_mnesia.erl +++ b/apps/emqx_authentication/src/emqx_authentication_mnesia.erl @@ -32,20 +32,19 @@ , list_users/1 ]). +%% TODO: support bcrypt -service_type(#{ name => mnesia, params_spec => #{ user_id_type => #{ order => 1, type => string, - required => true, enum => [<<"username">>, <<"clientid">>, <<"ip">>, <<"common name">>, <<"issuer">>], default => <<"username">> }, password_hash_algorithm => #{ order => 2, type => string, - required => true, enum => [<<"plain">>, <<"md5">>, <<"sha">>, <<"sha256">>, <<"sha512">>], default => <<"sha256">> } @@ -55,6 +54,7 @@ -record(user_info, { user_id :: {user_group(), user_id()} , password_hash :: binary() + , salt :: binary() }). -type(user_group() :: {chain_id(), service_name()}). @@ -67,8 +67,6 @@ -define(TAB, mnesia_basic_auth). -%% TODO: Support salt - %%------------------------------------------------------------------------------ %% Mnesia bootstrap %%------------------------------------------------------------------------------ @@ -103,8 +101,8 @@ authenticate(ClientInfo = #{password := Password}, case mnesia:dirty_read(?TAB, {UserGroup, UserID}) of [] -> ignore; - [#user_info{password_hash = Hash}] -> - case Hash =:= emqx_passwd:hash(Algorithm, Password) of + [#user_info{password_hash = Hash, salt = Salt}] -> + case Hash =:= emqx_passwd:hash(Algorithm, <>) of true -> ok; false -> @@ -220,9 +218,11 @@ import_users_from_csv(Filename, #{user_group := UserGroup}) -> import(_UserGroup, []) -> ok; -import(UserGroup, [#{<<"user_id">> := UserID, <<"password_hash">> := PasswordHash} | More]) +import(UserGroup, [#{<<"user_id">> := UserID, + <<"password_hash">> := PasswordHash, + <<"salt">> := Salt} | More]) when is_binary(UserID) andalso is_binary(PasswordHash) -> - import_user(UserGroup, UserID, PasswordHash), + import_user(UserGroup, UserID, PasswordHash, Salt), import(UserGroup, More); import(_UserGroup, [_ | _More]) -> {error, bad_format}. @@ -234,8 +234,9 @@ import(UserGroup, File, Seq) -> Fields = binary:split(Line, [<<",">>, <<" ">>, <<"\n">>], [global, trim_all]), case get_user_info_by_seq(Fields, Seq) of {ok, #{user_id := UserID, - password_hash := PasswordHash}} -> - import_user(UserGroup, UserID, PasswordHash), + password_hash := PasswordHash, + salt := Salt}} -> + import_user(UserGroup, UserID, PasswordHash, Salt), import(UserGroup, File, Seq); {error, Reason} -> {error, Reason} @@ -260,7 +261,7 @@ get_csv_header(File) -> get_user_info_by_seq(Fields, Seq) -> get_user_info_by_seq(Fields, Seq, #{}). -get_user_info_by_seq([], [], #{user_id := _, password_hash := _} = Acc) -> +get_user_info_by_seq([], [], #{user_id := _, password_hash := _, salt := _} = Acc) -> {ok, Acc}; get_user_info_by_seq(_, [], _) -> {error, bad_format}; @@ -268,18 +269,27 @@ get_user_info_by_seq([UserID | More1], [<<"user_id">> | More2], Acc) -> get_user_info_by_seq(More1, More2, Acc#{user_id => UserID}); get_user_info_by_seq([PasswordHash | More1], [<<"password_hash">> | More2], Acc) -> get_user_info_by_seq(More1, More2, Acc#{password_hash => PasswordHash}); +get_user_info_by_seq([Salt | More1], [<<"salt">> | More2], Acc) -> + get_user_info_by_seq(More1, More2, Acc#{salt => Salt}); get_user_info_by_seq(_, _, _) -> {error, bad_format}. -compile({inline, [add/4]}). add(UserGroup, UserID, Password, Algorithm) -> + Salt = case Algorithm of + <<"plain">> -> <<>>; + _ -> crypto:strong_rand_bytes(16) + end, + SaltedPassword = <>, Credential = #user_info{user_id = {UserGroup, UserID}, - password_hash = emqx_passwd:hash(Algorithm, Password)}, + password_hash = emqx_passwd:hash(Algorithm, SaltedPassword), + salt = Salt}, mnesia:write(?TAB, Credential, write). -import_user(UserGroup, UserID, PasswordHash) -> +import_user(UserGroup, UserID, PasswordHash, Salt) -> Credential = #user_info{user_id = {UserGroup, UserID}, - password_hash = PasswordHash}, + password_hash = PasswordHash, + salt = base64:decode(Salt)}, mnesia:write(?TAB, Credential, write). delete_user2(UserInfo) -> diff --git a/apps/emqx_authentication/test/data/user-credentials.csv b/apps/emqx_authentication/test/data/user-credentials.csv index 0a0affaa2..108c9f10d 100644 --- a/apps/emqx_authentication/test/data/user-credentials.csv +++ b/apps/emqx_authentication/test/data/user-credentials.csv @@ -1,3 +1,3 @@ -user_id,password_hash -myuser3,8d41233e39c95b5da13361e354e1c9e639f07b27d397463a8f91b71ee07ccfb2 -myuser4,5809df0154f3cb4ac5c3a5572eaca0c5f7f9d858e887fc675b2becab9feb19d1 +user_id,password_hash,salt +myuser3,13de23cc872cf8198797914e95b9ec4e123fd7aaea186aea824452ec0f651a91,DztjMHrbVWmzkF1/dKD/ag== +myuser4,5231a927328f24e7254513819e47277feeb379a724f5e784ddbb09db42d322b7,+kGfV4AH+MR3f30zhoPIkQ== diff --git a/apps/emqx_authentication/test/data/user-credentials.json b/apps/emqx_authentication/test/data/user-credentials.json index a910a8dc2..1361592da 100644 --- a/apps/emqx_authentication/test/data/user-credentials.json +++ b/apps/emqx_authentication/test/data/user-credentials.json @@ -1,10 +1,12 @@ [ { "user_id":"myuser1", - "password_hash":"09343625c6c123d3434932fe1ce08bae5ac00a8f95bd746e10491b0bafdd1817" + "password_hash":"3e4845e5fc818ac1bfe6a3f77ab665e7721700b5803b6f76def5dce6aacdc42c", + "salt": "LvLGNfMjUJhUpuWIubv4Gg==" }, { "user_id":"myuser2", - "password_hash":"8767a7d316ad68cb607c7c805b859ffa78277dda13b7a3e2e8b53cad3cabbc6e" + "password_hash":"54bd059dc88e6dd9158306a638215fdce5545eac351fdf2affc8ee94686711c5", + "salt": "wF1mavOutYiNvwyYw0PmbQ==" } ]