眾所周知,Web使人們可以很方便的訪問分布在世界各個角落里信息。但是僅僅是方便還是不夠的,並不是所有的信息都適合在互聯網上公開訪問,我們需要保證只有特定的人才能看到我們的敏感信息並且執行特定的操作。
服務器需要通過某種方式了解訪問用戶的身份。一旦服務器知道了用戶身份,就可以判斷用戶可以訪問的事務和資源了。認證意味着要證明客戶端訪問用戶是誰。通常情況是通過提供用戶名和密碼來認證的。HTTP為我們提供了一些原生的工具。今天我們來看下基本認證。
HTTP質詢/響應認證框架
HTTP提供了一個原生的質詢/響應框架,簡化了對用戶的認證過程。HTTP的認證模型如圖所示。
Web服務器接收到一條HTTP請求報文時,服務器沒有直接響應請求的資源,而是以一個“認證質詢”進行響應,要求用戶提供一些保密信息來說明其身份。用戶再次發起請求時,要附上保密證書(用戶名和密碼)。如果與要求的不匹配,服務器可以再次質詢客戶端,或者產生一條錯誤信息。如果證書匹配則返回請求的資源。
認證協議與首部
- HTTP提供可定制的控制首部,為不同的認證協議提供了一個可擴展框架。
- HTTP提供了兩個認證協議:基本認證和摘要認證。
基本認證實例
- 客戶端請求某資源。
- 服務器對用戶進行質詢時,會返回一條401Unauthorized響應,並在WWW-Authenticate首部中說明可以使用的認證方式。
- 客戶端重新發送請求,並在Authorization首部附加上用戶名、密碼等其他一些認證參數。
- 授權成功完成后,服務器會返回一個正常的狀態碼(比如,200 OK),對於高級算法來說,可能還會在Authentication-Info首部附加額外的信息。
HTTP基本認證將用戶名和密碼打包在一起,並使用base-64編碼方式對其進行編碼。具體過程如下圖所示。
基本認證的安全缺陷
- 基本認證通過網絡發送用戶名和密碼,雖然進行base-64編碼可以隱藏用戶名和密碼,但是很容易通過反向編碼過程進行解碼。
- 即使密碼以更加難以解碼的方式加密,第三方用戶仍然可以捕獲被修改過的用戶名和密碼,並通過重放攻擊獲取服務器的訪問權限。
- 很多用戶會將不同的服務使用相同的用戶名和密碼,基本認證直接發送用戶名和密碼,會對一些重要的服務(比如在線銀行網站)造成威脅。
- 基本認證沒有提供任何針對代理和中間人節點的防護措施,他們沒有修改認證首部,但卻修改了報文的其余部分,這樣就嚴重的改變了事務的本質。
- 假冒服務器很容易騙過基本認證。如果在用戶實際鏈接到一台惡意服務器或者網關的時候,能夠讓用戶相信他鏈接的是一個受基本認證保護的合法主機,攻擊者就可以請求用戶輸入密碼。
- IIS中站點默認開啟匿名身份驗證,並可以直接訪問。
基本認證實例
- IIS中站點默認開啟匿名身份驗證,並可以直接訪問
2. 關閉匿名認證,開啟基本認證方式,直接訪問需要輸入用戶名密碼


3.客戶端模擬基本認證過程
控制台模擬代碼如下
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication_HttpSec
{
class Program
{
static void Main(string[] args)
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri("HTTP://Localhost"));
request.Method = "Get";
WebResponse response = null;
try
{
response = request.GetResponse();
}
catch (WebException ex)
{
Console.WriteLine("訪問發生異常,異常信息如下:"+ ex.Message);
Console.WriteLine("異常信息返回的質詢響應頭為:");
foreach (string key in ex.Response.Headers.Keys)
{
Console.WriteLine(" "+ key +":"+ex.Response.Headers[key]);
}
Console.WriteLine("添加Authorization認證頭部並重新發送請求");
HttpWebRequest request2 = (HttpWebRequest)HttpWebRequest.Create(new Uri("HTTP://Localhost"));
request2.Method = "Get";
request2.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes("administrator:P@ssword")));
try
{
response = request2.GetResponse();
}
catch (WebException ex2)
{
Console.WriteLine("添加Authorization認證頭部並重新發送請求發生異常:"+ex2.Message);
Console.Read();
return;
}
Stream stream = response.GetResponseStream();
System.IO.StreamReader reader = new StreamReader(stream);
string content = reader.ReadToEnd();
Console.WriteLine("請求響應的內容如下");
Console.WriteLine(content);
}
Console.Read();
}
}
}

