开源软件联盟PostgreSQL分会

利用AI编码增强PostgreSQL密码校验

Image

前言

最近有朋友讲PostgreSQL的密码强度校验太弱了,尽管自带了passwordcheck插件,但还是只能校验简单的场景。

原理简介

passwordcheck密码校验仅支持一些简单场景:

1、密码不能等于用户名
2、密码长度不低于MIN_PWD_LENGTH(默认为8)
3、密码中不能包含用户名
4、密码必须同时包含字母和非字母
5、使用cracklib来校验密码,和cracklib字典设置有关

  1. staticvoid

  2. check_password(constchar*username,

  3. constchar*shadow_pass,

  4. PasswordType password_type,

  5. Datum validuntil_time,

  6. bool validuntil_null)

  7. {

  8. if(prev_check_password_hook)

  9. prev_check_password_hook(username, shadow_pass,

  10. password_type, validuntil_time,

  11. validuntil_null);

  12. if(password_type != PASSWORD_TYPE_PLAINTEXT)

  13. {

  14. /*

  15. * Unfortunately we cannot perform exhaustive checks on encrypted

  16. * passwords - we are restricted to guessing. (Alternatively, we could

  17. * insist on the password being presented non-encrypted, but that has

  18. * its own security disadvantages.)

  19. *

  20. * We only check for username = password.

  21. */

  22. constchar*logdetail = NULL;

  23. /* 密码不能等于用户名 */

  24. if(plain_crypt_verify(username, shadow_pass, username,&logdetail)== STATUS_OK)

  25. ereport(ERROR,

  26. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),

  27. errmsg("password must not equal user name")));

  28. }

  29. else

  30. {

  31. /*

  32. * For unencrypted passwords we can perform better checks

  33. */

  34. constchar*password = shadow_pass;

  35. int pwdlen = strlen(password);

  36. int i;

  37. bool pwd_has_letter,

  38. pwd_has_nonletter;

  39. #ifdef USE_CRACKLIB

  40. constchar*reason;

  41. #endif

  42. /* 密码长度不低于MIN_PWD_LENGTH(默认为8)*/

  43. /* enforce minimum length */

  44. if(pwdlen < MIN_PWD_LENGTH)

  45. ereport(ERROR,

  46. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),

  47. errmsg("password is too short")));

  48. /* 密码中不能包含用户名 */

  49. /* check if the password contains the username */

  50. if(strstr(password, username))

  51. ereport(ERROR,

  52. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),

  53. errmsg("password must not contain user name")));

  54. /* check if the password contains both letters and non-letters */

  55. pwd_has_letter =false;

  56. pwd_has_nonletter =false;

  57. for(i =0; i < pwdlen; i++)

  58. {

  59. /*

  60. * isalpha() does not work for multibyte encodings but let's

  61. * consider non-ASCII characters non-letters

  62. */

  63. if(isalpha((unsignedchar) password[i]))

  64. pwd_has_letter =true;

  65. else

  66. pwd_has_nonletter =true;

  67. }

  68. /* 密码必须同时包含字母和非字母 */

  69. if(!pwd_has_letter ||!pwd_has_nonletter)

  70. ereport(ERROR,

  71. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),

  72. errmsg("password must contain both letters and nonletters")));

  73. #ifdef USE_CRACKLIB

  74. /* call cracklib to check password */

  75. if((reason =FascistCheck(password, CRACKLIB_DICTPATH)))

  76. ereport(ERROR,

  77. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),

  78. errmsg("password is easily cracked"),

  79. errdetail_log("cracklib diagnostic: %s", reason)));

  80. #endif

  81. }

  82. /* all checks passed, password is ok */

  83. }

被吐槽了,这个密码安全性校验也太差了?连个字母大小写都没判断?
我给朋友说改插件呗,源码都在手里了,你想怎么改就怎么改,这就是PG的优势。

代码实现

刚好有空,自己想在之前的功能基础上实现一下校验密码同时包含大小写字母。突然想到AI不是挺猛吗,让AI来写一下试试水。

输入一句“C语言,判断一个字符串是否同时包含大小写字母”,隔了几秒就出结果了,不仅给了函数定义,还给了解释和注意事项。
Image

函数定义

  1. bool contains_both_cases(constchar*str);

  2. /* check if the password contain both uppercase and lowercase letters */

  3. bool

  4. contains_both_cases(constchar*str)

  5. {

  6. bool has_upper =false, has_lower =false;

  7. for(int i =0; str[i]; i++){

  8. if(isupper((unsignedchar)str[i])){

  9. has_upper =true;

  10. }

  11. if(islower((unsignedchar)str[i])){

  12. has_lower =true;

  13. }

  14. if(has_upper && has_lower){

  15. returntrue;

  16. }

  17. }

  18. returnfalse;

  19. }

在check_password函数中调用,进行大小写字母校验

  1. staticvoid

  2. check_password(constchar*username,

  3. constchar*shadow_pass,

  4. PasswordType password_type,

  5. Datum validuntil_time,

  6. bool validuntil_null)

  7. {

  8. /* 省略部分代码行 */

  9. #ifdef USE_CRACKLIB

  10. /* call cracklib to check password */

  11. if((reason =FascistCheck(password, CRACKLIB_DICTPATH)))

  12. ereport(ERROR,

  13. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),

  14. errmsg("password is easily cracked"),

  15. errdetail_log("cracklib diagnostic: %s", reason)));

  16. #endif

  17. /* check if the password contain both uppercase and lowercase letters */

  18. if(!contains_both_cases(password))

  19. ereport(ERROR,

  20. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),

  21. errmsg("password must contain both uppercase and lowercase letters")));

  22. }

  23. /* all checks passed, password is ok */

  24. }

重新编译passwordcheck,重启数据库。

测试验证

进行用户密码校验,可以看到已经可以校验密码是否同时包含大小写字母。
当然也可以继续加入必须包含特殊字符校验,感兴趣的朋友可以自行修改。

  1. postgres=# create user testuser password '123';

  2. ERROR: password is too short

  3. postgres=# create user testuser password '12345678';

  4. ERROR: password must contain both letters and nonletters

  5. postgres=# create user testuser password 'testuser';

  6. ERROR: password must not contain user name

  7. postgres=# create user testuser password '1234qwer';

  8. ERROR: password must contain both uppercase and lowercase letters

  9. postgres=# create user testuser password '1234Qwer';

  10. CREATE ROLE

  11. postgres=#

小结

AI确实可以辅助我们提高工作效率,我们这里是一个极其简单的demo,当然对于复杂的业务逻辑来说AI目前不一定能够很好的实现。
不过已经能够预感到等后续发展到一定程度后,对部分工作种类来说可能会产生“革命性”的影响。

ImageImage