使用数据库功能更快地执行用户身份验证的方法
Faster way to perform user authentication using database functions
有没有更快的方法来使用数据库函数来保护对用户进行身份验证?
crypt() 函数似乎花了很多时间。
Table:
id (bigserial) pkey
username (text) indexed
password (text) indexed [password is the hash: crypt('12345678', gen_salt('bf', 8))]
普通测试:
test_db=# explain analyze SELECT id FROM users WHERE id = 1 AND password='12345678' LIMIT 1;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.28..8.29 rows=1 width=8) (actual time=0.029..0.029 rows=0 loops=1)
-> Index Scan using users_idx_password01 on users (cost=0.28..8.29 rows=1 width=8) (actual time=0.028..0.028 rows=0 loops=1)
Index Cond: (password = '12345678'::text)
Filter: (id = 1)
Total runtime: 0.037 ms
(5 rows)
Crypt() 测试:
test_db=# explain analyze SELECT id FROM users WHERE id = 1 AND password=(crypt('12345678',password)) LIMIT 1;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.28..8.30 rows=1 width=8) (actual time=7.534..7.534 rows=1 loops=1)
-> Index Scan using users_pkey on users (cost=0.28..8.30 rows=1 width=8) (actual time=7.534..7.534 rows=1 loops=1)
Index Cond: (id = 1)
Filter: (password = crypt('12345678'::text, password))
Total runtime: 7.550 ms
(5 rows)
我不完全确定 postgres 如何处理这样的查询,但在我看来,对每一行都执行了 crypt 函数。当您考虑使用适当的密码哈希函数时,故意慢,这样的查询将变得每一行都变慢。
处理此类查询的方法是,仅搜索用户,然后验证密码哈希:
SELECT password FROM users WHERE username = "carfield"
之后您在代码中测试找到的密码哈希。这也允许为每个密码处理唯一的盐,这是必须的。合适的散列函数是 BCrypt、PBKDF2 或 SCrypt,它们都有成本因素。通常编程环境已经提供了功能,这是 PHP:
中的示例
$isPasswordCorrect = password_verify($password, $existingHashFromDb);
有没有更快的方法来使用数据库函数来保护对用户进行身份验证? crypt() 函数似乎花了很多时间。
Table:
id (bigserial) pkey
username (text) indexed
password (text) indexed [password is the hash: crypt('12345678', gen_salt('bf', 8))]
普通测试:
test_db=# explain analyze SELECT id FROM users WHERE id = 1 AND password='12345678' LIMIT 1;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.28..8.29 rows=1 width=8) (actual time=0.029..0.029 rows=0 loops=1)
-> Index Scan using users_idx_password01 on users (cost=0.28..8.29 rows=1 width=8) (actual time=0.028..0.028 rows=0 loops=1)
Index Cond: (password = '12345678'::text)
Filter: (id = 1)
Total runtime: 0.037 ms
(5 rows)
Crypt() 测试:
test_db=# explain analyze SELECT id FROM users WHERE id = 1 AND password=(crypt('12345678',password)) LIMIT 1;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.28..8.30 rows=1 width=8) (actual time=7.534..7.534 rows=1 loops=1)
-> Index Scan using users_pkey on users (cost=0.28..8.30 rows=1 width=8) (actual time=7.534..7.534 rows=1 loops=1)
Index Cond: (id = 1)
Filter: (password = crypt('12345678'::text, password))
Total runtime: 7.550 ms
(5 rows)
我不完全确定 postgres 如何处理这样的查询,但在我看来,对每一行都执行了 crypt 函数。当您考虑使用适当的密码哈希函数时,故意慢,这样的查询将变得每一行都变慢。
处理此类查询的方法是,仅搜索用户,然后验证密码哈希:
SELECT password FROM users WHERE username = "carfield"
之后您在代码中测试找到的密码哈希。这也允许为每个密码处理唯一的盐,这是必须的。合适的散列函数是 BCrypt、PBKDF2 或 SCrypt,它们都有成本因素。通常编程环境已经提供了功能,这是 PHP:
中的示例$isPasswordCorrect = password_verify($password, $existingHashFromDb);