当前位置 主页 > 服务器问题 > nginx问题汇总 > 最大化 缩小

    详解nginx basic auth配置踩坑记

    栏目:nginx问题汇总 时间:2019-03-10 16:38

    本篇文章主要介绍了详解nginx basic auth配置踩坑记,nginx的basic auth配置由ngx_http_auth_basic_module模块提供,对HTTP Basic Authentication协议进行了支持,感兴趣的小伙伴们可以参考一下

    nginx的basic auth配置由ngx_http_auth_basic_module模块提供,对HTTP Basic Authentication协议进行了支持,用户可通过该配置设置用户名和密码对web站点进行简单的访问控制。

    basic auth配置示例:

    location / {  auth_basic      "closed site";  auth_basic_user_file conf/htpasswd;}

    说明:

    auth_basic可设置为off或其它字符串,为off时表示不开启密码验证 auth_basic_user_file 为包含用户名和密码的文件,文件内容如elastic:YsEm9Tb4.RwB6

    踩坑的地方就是这个密码,官方文档里对支持的密码类型进行了说明:

    采用系统函数crypt()加密的密码;可通过htpasswd命令或者openssl passwd命令生成 通过Apache提供的基于MD5的变种加密算法(apr1),同样可通过htpasswd或者openssl passwd命令生成 以“{scheme}data”格式表示的加密后的密码,RFC 2307中有对该格式的密码标准进行了说明。其中scheme指的是加密算法,nginx支持的scheme有PLAIN, SHA,SSHA算法。

    使用htpasswd或者openssl passwd命令生成的密码固然可以使得配置生效,nginx能够正常地进行密码安全校验,如果密码类型不支持, 则nginx或报错:

    crypt_r() failed (22: Invalid argument)

    但是因为业务的需要,我们要用代码生成nginx的配置并下发配置到每个云主机中,之后拉起nginx进程。项目代码使用go语言编写,所以需要找一个对应的函数或者库生成nginx支持的密码。

    go语言生成nginx支持的密码

    在进行自动生成密码开发之前,思考了一下大概有三种方案可以实现:

    项目服务器上安装htpasswd工具或openssl, 通过代码执行本地命令生成加密密码 直接调用Linux系统函数crypt()加密密码 使用go标准库crypto加密密码

    首先,第一种方式是不太可取的,因为需要强依赖服务器环境,所以直接pass。下面看第二种和第三种方式的具体实现。

    直接调用系统函数crypt()

    Linux的crypt函数有两个参数,函数定义为:

    char *crypt(const char *key, const char *salt);

    其中参数key为需要加密的内容,salt参数有两种类型:

    长度为2的字符串,取值范围为[a-zA-Z0-9./],如果超过两位会被忽略,并且只能支持最长8位的key,如果key超过8位,则8位之后的会被忽略 $id$salt$encrypted 格式,用于支持其它的加密算法, id表示算法类型,具体取值有:
    ID | Method  ─────────────────────────────────────────────  1  | MD5  2a | Blowfish (not in mainline glibc; added in some    | Linux distributions)  5  | SHA-256 (since glibc 2.7)  6  | SHA-512 (since glibc 2.7)

    go语言中可以通过import "C"方式直接调用c语言的库函数,下面是封装crypt函数的具体实现:

    package crypt/*#define _GNU_SOURCE#include <unistd.h>*/import "C"import (  "sync"  "unsafe")var (  mu sync.Mutex)func Crypt(pass, salt string) (string, error) {  c_pass := C.CString(pass)  defer C.free(unsafe.Pointer(c_pass))  c_salt := C.CString(salt)  defer C.free(unsafe.Pointer(c_salt))  mu.Lock()  c_enc, err := C.crypt(c_pass, c_salt)  mu.Unlock()  if c_enc == nil {    return "", err  }  defer C.free(unsafe.Pointer(c_enc))  return C.GoString(c_enc), err}