HTTP Digest 認證:原理剖析與服務端實現詳解

HTTP Digest 認證:原理剖析與服務端實現詳解

HTTP 協議中的 Digest 認證(摘要認證)是一種比 Basic 認證更安全的身份驗證機制,其核心設計是避免密碼明文傳輸,并通過動態隨機數(Nonce)防范重放攻擊。本文將結合標準協議流程與具體服務端代碼實現,深入解析 Digest 認證的技術細節。

一、Digest 認證的核心原理與流程

1.1 為什么需要 Digest 認證?

Basic 認證直接通過 Base64 編碼傳輸用戶名和密碼(如 username:password),雖然編碼可逆但無加密,安全性極差。Digest 認證通過哈希算法(如 MD5)對密碼進行處理,客戶端僅傳輸密碼的哈希值(而非明文),且每次請求使用動態隨機數(Nonce),大幅提升了安全性。

1.2 標準協議流程(RFC 7616)

Digest 認證的核心是 “挑戰 - 響應” 模式,完整流程可分為 4 步:

步驟 1:客戶端首次請求受保護資源

客戶端訪問服務端的受保護路徑(如示例中的 /sd),未攜帶認證信息。

步驟 2:服務端返回 401 挑戰(Challenge)

服務端返回狀態碼 401 Unauthorized,并在 WWW-Authenticate 頭部中攜帶以下關鍵參數:

  • realm:認證域(如 MyProtectedSD),用于提示用戶認證的上下文(如 “我的受保護存儲”)。
  • nonce:服務端生成的一次性隨機數(如 a1b2c3...),用于防止重放攻擊。
  • opaque:服務端生成的固定字符串(如 MD5 哈希值),客戶端需原樣返回。
  • qop:認證質量(Quality of Protection),常見值為 auth(僅驗證請求)。
  • algorithm:哈希算法(默認 MD5)。

示例頭部:

WWW-Authenticate: Digest realm="MyProtectedSD", qop="auth", nonce="a1b2c3...", opaque="d4e5f6...", algorithm="MD5"
步驟 3:客戶端構造認證響應(Response)

客戶端收到挑戰后,提示用戶輸入用戶名和密碼,計算并組裝 Authorization 頭部,包含以下參數:

  • username:用戶輸入的用戶名。

  • realm:服務端返回的 realm(需與本地存儲的密碼關聯)。

  • nonce:服務端返回的 nonce(原樣使用)。

  • uri:請求的資源路徑(如 /sd)。

  • response:核心哈希值,通過以下公式計算:

    response = MD5(HA1:nonce:nc:cnonce:qop:HA2)
    

    其中:

    • HA1 = MD5(username:realm:password)(客戶端預計算的用戶密碼哈希)。
    • HA2 = MD5(method:uri)(請求方法與資源路徑的哈希,如 GET:/sd)。
    • nc:請求計數(Nonce Count,防止重放攻擊的遞增序號)。
    • cnonce:客戶端生成的隨機數(Client Nonce,增強隨機性)。
步驟 4:服務端驗證響應

服務端收到 Authorization 頭部后,根據以下邏輯驗證:

  1. 校驗 realmnonce(是否有效且未過期)、opaque 是否匹配。
  2. 根據用戶名獲取存儲的密碼(或預計算的 HA1)。
  3. 重新計算 HA1HA2 和期望的 response
  4. 比較客戶端提供的 response 與服務端計算的 response,一致則認證成功。

二、服務端實現邏輯:代碼解析

本文提供的服務端代碼基于 Python 的 http.server 模塊,實現了 Digest 認證的核心邏輯。以下是關鍵模塊的詳細解析。

2.1 全局配置與狀態管理

# --- 配置 ---
SERVER_ADDRESS = '0.0.0.0'  # 監聽所有接口,方便測試
SERVER_PORT = 8001
REALM = "MyProtectedSD"  # 保護域名,會顯示在客戶端的認證提示中# 存儲用戶名和密碼(在實際應用中,密碼應該哈希存儲,這里為了演示方便直接存儲)
# 或者更好的方式是存儲 HA1 = MD5(username:realm:password)
# 例如: HA1 = hashlib.md5(f"your_username_here:{REALM}:your_password_here".encode()).hexdigest()
USERS_PASSWORDS = {"admin001": "my_password_random_generation"
}# 存儲已發出的 nonce 及其創建時間,用于校驗和防止重放
# {nonce_value: creation_timestamp}
# 實際應用中,nonce 應該有過期機制,并且用后即焚或嚴格校驗 nc (nonce count)
active_nonces = {}
NONCE_LIFETIME_SECONDS = 300  # Nonce 有效期,例如 5 分鐘# Opaque 值,服務器生成,客戶端原樣返回
OPAQUE = hashlib.md5(os.urandom(16)).hexdigest()
  • 用戶存儲:示例中直接存儲明文密碼(實際生產環境應存儲預計算的 HA1 = MD5(username:realm:password))。
  • nonce 管理active_nonces 字典記錄 nonce 及其生成時間,用于后續過期校驗。
  • opaque:服務端生成的固定字符串,防止客戶端篡改挑戰參數。

