Basic Auth用於服務端簡單的登陸認證,一般使用服務器Nginx、Apache自己便可完成。好比咱們要限定某個域名或者頁面必須輸入用戶名、密碼才能登陸,但又不想使用後端開發語言,此時Basic Auth就派上用場了。php
Basic Auth 使用htpasswd工具進行生成 http 基本認證的密碼文件。html
首先說一下Basic Auth使用流程。vue
新建一個文件auth_basic_user_file
,例如:nginx
# 建立目錄 sudo mkdir -p /usr/local/nginx/ # 生成文件 sudo touch /work/yphp/nginx/nginx-htpasswd
文件名就是nginx-htpasswd
。算法
使用htpasswd工具生成密碼文件:shell
# 安裝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 的一個命令工具,因此本機若是沒有該命令,須要先安裝。apache
htpasswd 命令最後一個參數是用戶名,也就是須要登陸的用戶名。命令運行後,會要求輸入該用戶登陸時的密碼,這裏我輸入了123。最終咱們發現會往/work/yphp/nginx/nginx-htpasswd
文件添加了一行內容。segmentfault
其中冒號前面的就是用戶名,後面是加密的密碼。後端
若是沒有htpasswd工具怎麼辦呢?也能夠藉助在線的工具生成:http://tool.oschina.net/htpasswd 。加密方式選擇crypt。點擊生成後,把生成結果追加到nginx-htpasswd文件裏便可:安全
cat /work/yphp/nginx/nginx-htpasswd yujc:sBoB9G5lTLvPk yujc2:RF8ulInobr21M
你們會發現,相同的密碼,每次生成的結果都不同,不要緊,只要密碼沒變,最終都能登陸的。緣由在後面再說明。
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; }
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()
函數便可實現加密。
crypt() 返回一個基於標準 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
自己就包含了算法的類型以及哈希時實際用到鹽值。
實際使用的算法判斷有下面這幾種狀況:
php > echo crypt("123", "t123"); t1ZzgDe4z3qWE php > echo crypt("123", "123"); 12IbR.gJ8wcpc php > echo crypt("123", "t"); *0
_
開頭,後面緊接着4字節的迭代次數和4字節的鹽值。也就是取前9位,後面是什麼值無所謂。php > echo crypt("123", "_12345678"); _12345678VaI36zUn7Jk php > echo crypt("123", "_12345678t"); _12345678VaI36zUn7Jk php > echo crypt("123", "_testtest"); _testtest4v7fH1Er0Ng php > echo crypt("123", "_testtest1"); _testtest4v7fH1Er0Ng
$1$
開頭,而後是12個字符之內的鹽值。只要前12位相同,生成的hash相同。php > echo crypt("123", '$1$'); $1$$GmbL3iXOMZR57QuGDLv.L1 php > echo crypt("123", '$1$2'); $1$2$WOzAAwhejT62wplMg6rEE1 php > echo crypt("123", '$1$23'); $1$23$0ZjnChzzaj90xZQJQKHFS1 php > echo crypt("123", '$1$123456789'); $1$12345678$tRy4cXc3kmcfRZVj4iFXr/ php > echo crypt("123", '$1$1234567890'); $1$12345678$tRy4cXc3kmcfRZVj4iFXr/
注意:PHP裏雙引號裏面的字符串若是包含
$
會被認爲是變量。
$2a$
、$2x$
或者$2y$
開頭,而後是用於cost參數的兩位數字,緊接着一個$字符,最後是22位./0-9A-Za-z範圍裏的字符。php > echo crypt("123", '$2a$07$usesomesillystringforsalt$'); $2a$07$usesomesillystringforeN7/2NBfGxbAuv02IPrTFBImFJd5PJ1m php > echo crypt("123", '$2a$07$usesomesillystringforsalt$1'); $2a$07$usesomesillystringforeN7/2NBfGxbAuv02IPrTFBImFJd5PJ1m
使用這個算法的時候,
$str
最長支持72個字符,超過會被截掉。
$5$
開頭,而後是16個字符的鹽值,鹽值以前還可使用rounds=
php > echo crypt("123", '$5$rounds=5000$usesomesillystringforsalt$'); $5$rounds=5000$usesomesillystri$BYJncGl82VuZ6T61c4wSpXT.xoDSuz9aF4JyE9F08U4
rounds的默認值爲5000,範圍是1000到999,999,999,若是N不在這個範圍裏,會被截取到最接近的範圍裏。
$6$
開頭,而後是16個字符的鹽值,鹽值以前還可使用rounds=
php > echo crypt("123", '$6$rounds=5000$usesomesillystringforsalt$'); $6$rounds=5000$usesomesillystri$YPNvueKNHmPrzbloaqIomo1gPrVo8aLnqwrKlhlfThu2wzo73efrh/FCR4CAUf/GFe7gF6vuLWTMyFNb7jfnT1
rounds的默認值爲5000,範圍是1000到999,999,999,若是N不在這個範圍裏,會被截取到最接近的範圍裏。
PHP裏咱們使用crypt函數,salt直接傳第一個參數的base64_encode便可:
$hashed_password = crypt ( 'mypassword', base64_encode('mypassword') );
一、Nginx配置Basic Auth登陸認證 - 簡書
https://www.jianshu.com/p/b4a78af4e266
二、PHP筆記 —— crypt方法 - 我的文章 - SegmentFault 思否
http://www.javashuo.com/article/p-ztkcwooa-kn.html
三、PHP: crypt - Manual
http://php.net/manual/zh/function.crypt.php