Basic Auth用于服务端简单的登录认证,通常使用服务器Nginx、Apache本身即可完成。比如我们要限定某个域名或者页面必须输入用户名、密码才能登录,但又不想使用后端开发语言,此时Basic Auth就派上用场了。
Basic Auth 使用htpasswd工具进行生成 http 基本认证的密码文件。
流程首先说一下Basic Auth使用流程。
创建认证文件新建一个文件auth_basic_user_file,例如:
# 创建目录 sudo mkdir -p /usr/local/nginx/ # 生成文件 sudo touch /work/yphp/nginx/nginx-htpasswd文件名就是nginx-htpasswd。
生成密码使用htpasswd工具生成密码文件:
# 安装htpasswd sudo apt-get install apache2-utils # 生成密码 sudo htpasswd -c -d /work/yphp/nginx/nginx-htpasswd yujc New password: Re-type new password: Adding password for user yujc # 查看文件内容 cat //work/yphp/nginx/nginx-htpasswd yujc:sBoB9G5lTLvPk这里解释说明一下:
htpasswd 是开源 http 服务器 apache httpd 的一个命令工具,所以本机如果没有该命令,需要先安装。
htpasswd 命令最后一个参数是用户名,也就是需要登录的用户名。命令运行后,会要求输入该用户登录时的密码,这里我输入了123。最终我们发现会往/work/yphp/nginx/nginx-htpasswd文件添加了一行内容。
其中冒号前面的就是用户名,后面是加密的密码。
如果没有htpasswd工具怎么办呢?也可以借助在线的工具生成: 。加密方式选择crypt。点击生成后,把生成结果追加到nginx-htpasswd文件里即可:
cat /work/yphp/nginx/nginx-htpasswd yujc:sBoB9G5lTLvPk yujc2:RF8ulInobr21M大家会发现,相同的密码,每次生成的结果都不一样,没关系,只要密码没变,最终都能登录的。原因在后面再说明。
Nginx配置Basic Auth server { listen 80; server_name test.com; auth_basic "登录认证"; auth_basic_user_file /work/yphp/nginx/nginx-htpasswd; root /mnt/html/www; index index.html index.php; }重启Nginx服务后,访问test.com 就会要求输入用户名、密码。
备注:一定要注意auth_basic_user_file路径,如果文件不存在,会不厌其烦的出现403。
如果只想某一个页面支持Basic Auth,可以将auth_basic配置到location里:
location /test { auth_basic "登录认证"; auth_basic_user_file /work/yphp/nginx/nginx-htpasswd; } htpasswd加密方式MD5:使用MD5加密密码。在Windows, Netware 和TPF上,这是默认的加密方式。
crypt:使用crypt()加密密码。在除了Windows, Netware和TPF的平台上,这是默认的。 虽然它在所有平台上可以为htpasswd所支持, 但是在Windows, Netware和TPF上不能为httpd服务器所支持。
SHA:使用SHA加密密码。 它是为了方便转入或移植到使用LDAP Directory Interchange Format (ldif)的Netscape而设计的。
plain:不加密,使用纯文本的密码。虽然在所有平台上 htpasswd 都可以建立这样的密码, 但是httpd后台只在Windows, Netware和TPF上支持纯文本的密码。
通常我们使用crypt加密方式。如果你使用PHP语言,内置的crypt()函数即可实现加密。
cryptcrypt() 返回一个基于标准 UNIX DES 算法或系统上其他可用的替代算法的散列字符串。
这里以PHP的crypt为例子说明。该函数原型:
string crypt ( string $str [, string $salt ] )salt 参数是可选的。然而,如果没有salt的话,crypt()创建出来的会是弱密码。 php 5.6及之后的版本会在没有它的情况下抛出一个 E_NOTICE 级别的错误。为了更好的安全性,请确保指定一个足够强度的盐值。
我们使用该函数生成密码的hash值,使用不同的salt值:
php > echo crypt("123", "123456"); 12IbR.gJ8wcpc php > echo crypt("123", "abcde"); abLEFxdWWYR3c然后复制到/work/yphp/nginx/nginx-htpasswd:
#yujc:sBoB9G5lTLvPk yujc2:12IbR.gJ8wcpc yujc3:abLEFxdWWYR3c输入123均能登录成功。
注意:测试新用户需要将已登录用户注释掉,无需重启nginx。
为什么验证的时候我们并没有告诉nginx的salt是多少,但是还能验证?为什么同一密码不同salt产生的hash都能验证?
我们看下面的例子:
$ php -a Interactive mode enabled php > echo crypt("123", "12IbR.gJ8wcpc"); 12IbR.gJ8wcpc php > echo crypt("123", "abLEFxdWWYR3c"); abLEFxdWWYR3c php > echo crypt("123", "12test"); 12IbR.gJ8wcpc大家应该发现了什么。我们把加密后的hash当做salt再次使用crypt函数,生成的hash竟然与传入的salt相同。然后我们把salt前2位保持不变,后面的改成其他的,再使用crypt函数,生成的hash没有变化。这说明crypt函数只与salt的前几位有关系:只要前几位不变,生成的hash是一样的。
我们既没有指定使用的算法,也没有指定盐值,crypt是怎么知道使用什么算法和盐值的呢?其实crypt是根据$salt参数来判断使用哪种哈希算法。也就是说,$salt本身就包含了算法的类型以及哈希时实际用到盐值。
实际使用的算法判断有下面这几种情况: