| name | performing-soap-web-service-security-testing |
| description | 通过分析 WSDL 定义,测试 XML 注入(XML Injection)、XXE、WS-Security 绕过和 SOAPAction 欺骗,对 SOAP Web 服务执行安全测试。 |
| domain | cybersecurity |
| subdomain | api-security |
| tags | ["soap","web-services","wsdl","xml-injection","xxe","ws-security","penetration-testing","soapaction-spoofing","xpath-injection"] |
| version | 1.0 |
| author | mahipal |
| license | Apache-2.0 |
执行 SOAP Web 服务安全测试
概述
SOAP(简单对象访问协议,Simple Object Access Protocol)Web 服务在企业环境、金融系统、医疗健康和政务集成中仍广泛部署。SOAP 服务的安全测试包括:分析 WSDL(Web 服务描述语言)定义以了解可用方法、测试基于 XML 的注入攻击(XXE、XPath 注入、XML 炸弹)、评估 WS-Security 实施正确性、SOAPAction 头欺骗,以及评估认证和授权控制。与 REST API 不同,SOAP 服务使用 XML 信封,并且通常实施可能被错误配置的复杂安全标准。
前置条件
- 目标 SOAP Web 服务端点 URL
- WSDL 文件或服务的 WSDL URL 访问权限
- SoapUI 或 ReadyAPI 用于结构化测试
- 带 SOAP 扩展的 Burp Suite 用于拦截
- Python 3.8+ 及 zeep 和 lxml 库
- 执行安全测试的授权
测试方法论
阶段 1:WSDL 侦察
"""SOAP Web 服务安全测试工具
分析 WSDL 定义并测试 SOAP 端点中的
常见漏洞,包括 XXE、注入和 WS-Security 错误配置。
"""
import requests
import xml.etree.ElementTree as ET
from lxml import etree
import sys
import re
from typing import List, Dict, Optional
from dataclasses import dataclass
@dataclass
class SOAPOperation:
name: str
action: str
input_message: str
output_message: str
parameters: List[Dict]
class SOAPSecurityTester:
NAMESPACES = {
'wsdl': 'http://schemas.xmlsoap.org/wsdl/',
'soap': 'http://schemas.xmlsoap.org/wsdl/soap/',
'soap12': 'http://schemas.xmlsoap.org/wsdl/soap12/',
'xsd': 'http://www.w3.org/2001/XMLSchema',
'wsse': 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd',
}
def __init__(self, wsdl_url: str, endpoint_url: Optional[str] = None):
self.wsdl_url = wsdl_url
self.endpoint_url = endpoint_url
.operations: [SOAPOperation] = []
.findings: [] = []
() -> [SOAPOperation]:
response = requests.get(.wsdl_url, timeout=)
root = etree.fromstring(response.content)
.endpoint_url:
address = root.find(, .NAMESPACES)
address :
.endpoint_url = address.get()
binding_op root.findall(, .NAMESPACES):
name = binding_op.get()
soap_op = binding_op.find(, .NAMESPACES)
action = soap_op.get(, ) soap_op
operation = SOAPOperation(
name=name,
action=action,
input_message=,
output_message=,
parameters=[]
)
.operations.append(operation)
()
op .operations:
()
.operations
() -> :
xxe_payloads = [
{
: ,
: .(operation=operation.name)
},
{
: ,
: .(operation=operation.name)
},
{
: ,
: .(operation=operation.name)
}
]
results = []
xxe xxe_payloads:
:
response = requests.post(
.endpoint_url,
data=xxe[],
headers={
: ,
: operation.action,
},
timeout=
)
vulnerable =
indicators = []
response.text response.text:
vulnerable =
indicators.append()
response.status_code == response.text:
indicators.append()
response.elapsed.total_seconds() > :
indicators.append()
vulnerable =
result = {
: xxe[],
: vulnerable,
: response.status_code,
: response.elapsed.total_seconds(),
: indicators
}
results.append(result)
vulnerable:
.findings.append({
: ,
: ,
: operation.name,
: xxe[]
})
requests.exceptions.Timeout:
results.append({
: xxe[],
: ,
: []
})
{: operation.name, : results}
() -> :
sqli_payloads = [
,
,
,
,
,
]
results = []
payload sqli_payloads:
soap_body =
:
response = requests.post(
.endpoint_url,
data=soap_body,
headers={
: ,
: operation.action,
},
timeout=
)
sql_errors = [
, , , ,
, ,
,
]
error_found = (err response.text err sql_errors)
error_found:
.findings.append({
: ,
: ,
: operation.name,
:
})
results.append({
: payload,
: response.status_code,
: error_found,
: response.elapsed.total_seconds()
})
requests.exceptions.RequestException:
{: operation.name, : results}
() -> :
results = []
i, operation (.operations):
j, other_op (.operations):
i == j:
soap_body =
:
response = requests.post(
.endpoint_url,
data=soap_body,
headers={
: ,
: other_op.action,
},
timeout=
)
response.status_code == response.text:
.findings.append({
: ,
: ,
: operation.name,
:
})
results.append({
: operation.name,
: other_op.action,
:
})
requests.exceptions.RequestException:
{: results}
() -> :
test_cases = [
{
: ,
:
},
{
: ,
:
},
{
: ,
:
}
]
results = []
test test_cases:
.operations:
operation = .operations[]
soap_body =
:
response = requests.post(
.endpoint_url,
data=soap_body,
headers={: },
timeout=
)
accepted = response.status_code == response.text
accepted:
.findings.append({
: ,
: ,
: operation.name,
: test[]
})
results.append({
: test[],
: accepted,
: response.status_code
})
requests.exceptions.RequestException:
{: results}
() -> :
{
: .endpoint_url,
: .wsdl_url,
: (.operations),
: (.findings),
: ([f f .findings f[] == ]),
: ([f f .findings f[] == ]),
: .findings
}
():
wsdl_url = sys.argv[] (sys.argv) >
tester = SOAPSecurityTester(wsdl_url)
()
operations = tester.parse_wsdl()
op operations:
()
tester.test_xxe_vulnerability(op)
tester.test_sql_injection(op)
tester.test_soapaction_spoofing()
tester.test_ws_security_bypass()
report = tester.generate_report()
()
()
()
()
()
(
)
finding report[]:
()
()
()
__name__ == :
main()
参考资料