2.2 nonce 生成與過期校驗

def generate_nonce():"""生成唯一的 nonce 并記錄創建時間"""nonce = hashlib.md5((os.urandom(16).hex() + str(time.time())).encode()).hexdigest()active_nonces[nonce] = time.time()  # 存儲 nonce 與時間戳return nonce

nonce 是 Digest 認證的安全基石,其生成需滿足:

  • 隨機性:通過 os.urandom(16) 生成隨機字節,結合時間戳確保唯一性。
  • 時效性active_nonces 記錄生成時間,超過 NONCE_LIFETIME_SECONDS(5 分鐘)后失效,防止重放攻擊。

2.3 挑戰響應(401 狀態碼)

def send_401_challenge(self, stale=False):"""發送 401 Unauthorized 響應和 WWW-Authenticate 挑戰頭"""self.send_response(401)self.send_header('Content-type', 'text/plain')nonce = generate_nonce()  # 生成新 nonceauth_challenge = f'Digest realm="{REALM}", qop="auth", nonce="{nonce}", opaque="{OPAQUE}", algorithm="MD5"'if stale:auth_challenge += ', stale="true"'  # 標記舊 nonce 過期,提示客戶端使用新 nonceself.send_header('WWW-Authenticate', auth_challenge)self.end_headers()self.wfile.write(b"Authentication required.")print(f"Sent 401 challenge with new nonce: {nonce}")

當客戶端未攜帶認證信息或認證失敗時,服務端返回 401 狀態碼,并通過 WWW-Authenticate 頭部發送挑戰參數。若 stale=True(如 nonce 過期),客戶端會自動使用新 nonce 重試。

2.4 認證頭解析與驗證

2.4.1 解析 Authorization 頭部
def parse_digest_auth_header(auth_header_value):"""解析 Authorization: Digest ... 頭部字符串返回一個包含各參數的字典"""if not auth_header_value or not auth_header_value.lower().startswith('digest '):return Noneauth_parts = {}# 移除 "Digest " 前綴value_str = auth_header_value[len('Digest '):]# 使用正則表達式解析 key="value" 或 key=value 對# 這個正則表達式處理了帶引號和不帶引號的值pattern = re.compile(r'(\w+)=(?:"([^"]*)"|([^\s,]*))')for match in pattern.finditer(value_str):key = match.group(1)# 值可能在 group(2) (帶引號) 或 group(3) (不帶引號)val = match.group(2) if match.group(2) is not None else match.group(3)auth_parts[key] = valreturn auth_parts

客戶端發送的 Authorization 頭部是一個復雜的字符串(如 Digest username="admin001", realm="MyProtectedSD", nonce="a1b2c3", ...),此函數通過正則表達式提取各參數,供后續驗證使用。

