作者
digoal
日期
2021-06-25
标签
PostgreSQL , md5 , scram-sha-256
背景
PG 目前的两种数据库用户密码存储方法, 建议选择scram-sha-256. 为什么呢?
1、PG md5密码加密方法
```
postgres=# set password_encryption ='md5';
SET
postgres=# alter role postgres encrypted password 'abc';
ALTER ROLE
postgres=# select rolname,rolpassword from pg_authid where rolname='postgres';
rolname | rolpassword
----------+-------------------------------------
postgres | md567429efea5606f58dff8f67e3e2ad490
(1 row)
MD5码 = md5(pwd+username)
postgres=# select md5('abcpostgres');
md5
67429efea5606f58dff8f67e3e2ad490
(1 row)
```
md5码的方法与pgcrytpo插件中的digest, hmac类似, 使用pwd加密出一个静态的hash, 使用时服务端存储hash如果要校验客户的密码是否正确必须拿hash去校验所以协议上无法防止泄漏hash后的认证. 参考如下:
MD5码泄漏有安全风险:
《PostgreSQL md5 对比 MySQL - 秘钥认证》
2、SCRAM-SHA-256 密码存储加密方法, 更加健壮
相关代码如下:
src/common/scram-common.c
存储格式:
SCRAM-SHA-256
$
<iteration count>
:
<salt>
$
<StoredKey>
:
<ServerKey>
```
postgres=# set password_encryption ='scram-sha-256';
SET
postgres=# alter role postgres encrypted password 'abc';
ALTER ROLE
postgres=# select rolname,rolpassword from pg_authid where rolname='postgres';
rolname | rolpassword
----------+---------------------------------------------------------------------------------------------------------------------------------------
postgres | SCRAM-SHA-256$4096:N3V5yiPtZeUy8qeFzIN4Yw==$qzsIb2zahYWa0lkEQKlpKwN2rlx7rTTgKPzFS3vuBgg=:THe9oAyu7FVf7yIzvPSNA6bhUo++HBRE2s6ooKNd4Zg=
(1 row)
postgres=# alter role postgres encrypted password 'abc';
ALTER ROLE
同样的密码, 修改后存储内容也会变化.
postgres=# select rolname,rolpassword from pg_authid where rolname='postgres';
rolname | rolpassword
----------+---------------------------------------------------------------------------------------------------------------------------------------
postgres | SCRAM-SHA-256$4096:wlpFWX0mdrNHRcNFmF/mmA==$V3DLawFi9ElfE2+wqg1Kylz3UkB3R7i++AktU36V/PU=:lpxA8Cta59lq4dZCPcX2KVgaNMmKzaheJ9ZNva74hoE=
(1 row)
```
SCRAM-SHA-256
$
4096
:
HQ/MO4C1qFcdRonv2hiG0Q==
$
Cgif0D/DtZQwwQNtOtvDs3LQtTZs6C2mPoKT9bcjbdw=
:
2YD87hpH+x/FudOeFtLQAqVHlwYBo/iCR8nZdhhsP4c=
同样的密码, 它为什么能不一样? 因为有随机salt的加入
模拟加密过程:
```
crypt('pwd', '随机salt1') = res1;
crypt('pwd', '随机salt2') = res2;
```
模拟校验密码过程:
```
res1 = crypt('pwd', res1)
res2 = crypt('pwd', res2)
res1, res2 泄漏无安全风险.
```
例子:
```
postgres=# select crypt('hello 德哥', gen_salt('bf'));
crypt
$2a$06$LpqOUr49S58ooqzfjmTBRu6vI.D2Ann5lOTCzz/FLG7PHJNbVPqBC
(1 row)
postgres=# select crypt('hello 德哥', gen_salt('bf'));
crypt
$2a$06$lj0K8Jjcw3.uEWjito8FO.deLAad0CjLSBsYTO2nYABVnHDSz7YCS
(1 row)
postgres=# select crypt('hello 德哥', gen_salt('bf',10));
crypt
$2a$10$nPoQJv7lPZ5vCZGkX11qUuZ6t6tuR3HfVToT9uPS5/1cCyph3u0La
(1 row)
postgres=# select crypt('hello 德哥', gen_salt('bf',15));
crypt
$2a$15$IoSJ8tY1M0N4WJhQEZhz8uy/FD8o5dN6Muzr9BetMyyrsCN5UxNde
(1 row)
postgres=# select crypt('hello 德哥', gen_salt('bf',15));
crypt
$2a$15$rFB4Yfg4MQjlkAjUmHxyMuUCOigM8GhmSENjfy30uXK5X89zWdiXq
(1 row)
postgres=# select crypt('hello 德哥', '$2a$10$nPoQJv7lPZ5vCZGkX11qUuZ6t6tuR3HfVToT9uPS5/1cCyph3u0La');
crypt
$2a$10$nPoQJv7lPZ5vCZGkX11qUuZ6t6tuR3HfVToT9uPS5/1cCyph3u0La
(1 row)
postgres=# select crypt('hello 德哥', '$2a$15$rFB4Yfg4MQjlkAjUmHxyMuUCOigM8GhmSENjfy30uXK5X89zWdiXq');
crypt
$2a$15$rFB4Yfg4MQjlkAjUmHxyMuUCOigM8GhmSENjfy30uXK5X89zWdiXq
(1 row)
```
scram-sha-256的加密方法, 数据库存储res, 客户端必须提供pwd, 提供res无法校验密码正确性, 所以泄漏res不会影响安全性.
PostgreSQL 许愿链接
您的愿望将传达给PG kernel hacker、数据库厂商等, 帮助提高数据库产品质量和功能, 说不定下一个PG版本就有您提出的功能点. 针对非常好的提议,奖励限量版PG文化衫、纪念品、贴纸、PG热门书籍等,奖品丰富,快来许愿。开不开森.
9.9元购买3个月阿里云RDS PostgreSQL实例
PostgreSQL 解决方案集合
德哥 / digoal's github - 公益是一辈子的事.





