Linux 用户认证(crypt方式)
来源:互联网 发布:部落冲突石头升级数据 编辑:程序博客网 时间:2024/04/26 20:30
最近做的一些开发和Linux用户有密切的关系,以前没有做过相关的学习,仅仅停留在使用shell下的useradd, passwd命令,但对用户的认证及密码的管理基本没有了解。在这里做个小结。
1. 第一个重要文件/etc/passwd
例:/etc/passwd中的一行
rwan:x:1000:1000:Robin:/home/rwan:/bin/bash
包含七个字段,各个字段间用冒号隔开(用户名:密码:用户id:组id:用户描述:用户家目录:用户的登录shell)
POSIX.1 定义了两个接口获取用户口令文件
#include <pwd.h>struct passwd *getpwuid(uid_t uid); //通过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/passwd中的所有密码都是个x?
在最早的Unix系统中,用户密码确实存放在/etc/passwd,但为了安全,后来把密码存放在/etc/shadow中,
因为/etc/paasswd对所有用户都是可读的,如果密码放在这里,会被暴力破解,而/etc/shadow只有root用户可读写和
shadow组用户可读(这里不同发行版可能不同,Fedora中/etc/shadow只有root可只读,此处测试在Ubuntu下)。
root@localhost:/home/rwan# ls -l /etc/passwd-rw-r--r-- 1 root root 1371 2009-08-29 05:05 /etc/passwdroot@localhost:/home/rwan# ls -l /etc/shadow-rw-r----- 1 root shadow 878 2009-08-29 05:05 /etc/shadow
2.第二个重要文件/etc/shadow
例:/etc/shadow中的一行
rwan:$1$TA.EyKcB$GMnqWwkKY9cr8667xIwXE0:14574:0:99999:7:::
包含九项内容(用户登录名:加密口令:之后的几项用于控制口令改动频率及账户活动状态情况)。
而在/etc/shadow中大致有三种情形,密码项为*,!,或一个字符串,分别表示禁止账户登录,密码未设置,及加密后的密码。
使用useradd添加一个新用户,就会发现该用户的的密码项为!
例:添加一个无密码用户
root@localhost:/home/rwan# useradd testroot@localhost:/home/rwan# cat /etc/passwd |grep testtest:x:1001:1002::/home/test:/bin/shroot@localhost:/home/rwan# cat /etc/shadow | grep testtest:!:14574:0:99999:7:::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; //密码 ……}
3. 登录过程中如何进行密码比对
为了提高安全性,Linux引入了salt,所谓的salt,即为一个随机数,引入的时候为一个12-bit的数值,
当用户设置密码时,会随机生成一个salt,与用户的密码一起加密,得到一个加密的字符串(salt以明文形式包含在该字符串中),
存储到密码文件中,这样就将攻击的难度扩大了212即4096倍。crypt将用户的key和salt一起适应某种算法进行加密(散列)
#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
例:一个小程序
首先给刚才新建的用户test设置密码123456,
root@localhost:/home/rwan# passwd testroot@localhost:/home/rwan# cat /etc/shadow | grep testtest:$1$svja5yi5$nGAXQLRtqM454THCcBv/50:14574:0:99999:7:::可以看到,Ubuntu采用的是Md5认证,salt = $1$svja5yi5$, 密钥 = nGAXQLRtqM454THCcBv/50可以用下面的程序来试验。#include <stdio.h>#include <stdlib.h>#include <string.h>void main(){ char *salt = "$1$svja5yi5"; printf("user test's secrect key = %s /n",crypt("123456", salt));}root@localhost:/home/rwan# gcc -o user.o user.c -lcryptroot@localhost:/home/rwan# ./user.ouser test's secrect key = $1$svja5yi5$nGAXQLRtqM454THCcBv/50
呵呵。不错吧。和/etc/shadow中的一模一样吧,废话,不一样的话,出大问题了。
那么Linux是如何认证用户密码的,应该是用户输入密码后,login程序从/etc/shadow中获得该用户的salt,
并计算密钥,和/etc/shadow中的比对,有了上面的struct spwd* getspnam(const char *name)函数,想模拟写个也不难。
4.更多思考
既然/etc/shadow只有root可写,那为什么普通用户可以修改自己的密码?
这里有一个suid的概念,什么意思呢?
root@localhost:/home/rwan# ls -l /usr/bin/passwd-rwsr-xr-x 1 root root 29104 2006-12-19 15:35 /usr/bin/passwd
所有用户对passwd命令均有可执行权限,注意里面的那个s,是说如果你有执行权限,那么运行该程序的时间,会以文件属主的权限执行。
5.别走开,我们可以走的更远
学习下怎么制造salt吧。
以下代码摘自busybox。
#include <stdio.h>#include <unistd.h>static int i64c(int i){ i &= 0x3f; if (i == 0) return '.'; if (i == 1) return '/'; if (i < 12) return ('0' - 2 + i); if (i < 38) return ('A' - 12 + i); return ('a' - 38 + i);}int crypt_make_salt(char *p, int cnt, int x){ x += getpid() + time(NULL); do { /* x = (x*1664525 + 1013904223) % 2^32 generator is lame * (low-order bit is not "random", etc...), * but for our purposes it is good enough */ x = x*1664525 + 1013904223; /* BTW, Park and Miller's "minimal standard generator" is * x = x*16807 % ((2^31)-1) * It has no problem with visibly alternating lowest bit * but is also weak in cryptographic sense + needs div, * which needs more code (and slower) on many CPUs */ *p++ = i64c(x >> 16); *p++ = i64c(x >> 22); } while (--cnt); *p = '/0'; return x;}void main() { int rnd = rnd; //use uninitialized data to generate random digital char salt[sizeof("$N$XXXXXXXX")]; strcpy(salt, "$1$"); rnd = crypt_make_salt(salt + 3, 4, rnd); printf("slat = %s/n", salt); printf("secret key = %s/n", crypt("123456", salt));}root@localhost:/home/rwan# gcc -o user2.o user2.c -lcryptroot@localhost:/home/rwan# ./user2.oslat = $1$rTWCKgPtsecret key = $1$rTWCKgPt$pIvnCsr3wAOw8XrJ9SQug1
思想:目的是生成8个随机字符作为salt。对着ASCII表,去理解吧。
因为ASCII码中有很多字符时不可打印字符,为了让加密过的密码看起来像普通的字符串,系统使用了一种叫base64的编码,
将散列后的结果转化为可打印字符。base64的基本思想,base64的字符集为A-Za-z0-9/.- Linux 用户认证(crypt方式)
- 用户认证方式总结
- Linux用户认证机制
- cisco交换机用户认证方式
- oracle用户身份认证方式
- Linux-PAM认证方式
- Linux-PAM认证方式
- Linux-PAM认证方式
- Linux-PAM认证方式
- linux 认证方式
- Linux Examples: dm-crypt
- linux crypt函数
- 用户认证(一)
- WOW用户认证的方式-SRP
- oracle两种用户认证方式
- openfire采用LDAP方式认证用户
- oracle两种用户认证方式
- linux 统一认证方式实现
- MYSQL命令大全
- 那些伤感的记忆
- Shell简单全备mysql脚本案例
- android Theme level 11 使用总结
- 解决 WIN7消息队列安装错误
- Linux 用户认证(crypt方式)
- python map和reduce的用法
- ALV细节
- Android开发之Handler详解
- 复杂的C运行时库
- dwr无刷新分页
- 一道笔试题的思考(二)
- OpenScales 学习和介绍——地图是如何组成的
- django官方文档——模型字段关系参考