2.4.2 驗證認證響應
def verify_digest_response(self, auth_parts):"""校驗客戶端提供的 Digest 認證信息"""required_keys = ['username', 'realm', 'nonce', 'uri', 'response', 'qop', 'nc', 'cnonce']for key in required_keys:if key not in auth_parts:print(f"Missing digest auth key: {key}")return Falseusername = auth_parts.get('username')client_realm = auth_parts.get('realm')client_nonce = auth_parts.get('nonce')uri = auth_parts.get('uri')client_response = auth_parts.get('response')qop = auth_parts.get('qop')nc = auth_parts.get('nc')  # nonce countcnonce = auth_parts.get('cnonce')  # client noncealgorithm = auth_parts.get('algorithm', 'MD5').upper()  # 默認為 MD5# 1. 校驗 Realmif client_realm != REALM:print(f"Realm mismatch: expected '{REALM}', got '{client_realm}'")return False# 2. 校驗 Nonce# 檢查 nonce 是否由服務器發出且未過期# 實際應用中,還需要檢查 nc (nonce count) 以防止重放攻擊 (nc 應該單調遞增)# 這里簡化處理:只檢查 nonce 是否存在且未超時if client_nonce not in active_nonces:print(f"Invalid nonce: {client_nonce} (not issued by server)")# 可以考慮發送 stale=true,讓客戶端用新 nonce 重試return "stale"  # 特殊返回值表示 nonce 過期if time.time() - active_nonces[client_nonce] > NONCE_LIFETIME_SECONDS:print(f"Nonce expired: {client_nonce}")del active_nonces[client_nonce] # 刪除過期的 noncereturn "stale"  # 特殊返回值表示 nonce 過期# 3. 校驗 Opaque (如果服務器在挑戰中發送了)if 'opaque' in auth_parts and auth_parts.get('opaque') != OPAQUE:print(f"Opaque mismatch")return False# 4. 獲取用戶密碼 (或預計算的 HA1)password = USERS_PASSWORDS.get(username)if not password:print(f"Unknown user: {username}")return False# 5. 計算 HA1# HA1 = MD5(username:realm:password)ha1_str = f"{username}:{REALM}:{password}"ha1 = hashlib.md5(ha1_str.encode('utf-8')).hexdigest()print(f"Calculated HA1 for {username}: {ha1}")# 6. 計算 HA2# HA2 = MD5(method:uri)# 注意: self.command 是 HTTP 方法 (e.g., "GET")# uri 是客戶端在 Authorization 頭中提供的 URIha2_str = f"{self.command}:{uri}"ha2 = hashlib.md5(ha2_str.encode('utf-8')).hexdigest()print(f"Calculated HA2 for {self.command}:{uri}: {ha2}")# 7. 計算期望的 response# response = MD5(HA1:nonce:nc:cnonce:qop:HA2)if qop == "auth" or qop == "auth-int":  # auth-int 需要校驗 body,這里簡化expected_response_str = f"{ha1}:{client_nonce}:{nc}:{cnonce}:{qop}:{ha2}"else:# 如果 qop 不存在 (較老的 RFC 2069 規范,requests 不會這樣)expected_response_str = f"{ha1}:{client_nonce}:{ha2}"expected_response = hashlib.md5(expected_response_str.encode('utf-8')).hexdigest()print(f"Expected response: {expected_response}")print(f"Client response:   {client_response}")# 8. 比較 responseif client_response == expected_response:# 認證成功后,可以考慮使當前 nonce 失效(或嚴格檢查 nc)# del active_nonces[client_nonce] # 如果 nonce 只能使用一次return Trueelse:print("Response mismatch.")return False

此函數是服務端認證的核心邏輯,通過 8 步校驗確保客戶端的合法性:

  • 參數完整性:檢查必要參數(如 usernamenonce)是否存在。
  • realm 匹配:確保客戶端請求的認證域與服務端配置一致。
  • nonce 有效性:驗證 nonce 是否由服務端生成且未過期(防止重放攻擊)。
  • opaque 校驗:確保客戶端未篡改挑戰參數。
  • 哈希計算:重新計算 HA1(用戶密碼哈希)和 HA2(請求信息哈希),并生成期望的 response,與客戶端提供的 response 比較。

2.5 請求處理(do_GET 方法)

def do_GET(self):parsed_path = urlparse(self.path)# 只對 /sd 路徑進行認證if parsed_path.path == '/sd':auth_header = self.headers.get('Authorization')if not auth_header:print("No Authorization header, sending 401 challenge.")self.send_401_challenge()returnauth_parts = parse_digest_auth_header(auth_header)if not auth_parts:print("Malformed Authorization header, sending 401 challenge.")self.send_401_challenge()  # 或發送 400 Bad Requestreturnverification_result = self.verify_digest_response(auth_parts)if verification_result == "stale":print("Nonce was stale, sending 401 challenge with stale=true.")self.send_401_challenge(stale=True)elif verification_result:print("Authentication successful!")self.send_response(200)self.send_header('Content-type', 'application/json')self.end_headers()response_data = {"message": "Welcome to the secure data area!", "user": auth_parts.get('username')}import jsonself.wfile.write(json.dumps(response_data).encode('utf-8'))else:print("Authentication failed, sending 401 challenge again.")# 認證失敗,可以簡單地再次發送 401 (可能用新的 nonce)# 或者根據具體策略,如果嘗試次數過多可以發送 403 Forbiddenself.send_401_challenge()else:self.send_response(200)self.send_header('Content-type', 'text/plain')self.end_headers()self.wfile.write(b"This is an open area.")

