如何用Kerberos加密请求消息体?认证成功但加密请求报错
问题分析与解决方案
你的核心问题是:第二个请求仅构造了multipart/encrypted的格式框架,但没有用Kerberos会话密钥加密SOAP消息体,WEC服务器无法解密明文内容,因此返回failed to unwrap kerberos packet错误。
结合OpenWEC协议文档关键内容翻译:
客户端发送枚举请求时,需使用
multipart/encrypted格式的请求体,其中包含两部分:
- 第一部分为元数据,指定原始内容类型和长度;
- 第二部分是通过Kerberos会话密钥加密后的SOAP消息二进制数据,需使用GSSAPI的
wrap操作生成。
具体实现步骤
- 保留Kerberos GSS上下文:第一个认证请求不能只获取token,需要保留GSS客户端上下文,用于后续的加密操作。
- 加密SOAP消息体:使用
kerberos.authGSSClientWrap方法,通过已建立的Kerberos会话加密SOAP内容。 - 修正multipart payload构造:将加密后的二进制数据放入
application/octet-stream部分,而不是明文。
修改后的完整代码
import requests import kerberos def init_kerberos_context(service): # 初始化GSS客户端上下文并完成认证,返回上下文和token _, krb_context = kerberos.authGSSClientInit(service) kerberos.authGSSClientStep(krb_context, "") negotiate_token = kerberos.authGSSClientResponse(krb_context) return krb_context, negotiate_token # 替换为实际的SOAP内容 soap_message = "<soap:Envelope ...></soap:Envelope>" auth_url = "http://localhost:8081/wsman" # 初始化Kerberos上下文并获取认证token krb_context, negotiate_token = init_kerberos_context(service="http@localhost") auth_headers = { 'Host': 'localhost:8081', 'Content-Length': '0', 'Authorization': f'Kerberos {negotiate_token}', 'Content-Type': 'application/soap+xml;charset=UTF-8', 'Accept-Encoding': 'gzip' } session = requests.Session() auth_response = session.post(auth_url, headers=auth_headers) print(f"Auth Response status code: {auth_response.status_code}") print(f"Auth Response content: {auth_response.text}") # 加密SOAP消息体 # wrap参数:上下文、明文内容、是否为隐私(加密+完整性)、是否为序列 encrypted_data, _ = kerberos.authGSSClientWrap(krb_context, soap_message.encode('utf-8'), True, True) boundary = "Encrypted Boundary" # 构造正确的multipart/encrypted payload payload_parts = [ f"--{boundary}", 'Content-Type: application/HTTP-Kerberos-session-encrypted', f'OriginalContent: type=application/soap+xml;charset=UTF-8;Length={len(soap_message)}', f"--{boundary}", 'Content-Type: application/octet-stream', '', # 空行分隔头部和内容 f"--{boundary}--" # 结束边界必须带-- ] # 用\r\n连接文本部分,再拼接二进制加密数据 payload = '\r\n'.join(payload_parts[:-2]).encode('utf-8') + b'\r\n' + encrypted_data + b'\r\n' + payload_parts[-1].encode('utf-8') soap_headers = { 'Host': 'localhost:8081', 'User-Agent': 'Go-http-client/1.1', 'Content-Type': f'multipart/encrypted;protocol="application/HTTP-Kerberos-session-encrypted";boundary="{boundary}"', 'Accept-Encoding': 'gzip' } soap_url = "http://localhost:8081/wsman/subscriptions/24f5eb95-d9b1-1005-8062-697970657274/0" soap_response = session.post(soap_url, headers=soap_headers, data=payload) print(f"SOAP Response status code: {soap_response.status_code}") print(f"SOAP Response content: {soap_response.text}") # 清理上下文 kerberos.authGSSClientClean(krb_context)
关键修改说明
- 保留GSS上下文:
init_kerberos_context函数返回上下文对象,这是后续加密操作的核心支撑,之前代码缺失了这一步。 - 加密操作:
authGSSClientWrap使用Kerberos会话密钥对SOAP内容加密,生成WEC可解密的二进制数据。 - payload格式修正:
- 结束边界必须添加
--,符合multipart规范; - 原始内容长度要与明文SOAP的字节数一致;
- 加密后的二进制数据直接作为二进制内容拼接,不能转成字符串处理。
- 结束边界必须添加
内容的提问来源于stack exchange,提问作者user14073111
相关产品推荐
相关产品推荐

