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 }
生成密码的具体实现:
func main() { des, err := crypt.Crypt("Elastic123", "in") if err != nil { fmt.Errorf("error:", err) return } sha512, err := crypt.Crypt("Elastic123", "$6$SomeSaltSomePepper$") if err != nil { fmt.Errorf("error:", err) return } fmt.Println("des:", des) fmt.Println("SHA512:", sha512) }
经过实测,上述通过调用crypt函数生成nginx支持的加密密码实际可用,但是需要注意的是如果密码长度超过8位,则salt参数只能选择$id$salt$encrypted类型,在测试过程中就是因为踩了这点坑导致nginx只能校验密码的前8位,无语。
因为在编写go代码过程中调用了C函数库,这种方式也需要依赖服务器所处环境,因此最好的方式是采用go标准库中的函数对密码进行加密。
使用crypto函数库
go的crypto标准库封装了很多中加密算法,采用SHA加密算法进行密码加密的代码如下:
package util import ( "crypto/sha1" "encoding/base64" ) func GetSha(password string) string { s := sha1.New() s.Write([]byte(password)) passwordSum := []byte(s.Sum(nil)) return base64.StdEncoding.EncodeToString(passwordSum) }
测试过程中通过调用GetSha()函数生成了对密码加密的字符串,但是直接配置在nginx的conf/htpasswd文件中,reload nginx配置后测试验证密码是否生效,结果还是报错,原来如前文所述,SHA加密的密码必须带有“{SHA}”前缀才可以,再次修改配置后经过验证,成功地用代码生成了nginx支持的对密码加密的字符串。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新动态
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]