服務端通過 do_GET 方法處理請求:

  • 若請求路徑為 /sd(受保護資源),則檢查 Authorization 頭部。
  • 無認證頭或解析失敗時,返回 401 挑戰。
  • 認證成功后返回資源(如示例中的 JSON 數據)。
  • 其他路徑(如根路徑)直接返回公開內容。

三、關鍵技術點與安全增強

3.1 nonce 的時效性與重放攻擊防范

  • 時效性nonce 僅在 NONCE_LIFETIME_SECONDS(5 分鐘)內有效,過期后服務端刪除記錄,客戶端需重新獲取新 nonce
  • 重放攻擊:通過 nc(請求計數)可以進一步防范 —— 客戶端每次使用同一 nonce 時,nc 必須遞增(如從 0000000100000002),服務端若發現 nc 未遞增或重復,則判定為重放攻擊。

3.2 密碼存儲的最佳實踐

示例中直接存儲明文密碼(僅為演示),實際生產環境應存儲預計算的 HA1MD5(username:realm:password))。這樣即使數據庫泄露,攻擊者也無法直接獲取密碼明文,需結合 realmusername 才能計算 HA1,進一步增強安全性。

3.3 與 Basic 認證的對比

特性Basic 認證Digest 認證
密碼傳輸方式Base64 編碼明文(可逆)哈希值(不可逆)
防重放攻擊不支持支持(通過 nonce、nc)
安全性低(易被中間人截獲明文)高(無明文傳輸,動態隨機數)
客戶端支持所有主流瀏覽器所有主流瀏覽器

四、測試與驗證

4.1 啟動服務端

運行代碼后,服務端監聽 0.0.0.0:8001,保護路徑為 /sd

4.2 測試請求

使用 requests 模擬客戶端請求:

res = requests.get('http://127.0.0.1:8001/sd',auth=HTTPDigestAuth('admin001', 'my_password_random_generation'))
print(f"Status: {res.status_code}")
print(f"Request Authorization: {res.request.headers['Authorization']}")
print(f"Headers: {res.headers}")
print(f"Response Text: {res.text}")

requests 客戶端會自動處理挑戰 - 響應流程,請求后打印,可見如下響應信息:

Status: 200
Request Authorization: Digest username="admin001", realm="MyProtectedSD", nonce="f4b50139aeb242406e92e3a24a14f286", uri="/sd", response="72c8e7cf046193a3bce3fb80ec1ce4f6", opaque="b5a7e1bf338b6f1d6c70204c64fd9473", algorithm="MD5", qop="auth", nc=00000001, cnonce="0e22129e06725aa6"
Headers: {'Server': 'BaseHTTP/0.6 Python/3.12.9', 'Date': 'Thu, 22 May 2025 08:41:52 GMT', 'Content-type': 'application/json'}
Response Text: {"message": "Welcome to the secure data area!", "user": "admin001"}

服務端打印關鍵信息,可見客戶端請求流程及認證明細情況:

No Authorization header, sending 401 challenge.
127.0.0.1 - "GET /sd HTTP/1.1" 401 -
Sent 401 challenge with new nonce: f4b50139aeb242406e92e3a24a14f286
Calculated HA1 for admin001: fb5c1f99227711de645d65e5b091f978
Calculated HA2 for GET:/sd: 7c7e535b35fb1070562dec4be2da7ee5
Expected response: 72c8e7cf046193a3bce3fb80ec1ce4f6
Client response:   72c8e7cf046193a3bce3fb80ec1ce4f6
Authentication successful!
127.0.0.1 - "GET /sd HTTP/1.1" 200 -

若認證成功,服務端返回文本:

{"message": "Welcome to the secure data area!", "user": "admin001"}

4.3 驗證 nonce 過期

等待 5 分鐘后,若使用之前的 nonce 再次請求,服務端會返回 stale=true 的挑戰頭,提示客戶端使用新 nonce

五、服務端實現整體代碼

