免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1310 | 回复: 0
打印 上一主题 下一主题

linux用户认证 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-10-23 14:52 |只看该作者 |倒序浏览

    花了点时间研究了一下linux的密码认证机制,当系统启动出现login时,用户登录的过程是如何得到验证的。

首先linux系统里管理用户及密码的两个重要的文件,/etc/passwd, /etc/shadow。

/etc/passwd包含各个用户的信息,linux平台包含七个字段,各个字段间用冒号隔开,分别是:
用户名:密码:用户id:组id:用户描述:用户家目录:用户的登录shell

POSIX.1 定义了两个获取用户口令文件

#include pwd.h>
struct passwd *getpwuid(uid_t uid); //通过inode中的uid映射为登录名,获取密码项
struct passwd *getpwnam(const char *name); //通过用户名获取密码项
struct passwd
{
     char *pw_name; //用户名
     char *pw_passwd; //用户密码
     uid_t pw_uid; //用户id
     uid_t pw_gid; //用户组id
     char *pw_gecos; //用户描述
     char *pw_dir; //用户家目录
     char *pw_shell; //用户登录shell
};
要查看整个口令文件,POSIX.1接口则不能满足要求,需使用下列接口
#include pwd.h>
struct passwd *getpwent(); //返回口令记录的下一项
void setpwent(); //定位到开头,即从第一项开始读
void endpwent(); //读取结束,关闭

/etc/shadow包含用户的密码信息,在linux中包含九项内容,分别是:
用户登录名:加密口令:之后的几项用于控制口令改动频率及账户活动状态情况
Linux中提供了类似读取/etc/passwd的接口

#include shadow.h>
struct spwd* getspnam(const char *name);
struct spwd* getspent();
void setspent();
void endspent();
struct spwd
{
      Char *sp_namp; //用户名
      Char *sp_pwdp; //密码
     ……..
}

/etc/passwd, /etc/shadow中的密码项到底是怎么回事?
早先linux密码放在/etc/passwd项,出于安全考虑,后将密码移到/etc/shadow,而在/etc/passwd第二项以x作为标记。而在/etc/shadow中大致有三种情形,密码项为*,!!,或一个字符串,分别表示禁止账户登录,密码未设置,及加密后的密码。
使用useradd添加一个新用户,就会发现该用户的的密码项为!!。

用户密码如何产生,/etc/passwd的字符串含义是?
      最初linux将用户的密码通过某种one-way function得到一个散列(加密)后的字符串,并存储该字符串在密码文件中,但这种方式易遭受字典攻击,攻击者只有准备好字典,使用相同的one-way function计算出对应的值,逐个对比就ok就可以攻破。
为了提高安全性,引入salt,所谓的salt,即为一个随机数,引入的时候为一个12-bit的数值,当用户设置密码时,会随机生成一个salt,与用户的密码一起加密,得到一个加密的字符串(salt以明文形式包含在该字符串中),存储到密码文件中,这样就将攻击的难度扩大了212即4096倍。

crypt将用户的key和salt一起适应某种算法进行加密(散列)
   
#define _XOPEN_SOURCE
#inclue stdlib.h>
char *crypt(const char *key, const char *salt);

crypt中可以使用多种加密(散列)机制,包括最初的DES,还有后来为提高安全性引入的md5,blowfish,sha-256,sha-512.
crypt为支持不同的方式,将salt进行格式化,格式为:
$id$salt$encoded (这也是保存在密码文件中的格式)
这里不同id代表不同的算法,不同算法salt的长度也不同。

Id
Method
实际加密后的密码长度
1
MD5(12个salt字符)
22
2a
Blowfish

5
SHA-256(12个salt字符)
43
6
SHA-512(12个salt字符)
86

而最初的DES方式的salt为2个字符(A-Za-z0-9/+)提供了64*64=4096种可能性。
然后将用户key与salt拼接成一个新的字符串,用这个字符串作为密钥对某个原始串(通常为全0)进行DES加密,得到11个字符,然后将这11个字符接到salt后面即为用户加密后的密码。

如何验证某个用户的密码?
1,  根据用户名调用getspnam获取对应的spwd项。
2,  根据不同salt(长度不同),从spwd->sp_pwdp中获取salt的值
3,  根据用户传递来的key和salt的值,调用crypt(key,salt)得到加密后的值encoded_str
4,  将encoded_str与spwd->sp_pwdp进行对比,如果相等,则通过验证。

我的系统中密码的格式为:
$6$MLjJx2Ga$Rf36llsl8zknJUI8RYg6.U6T8BfdAp5fCfL0cFQkMoj7ZC5egPK85OhR    JG9kki16TVmDcGh1BrQ20I3tZp35S0
前面的部分为salt,后面的部分为加密后的密码。

由$6$可以知道,crypt使用sha-512算法。
#include stdio.h>
#include shadow.h>
#include stdlib.h>
#include string.h>
#define SALT_LEN 12
int main(int argc, char **argv)
{
    struct spwd *sp;
    char salt[SALT_LEN+1];
    sp = getspnam(argv[1]);
    if(sp == NULL)
    {
        printf("get spentry error\n");
        return -1;
    }
    strncpy(salt, sp->sp_pwdp, SALT_LEN);
    salt[SALT_LEN] = 0;
    if(strcmp(sp->sp_pwdp, (char*)crypt(argv[2], salt)) == 0)
        {
        printf("yes\n");
    }
    else
    {
        printf("no\n");
    }
    return 0;   
}
#gcc –o user user.c –lcrypt
#./user ydzhang a  //ydzhang的密码为a,输出为yes,需要有root权限
为什么SHA-512得到的结果是86个字符,不是512/8=64个字符吗?
因为ASCII码中有很多字符时不可打印字符,为了让加密过的密码看起来像普通的字符串,系统使用了一种叫base64的编码,将散列后的结果转化为可打印字符。
base64的基本思想,base64的字符集为A-Za-z0-9/+
base64将原始串每3个八位字节,先整理成4个6位形式(6位表示的范围0-63,与base64的集合大小一样),然后在每个6位前补两个0,得到4个8位的形式。
例如00111100 01010101 10101010—》000011111 00000101 00010110 00101010
如果原始串的字节数不能被3整除,base64推荐的方法是补0至能整除,后面的每6个0用一个“=”表示,但crypt不是这么做的。
以SHA-512为例,生成64字节的字符串,64除3余数为1,按照base64 =号补全的方法,应该得到长度为88的串,且以两个=号结束,而世界上长度为86字节。
个人猜测crypt的处理方式为:以余一个字节的情况为例,00110011 直接转化为00001100 00000011(前补0) 或者是 00001100 00110000(后补0),我看了root和ydzhang两个账户的末尾字符,分别是/ 和 0,所以在后面补0的可能性较大,而且处理也简单下,直接左移位即可。
另外每看过crpyt的代码,内部对salt和key的拼接方式,和base64的转化方式都不能确定,所以我直接通过拼接salt和key,并通过openssl的sha512工具验证没有成功。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/87570/showart_2076670.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP