nginx的basic auth配置由ngx_http_auth_basic_module模塊提供,對HTTP Basic Authentication協議進行了支持,用戶可經過該配置設置用戶名和密碼對web站點進行簡單的訪問控制。nginx
basic auth配置示例:web
location / { auth_basic "closed site"; auth_basic_user_file conf/htpasswd; }
說明:算法
踩坑的地方就是這個密碼,官方文檔裏對支持的密碼類型進行了說明:安全
使用htpasswd或者openssl passwd命令生成的密碼當然可使得配置生效,nginx可以正常地進行密碼安全校驗,若是密碼類型不支持, 則nginx或報錯:服務器
crypt_r() failed (22: Invalid argument)
可是由於業務的須要,咱們要用代碼生成nginx的配置並下發配置到每一個雲主機中,以後拉起nginx進程。項目代碼使用go語言編寫,因此須要找一個對應的函數或者庫生成nginx支持的密碼。函數
在進行自動生成密碼開發以前,思考了一下大概有三種方案能夠實現:工具
首先,第一種方式是不太可取的,由於須要強依賴服務器環境,因此直接pass。下面看第二種和第三種方式的具體實現。測試
Linux的crypt函數有兩個參數,函數定義爲:加密
char *crypt(const char *key, const char *salt);
其中參數key爲須要加密的內容,salt參數有兩種類型:code
$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標準庫中的函數對密碼進行加密。
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支持的對密碼加密的字符串。