import hashlib
import time
import os
import re
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse# --- 配置 ---
SERVER_ADDRESS = '0.0.0.0'  # 監聽所有接口,方便測試
SERVER_PORT = 8001
REALM = "MyProtectedSD"  # 保護域名,會顯示在客戶端的認證提示中# 存儲用戶名和密碼(在實際應用中,密碼應該哈希存儲,這里為了演示方便直接存儲)
# 或者更好的方式是存儲 HA1 = MD5(username:realm:password)
# 例如: HA1 = hashlib.md5(f"your_username_here:{REALM}:your_password_here".encode()).hexdigest()
USERS_PASSWORDS = {"admin001": "my_password_random_generation"
}# 存儲已發出的 nonce 及其創建時間,用于校驗和防止重放
# {nonce_value: creation_timestamp}
# 實際應用中,nonce 應該有過期機制,并且用后即焚或嚴格校驗 nc (nonce count)
active_nonces = {}
NONCE_LIFETIME_SECONDS = 300  # Nonce 有效期,例如 5 分鐘# Opaque 值,服務器生成,客戶端原樣返回
OPAQUE = hashlib.md5(os.urandom(16)).hexdigest()def generate_nonce():"""生成一個唯一的 nonce 并記錄創建時間"""nonce = hashlib.md5((os.urandom(16).hex() + str(time.time())).encode()).hexdigest()active_nonces[nonce] = time.time()  # 記錄 nonce 創建時間return noncedef parse_digest_auth_header(auth_header_value):"""解析 Authorization: Digest ... 頭部字符串返回一個包含各參數的字典"""if not auth_header_value or not auth_header_value.lower().startswith('digest '):return Noneauth_parts = {}# 移除 "Digest " 前綴value_str = auth_header_value[len('Digest '):]# 使用正則表達式解析 key="value" 或 key=value 對# 這個正則表達式處理了帶引號和不帶引號的值pattern = re.compile(r'(\w+)=(?:"([^"]*)"|([^\s,]*))')for match in pattern.finditer(value_str):key = match.group(1)# 值可能在 group(2) (帶引號) 或 group(3) (不帶引號)val = match.group(2) if match.group(2) is not None else match.group(3)auth_parts[key] = valreturn auth_partsclass DigestAuthHandler(BaseHTTPRequestHandler):def send_401_challenge(self, stale=False):"""發送 401 Unauthorized 響應和 WWW-Authenticate 挑戰頭"""self.send_response(401)self.send_header('Content-type', 'text/plain')nonce = generate_nonce()  # 生成新 nonceauth_challenge = f'Digest realm="{REALM}", qop="auth", nonce="{nonce}", opaque="{OPAQUE}", algorithm="MD5"'if stale:auth_challenge += ', stale="true"'  # 標記舊 nonce 過期,提示客戶端使用新 nonceself.send_header('WWW-Authenticate', auth_challenge)self.end_headers()self.wfile.write(b"Authentication required.")print(f"Sent 401 challenge with new nonce: {nonce}")def verify_digest_response(self, auth_parts):"""校驗客戶端提供的 Digest 認證信息"""required_keys = ['username', 'realm', 'nonce', 'uri', 'response', 'qop', 'nc', 'cnonce']for key in required_keys:if key not in auth_parts:print(f"Missing digest auth key: {key}")return Falseusername = auth_parts.get('username')client_realm = auth_parts.get('realm')client_nonce = auth_parts.get('nonce')uri = auth_parts.get('uri')client_response = auth_parts.get('response')qop = auth_parts.get('qop')nc = auth_parts.get('nc')  # nonce countcnonce = auth_parts.get('cnonce')  # client noncealgorithm = auth_parts.get('algorithm', 'MD5').upper()  # 默認為 MD5# 1. 校驗 Realmif client_realm != REALM:print(f"Realm mismatch: expected '{REALM}', got '{client_realm}'")return False# 2. 校驗 Nonce# 檢查 nonce 是否由服務器發出且未過期# 實際應用中,還需要檢查 nc (nonce count) 以防止重放攻擊 (nc 應該單調遞增)# 這里簡化處理:只檢查 nonce 是否存在且未超時if client_nonce not in active_nonces:print(f"Invalid nonce: {client_nonce} (not issued by server)")# 可以考慮發送 stale=true,讓客戶端用新 nonce 重試return "stale"  # 特殊返回值表示 nonce 過期if time.time() - active_nonces[client_nonce] > NONCE_LIFETIME_SECONDS:print(f"Nonce expired: {client_nonce}")del active_nonces[client_nonce] # 刪除過期的 noncereturn "stale"  # 特殊返回值表示 nonce 過期# 3. 校驗 Opaque (如果服務器在挑戰中發送了)if 'opaque' in auth_parts and auth_parts.get('opaque') != OPAQUE:print(f"Opaque mismatch")return False# 4. 獲取用戶密碼 (或預計算的 HA1)password = USERS_PASSWORDS.get(username)if not password:print(f"Unknown user: {username}")return False# 5. 計算 HA1# HA1 = MD5(username:realm:password)ha1_str = f"{username}:{REALM}:{password}"ha1 = hashlib.md5(ha1_str.encode('utf-8')).hexdigest()print(f"Calculated HA1 for {username}: {ha1}")# 6. 計算 HA2# HA2 = MD5(method:uri)# 注意: self.command 是 HTTP 方法 (e.g., "GET")# uri 是客戶端在 Authorization 頭中提供的 URIha2_str = f"{self.command}:{uri}"ha2 = hashlib.md5(ha2_str.encode('utf-8')).hexdigest()print(f"Calculated HA2 for {self.command}:{uri}: {ha2}")# 7. 計算期望的 response# response = MD5(HA1:nonce:nc:cnonce:qop:HA2)if qop == "auth" or qop == "auth-int":  # auth-int 需要校驗 body,這里簡化expected_response_str = f"{ha1}:{client_nonce}:{nc}:{cnonce}:{qop}:{ha2}"else:# 如果 qop 不存在 (較老的 RFC 2069 規范,requests 不會這樣)expected_response_str = f"{ha1}:{client_nonce}:{ha2}"expected_response = hashlib.md5(expected_response_str.encode('utf-8')).hexdigest()print(f"Expected response: {expected_response}")print(f"Client response:   {client_response}")# 8. 比較 responseif client_response == expected_response:# 認證成功后,可以考慮使當前 nonce 失效(或嚴格檢查 nc)# del active_nonces[client_nonce] # 如果 nonce 只能使用一次return Trueelse:print("Response mismatch.")return Falsedef do_GET(self):parsed_path = urlparse(self.path)# 只對 /sd 路徑進行認證if parsed_path.path == '/sd':auth_header = self.headers.get('Authorization')if not auth_header:print("No Authorization header, sending 401 challenge.")self.send_401_challenge()returnauth_parts = parse_digest_auth_header(auth_header)if not auth_parts:print("Malformed Authorization header, sending 401 challenge.")self.send_401_challenge()  # 或發送 400 Bad Requestreturnverification_result = self.verify_digest_response(auth_parts)if verification_result == "stale":print("Nonce was stale, sending 401 challenge with stale=true.")self.send_401_challenge(stale=True)elif verification_result:print("Authentication successful!")self.send_response(200)self.send_header('Content-type', 'application/json')self.end_headers()response_data = {"message": "Welcome to the secure data area!", "user": auth_parts.get('username')}import jsonself.wfile.write(json.dumps(response_data).encode('utf-8'))else:print("Authentication failed, sending 401 challenge again.")# 認證失敗,可以簡單地再次發送 401 (可能用新的 nonce)# 或者根據具體策略,如果嘗試次數過多可以發送 403 Forbiddenself.send_401_challenge()else:self.send_response(200)self.send_header('Content-type', 'text/plain')self.end_headers()self.wfile.write(b"This is an open area.")def log_message(self, format, *args):"""覆蓋默認日志,方便調試"""print(f"{self.address_string()} - {format % args}")def run_server(server_class=HTTPServer, handler_class=DigestAuthHandler, addr=SERVER_ADDRESS, port=SERVER_PORT):server_address = (addr, port)httpd = server_class(server_address, handler_class)print(f"Starting Digest Auth server on {addr}:{port}...")print(f"Protected path: /sd")print(f"Test with username: '{USERS_PASSWORDS.keys()}', password: '{USERS_PASSWORDS.values()}'")try:httpd.serve_forever()except KeyboardInterrupt:print("\nServer shutting down.")finally:httpd.server_close()if __name__ == '__main__':run_server()

