资讯专栏INFORMATION COLUMN

nginx basic auth配置踩坑记

canger / 1918人阅读

摘要:的配置由模块提供,对协议进行了支持,用户可通过该配置设置用户名和密码对站点进行简单的访问控制。其中指的是加密算法,支持的有算法。

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 
*/
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支持的对密码加密的字符串。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/40002.html

相关文章

  • Notadd 2.0 全新 Node.js 版本~ (开发中) [从 PHP 到 node 的坑记

    摘要:有着最全的协议支持,同时有各种非阻塞拓展,可以说是最符合要求的,但是异步需要对做很大的改动。的计划将基于开发,同时也提供一些无法提供的功能和特性。 一点小遗憾 对于 Notadd 我们本来期望它实现更多... 尽管我们也尝试做了很多努力,但是由于 PHP 本身的局限,以及考虑到开发环境配置的复杂程度,最终使用了折中方案。接下来,我们谈谈整个技术选型历程,也供今后相关开发者做借鉴和参考:...

    Tonny 评论0 收藏0
  • 利用阿里云 OSS 搭建私有 Docker 仓库

    摘要:前言最近开始研究的应用,于是打算搭建一个私有的仓库,并使用阿里云的作为存储引擎。登陆成功后,执行以下命令即可上传配置阿里云首先在刚才执行的命令行窗口中按退出服务。待上传完毕,可以打开阿里云的控制台界面检查文件是否被正确上传上去了。 前言 最近开始研究 Docker 的应用,于是打算 搭建一个私有的 Docker 仓库,并使用阿里云的 OSS 作为存储引擎 。从网上搜索到的资料大都是比较...

    haoguo 评论0 收藏0
  • Nginx 层面配置基础用户验证

    摘要:配置进行基础用户验证使用指令指定设置受保护区域的名称,此名称会显示在账号密码弹窗上,使用指令设置带有账户密码信息的路径。例如配置此外,如果某个区块不想继承整个认证体系,可以在区块内设置即用户认证关闭状态。通过和身份验证将限制与指令相结合。 原文链接: 何晓东 博客 应用场景:大概是在内部网站需要外部用户访问到,同时不能给访问者网站账号权限,所以在 nginx 层面进行限制。例如外包项目...

    lentrue 评论0 收藏0
  • webpack4 坑记

    最近偶然想学习下webpack的配置,于是走上了webpack4踩坑的不归路。。。 webpack4默认的特性: 配置默认初始化一些配置, 比如 entry 默认 ./src 开发模式和发布模式, 插件默认内置 CommonsChunk 配置简化 使用 ES6 语法,比如 Map, Set, includes 新增 WebAssembly 构建支持 如果要使用 webpack cli 命令,...

    lookSomeone 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<