ACL: store hashed passwords in memory.

Note that this breaks API compatibility with Redis < 6:

    CONFIG GET requirepass

Will no longer return a cleartext password as well, but the SHA256 hash
of the password set.
This commit is contained in:
antirez 2019-09-12 12:54:57 +02:00
parent ae5054b476
commit b170a01fa7

View File

@ -142,14 +142,14 @@ int time_independent_strcmp(char *a, char *b) {
/* Given an SDS string, returns the SHA256 hex representation as a /* Given an SDS string, returns the SHA256 hex representation as a
* new SDS string. */ * new SDS string. */
sds ACLHashPassword(sds cleartext) { sds ACLHashPassword(unsigned char *cleartext, size_t len) {
SHA256_CTX ctx; SHA256_CTX ctx;
unsigned char hash[SHA256_BLOCK_SIZE]; unsigned char hash[SHA256_BLOCK_SIZE];
char hex[SHA256_BLOCK_SIZE*2]; char hex[SHA256_BLOCK_SIZE*2];
char *cset = "0123456789abcdef"; char *cset = "0123456789abcdef";
sha256_init(&ctx); sha256_init(&ctx);
sha256_update(&ctx,(unsigned char*)cleartext,sdslen(cleartext)); sha256_update(&ctx,(unsigned char*)cleartext,len);
sha256_final(&ctx,hash); sha256_final(&ctx,hash);
for (int j = 0; j < SHA256_BLOCK_SIZE; j++) { for (int j = 0; j < SHA256_BLOCK_SIZE; j++) {
@ -721,13 +721,16 @@ int ACLSetUser(user *u, const char *op, ssize_t oplen) {
u->flags &= ~USER_FLAG_NOPASS; u->flags &= ~USER_FLAG_NOPASS;
listEmpty(u->passwords); listEmpty(u->passwords);
} else if (op[0] == '>') { } else if (op[0] == '>') {
sds newpass = sdsnewlen(op+1,oplen-1); sds newpass = ACLHashPassword((unsigned char*)op+1,oplen-1);
listNode *ln = listSearchKey(u->passwords,newpass); listNode *ln = listSearchKey(u->passwords,newpass);
/* Avoid re-adding the same password multiple times. */ /* Avoid re-adding the same password multiple times. */
if (ln == NULL) listAddNodeTail(u->passwords,newpass); if (ln == NULL)
listAddNodeTail(u->passwords,newpass);
else
sdsfree(newpass);
u->flags &= ~USER_FLAG_NOPASS; u->flags &= ~USER_FLAG_NOPASS;
} else if (op[0] == '<') { } else if (op[0] == '<') {
sds delpass = sdsnewlen(op+1,oplen-1); sds delpass = ACLHashPassword((unsigned char*)op+1,oplen-1);
listNode *ln = listSearchKey(u->passwords,delpass); listNode *ln = listSearchKey(u->passwords,delpass);
sdsfree(delpass); sdsfree(delpass);
if (ln) { if (ln) {
@ -744,7 +747,10 @@ int ACLSetUser(user *u, const char *op, ssize_t oplen) {
sds newpat = sdsnewlen(op+1,oplen-1); sds newpat = sdsnewlen(op+1,oplen-1);
listNode *ln = listSearchKey(u->patterns,newpat); listNode *ln = listSearchKey(u->patterns,newpat);
/* Avoid re-adding the same pattern multiple times. */ /* Avoid re-adding the same pattern multiple times. */
if (ln == NULL) listAddNodeTail(u->patterns,newpat); if (ln == NULL)
listAddNodeTail(u->patterns,newpat);
else
sdsfree(newpat);
u->flags &= ~USER_FLAG_ALLKEYS; u->flags &= ~USER_FLAG_ALLKEYS;
} else if (op[0] == '+' && op[1] != '@') { } else if (op[0] == '+' && op[1] != '@') {
if (strchr(op,'|') == NULL) { if (strchr(op,'|') == NULL) {
@ -899,11 +905,15 @@ int ACLCheckUserCredentials(robj *username, robj *password) {
listIter li; listIter li;
listNode *ln; listNode *ln;
listRewind(u->passwords,&li); listRewind(u->passwords,&li);
sds hashed = ACLHashPassword(password->ptr,sdslen(password->ptr));
while((ln = listNext(&li))) { while((ln = listNext(&li))) {
sds thispass = listNodeValue(ln); sds thispass = listNodeValue(ln);
if (!time_independent_strcmp(password->ptr, thispass)) if (!time_independent_strcmp(hashed, thispass)) {
sdsfree(hashed);
return C_OK; return C_OK;
}
} }
sdsfree(hashed);
/* If we reached this point, no password matched. */ /* If we reached this point, no password matched. */
errno = EINVAL; errno = EINVAL;