小總結

HTTP Digest 認證通過哈希算法和動態隨機數(nonce)解決了 Basic 認證的明文傳輸問題,是輕量級場景下的安全認證方案。本文結合代碼詳細解析了其核心流程(挑戰 - 響應)和服務端實現邏輯(nonce 管理、哈希計算、響應驗證),并強調了生產環境中的安全增強點(如存儲 HA1、校驗 nc)。實際應用中,建議結合 HTTPS 進一步加密傳輸過程,以達到更高的安全性。

————————————————

Java猿社區—Http digest authentication 請求代碼最全示例 - 簡書

HTTP認證之摘要認證——Digest(二) - xiaoxiaotank - 博客園

HTTP的幾種認證方式之DIGEST 認證(摘要認證) - wenbin_ouyang - 博客園

HTTP Authentication之Basic認證、Digest認證

http digest鑒權流程

python http 身份認證簡介

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/82355.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/82355.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/82355.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

PDF 表單按鈕動態邊框效果

問題描述 用戶在 Acrobat X 中創建 PDF 表單時遇到一個需求:表單以網格形式列出多個選項,當點擊某個選項時,需要在選項周圍顯示邊框(圓形或方形),再次點擊時邊框消失。 試過的解決方案 在文本上方放置透…

部署Gitlab-CE with Docker私有云環境

應用環境 Ubuntu 20.04.6 LTS (GNU/Linux 5.15.0-139-generic x86_64) Docker version 28.1.1, build 4eba377 文章目錄 拉取容器鏡像生成Run腳本參數解讀實例腳本環境配置管理員密碼遺忘服務郵箱配置郵件測試 運維問題集錦(1) 端口映射關系(2) 服務日志(3) 分支受保護 項目操作…

MyBatis 的動態 SQL 特性來實現有值字段才進行插入或更新

MyBatis 動態 SQL 解決方案 <!-- 動態INSERT語句 --> <insert id"addDailyFreezeTer" parameterType"com.linyang.pecker.pojo.DailyFreezeTerminalBean">INSERT INTO dailyfreezeter_info<trim prefix"(" suffix")" …

網絡原理與 TCP/IP 協議詳解

一、網絡通信的本質與基礎概念 1.1 什么是網絡通信&#xff1f; 網絡通信的本質是跨設備的數據交換&#xff0c;其核心目標是讓不同物理位置的設備能夠共享信息。這種交換需要解決三個核心問題&#xff1a; 如何定位設備&#xff1f; → IP地址如何找到具體服務&#xff1f;…

CUDA編程筆記(1)--最簡單的核函數

本文用來記錄cuda編程的一些筆記以及知識 本筆記運行在windows系統&#xff0c;vs編譯器中&#xff0c;cuda版本是12.6 先看一下最基本的代碼例子&#xff1a; #include<iostream> #include<cstdio> #include "cuda_runtime.h" #include "device…

系統架構中的限流實踐:構建多層防護體系(二)

系統架構中的限流實踐:構建多層防護體系 一、接入層限流:流量攔截第一關二、應用層限流(服務內限流)Java生態方案對比三、分布式限流(跨服務限流)四、數據層限流(數據庫/緩存限流)1. 數據庫防護策略2. 緩存優化方案五、中間件層限流(消息隊列/分布式服務)六、客戶端限…

AI學習筆記二十八:使用ESP32 CAM和YOLOV5實現目標檢測

若該文為原創文章&#xff0c;轉載請注明原文出處。 最近在研究使用APP如何顯示ESP32 CAM的攝像頭數據&#xff0c;看到有人實現把ESP32 CAM的數據流上傳&#xff0c;通過YOLOV5來檢測&#xff0c;實現拉流推理&#xff0c;這里復現一下。 一、環境 arduino配置esp32-cam開發環…

uni-app(5):Vue3語法基礎上

Vue (讀音 /vju?/&#xff0c;類似于 view) 是一套用于構建用戶界面的漸進式框架。與其它大型框架不同的是&#xff0c;Vue 被設計為可以自底向上逐層應用。Vue.js 的核心是一個允許采用簡潔的模板語法來聲明式地將數據渲染進 DOM 的系統&#xff0c;只關注視圖層&#xff0c;…

JAVA:Kafka 存儲接口詳解與實踐樣例

?? 1、簡述 Kafka 以其高吞吐、可擴展和高可靠性著稱,其強大性能的背后核心在于其高效的存儲設計。Kafka 不是傳統意義上的隊列,而是一個分布式日志系統,其存儲模塊是核心組成部分。 本文將深入剖析 Kafka 的存儲接口實現機制,并結合 Java 示例進行模擬驗證。 ?? 2、…

Docker 使用鏡像[SpringBoot之Docker實戰系列] - 第537篇

歷史文章&#xff08;文章累計530&#xff09; 《國內最全的Spring Boot系列之一》 《國內最全的Spring Boot系列之二》 《國內最全的Spring Boot系列之三》 《國內最全的Spring Boot系列之四》 《國內最全的Spring Boot系列之五》 《國內最全的Spring Boot系列之六》 《…

數據庫入門教程:以商品訂單系統為例

數據庫入門教程&#xff1a;以商品訂單系統為例 一、前言 數據庫是現代軟件開發中不可或缺的基礎&#xff0c;掌握數據庫的基本概念和操作&#xff0c;是每個開發者的必經之路。本文將以“商品-品牌-客戶-訂單-訂單項”為例&#xff0c;帶你快速入門數據庫的核心知識和基本操…

GeoServer樣式設置:使用本地圖標及分層/分視野顯示

GeoServer樣式設置:使用本地圖標及分層/分視野顯示 1、本地圖標生效設置2、GeoServer添加不同視野的圖標點樣式1)服務預覽效果2)本地圖標引用3)不同視野顯示不同圖標4)標注注記顯示空間的點數據,使用圖標來表示是非常常見的業務需求,而且由于在不同比例尺下,可能需要設…

DL00347-基于人工智能YOLOv11的安檢X光危險品刀具檢測含數據集

&#x1f6a8; AI技術革新&#xff0c;提升安檢效率與安全性&#xff01;YOLOv11助力X光危險品刀具檢測&#xff01; &#x1f4a1; 在安全領域&#xff0c;效率與精準度的要求從未如此迫切。作為科研人員&#xff0c;是否一直在尋找一款可以提升安檢準確率、減少人工干預、提…

測試計劃與用例撰寫指南

測試計劃與用例撰寫指南 一、測試計劃&#xff1a;項目測試的 “導航地圖”1.1 測試計劃的核心目標 1.2 測試計劃的關鍵要素 1.2.1 項目概述 1.2.2 測試策略 1.2.3 資源與進度 1.2.4 風險評估與應對 二、測試用例&#xff1a;測試執行的 “行動指南”2.1 測試用例的設計原則 2…

微服務的應用案例

從“菜市場”到“智慧超市”&#xff1a;一場微服務的變革之旅 曾經&#xff0c;我們的系統像一個熙熙攘攘的傳統菜市場。所有功能模塊&#xff08;攤販&#xff09;都擠在一個巨大的單體應用中。用戶請求&#xff08;買菜的顧客&#xff09;一多&#xff0c;整個市場就擁堵不堪…

Java設計模式之觀察者模式:從基礎到高級的全面解析

文章目錄 一、觀察者模式基礎概念1.1 什么是觀察者模式?1.2 觀察者模式的四大角色1.3 觀察者模式類圖二、觀察者模式實現步驟2.1 基礎實現步驟2.2 詳細代碼實現第一步:定義主題接口第二步:定義觀察者接口第三步:創建具體主題第四步:創建具體觀察者第五步:客戶端使用三、觀…

GATT 服務的核心函數bt_gatt_discover的介紹

目錄 概述 1 GATT 基本概念 1.1 GATT 的介紹 1.2 GATT 的角色 1.3 核心組件 1.4 客戶端操作 2 bt_gatt_discover函數的功能和應用 2.1 函數介紹 2.1 發現類型&#xff08;Discover Type&#xff09; 3 典型使用流程 3.1 服務發現示例 3.2 級聯發現模式 3.3 按UUID過…

【更新至2023年】1985-2023年全國及各省就業人數數據(無缺失)

1985-2023年全國及各省就業人數數據&#xff08;無缺失&#xff09; 1、時間&#xff1a;1985-2023年 2、來源&#xff1a;Z國統計年鑒、各省年鑒、新中國60年 3、指標&#xff1a;就業人數 4、范圍&#xff1a;全國及31省 5、缺失情況&#xff1a;無缺失 6、指標解釋&am…

0基礎學習Linux之揭開朦朧一面:環境基礎開發工具

目錄 Linux下安裝軟件的方案&#xff1a; 對于操作系統的理解&#xff1a; 操作系統的生態問題&#xff1a; 什么是好的操作系統&#xff08;os&#xff09;&#xff1a; 重新理解centos VS ubnutu VS kail&#xff1a; 關于yum: 用 yum 安裝軟件(安裝和卸載軟件一定要有r…

YOLO 算法詳解:實時目標檢測的里程碑

在計算機視覺領域&#xff0c;目標檢測一直是一個關鍵且熱門的研究方向&#xff0c;而 YOLO&#xff08;You Only Look Once&#xff09;算法憑借其出色的實時性和較高的檢測精度&#xff0c;成為了目標檢測算法中的明星選手。本文將深入探討 YOLO 算法的原理、發展歷程、技術優…