soap-errorstroubleshootingweb-services

SOAP MustUnderstand エラー: ヘッダーが理解されなかった場合の原因と解決策

SOAPless Team9 min read

構文的に正しい SOAP リクエストを送信しているにもかかわらず、以下のレスポンスが返ってくることがあります。

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <soap:Fault>
      <faultcode>soap:MustUnderstand</faultcode>
      <faultstring>
        SOAP header Security was not understood.
      </faultstring>
    </soap:Fault>
  </soap:Body>
</soap:Envelope>

MustUnderstand fault は、サーバーが mustUnderstand="1" と指定された必須ヘッダー要素を受信したものの、そのヘッダーを処理するハンドラーが登録されていないことを意味します。SOAP 仕様では、処理できない必須ヘッダーを含むメッセージは必ず拒否しなければならないと定められています。フォールバックもグレースフルデグラデーションもありません。

mustUnderstand 属性の意味

mustUnderstand は SOAP ヘッダー要素に付与されるバイナリ指示です。"1" (SOAP 1.1) または "true" (SOAP 1.2) に設定されると、受信側の SOAP プロセッサに「このヘッダーの処理方法を理解している必要がある。理解できない場合はメッセージ全体を拒否せよ」と伝えます。

<soap:Header>
  <wsse:Security
    xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
    soap:mustUnderstand="1">
    <wsse:UsernameToken>
      <wsse:Username>admin</wsse:Username>
      <wsse:Password>secret</wsse:Password>
    </wsse:UsernameToken>
  </wsse:Security>
</soap:Header>

この例では、サーバーに WS-Security の処理が有効になっていない場合、MustUnderstand fault を返さなければなりません。Security ヘッダーを無視して本文を処理することは、セキュリティ違反になるためです。

MustUnderstand Fault を引き起こす一般的なヘッダー

1. WS-Security ヘッダー

最も頻繁に発生するケースです。クライアントの SOAP ライブラリが WS-Security ヘッダー (UsernameToken、X.509 証明書、SAML アサーション) を自動的に追加しますが、サーバーが WS-Security を実装していない、または別のセキュリティメカニズムを期待しています。

<wsse:Security soap:mustUnderstand="1"
  xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
  <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <wsu:Created>2026-03-01T10:00:00Z</wsu:Created>
    <wsu:Expires>2026-03-01T10:05:00Z</wsu:Expires>
  </wsu:Timestamp>
</wsse:Security>

発生原因: WCF の wsHttpBinding はデフォルトで WS-Security ヘッダーを追加します。ターゲットサービスが basicHttpBinding や WCF 以外の SOAP スタックを使用している場合、WS-Security ハンドラーがなくヘッダーを拒否します。

2. WS-Addressing ヘッダー

WS-Addressing は ToActionMessageIDReplyTo などのルーティングメタデータを SOAP ヘッダーに追加します。

<wsa:Action soap:mustUnderstand="1"
  xmlns:wsa="http://www.w3.org/2005/08/addressing">
  http://example.com/IOrderService/GetOrder
</wsa:Action>
<wsa:To soap:mustUnderstand="1"
  xmlns:wsa="http://www.w3.org/2005/08/addressing">
  https://api.example.com/OrderService.svc
</wsa:To>

発生原因: WCF の wsHttpBinding はデフォルトで WS-Addressing を含みます。Java ベースの SOAP サービスでは WS-Addressing ハンドラーが設定されていないことが多く、古い ASP.NET ASMX サービスはこれをサポートしていません。

3. WS-ReliableMessaging ヘッダー

WS-ReliableMessaging は確認応答シーケンスによるメッセージ配信保証を提供します。

<wsrm:Sequence soap:mustUnderstand="1"
  xmlns:wsrm="http://schemas.xmlsoap.org/ws/2005/02/rm">
  <wsrm:Identifier>urn:uuid:abc123</wsrm:Identifier>
  <wsrm:MessageNumber>1</wsrm:MessageNumber>
</wsrm:Sequence>

発生原因: WCF の wsHttpBindingreliableSession enabled="true" を設定するとこれらのヘッダーが追加されます。WCF 以外のサービスはこれを処理できないことがほとんどです。

問題のヘッダーを特定する方法

fault メッセージにヘッダー名が含まれる場合もありますが、常にそうとは限りません。確実に特定するには、送信リクエストを調査する必要があります。

ステップ 1: 生のリクエストをキャプチャする

WCF メッセージログの場合:

<system.serviceModel>
  <diagnostics>
    <messageLogging logEntireMessage="true"
                    logMalformedMessages="true"
                    logMessagesAtServiceLevel="false"
                    logMessagesAtTransportLevel="true" />
  </diagnostics>
</system.serviceModel>

ネットワークプロキシを使用する場合 (言語非依存):

# mitmproxy で SOAP トラフィックをインターセプト
mitmproxy --mode reverse:https://api.example.com --listen-port 8080

ステップ 2: mustUnderstand="1" のヘッダーをすべて確認する

キャプチャした XML で mustUnderstand を検索します。mustUnderstand="1" が付いたすべてのヘッダー要素が原因の候補です。

解決策

解決策 1: 不要なヘッダーを除去する

最も直接的な修正方法です。サーバーが WS-Security、WS-Addressing、WS-ReliableMessaging を必要としない場合、送信を停止します。

WCF (.NET) — wsHttpBinding から basicHttpBinding に切り替え:

<!-- 変更前: wsHttpBinding は WS-Security + WS-Addressing を追加 -->
<endpoint binding="wsHttpBinding" contract="IOrderService" />

<!-- 変更後: basicHttpBinding は WS-* ヘッダーなしの素の SOAP を送信 -->
<endpoint binding="basicHttpBinding" contract="IOrderService" />

WCF — wsHttpBinding を維持しつつ特定の機能を無効化:

<wsHttpBinding>
  <binding name="NoWsExtensions">
    <security mode="None" />  <!-- WS-Security ヘッダーを除去 -->
    <reliableSession enabled="false" />  <!-- WS-RM ヘッダーを除去 -->
  </binding>
</wsHttpBinding>

WS-Addressing を除去するにはカスタムバインディングを使用:

<customBinding>
  <binding name="NoAddressing">
    <textMessageEncoding messageVersion="Soap11" />
    <httpTransport />
  </binding>
</customBinding>

解決策 2: サーバーにヘッダー処理を設定する

ヘッダーがユースケースに必要な場合 (WS-Security が必須など)、サーバーにそれを処理するよう設定します。

Java (Apache CXF) — WS-Security インターセプターの追加:

import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;

Map<String, Object> inProps = new HashMap<>();
inProps.put("action", "UsernameToken");
inProps.put("passwordType", "PasswordText");
inProps.put("passwordCallbackClass", "com.example.ServerPasswordCallback");

endpoint.getInInterceptors().add(new WSS4JInInterceptor(inProps));

解決策 3: カスタムヘッダーハンドラーを実装する

サーバーを制御している場合、ヘッダーを実際に処理せずに「理解済み」としてマークする no-op ハンドラーを登録できます。

WCF での実装:

public class CustomHeaderHandler : IDispatchMessageInspector
{
    public object AfterReceiveRequest(
        ref Message request,
        IClientChannel channel,
        InstanceContext instanceContext)
    {
        int headerIndex = request.Headers.FindHeader(
            "CustomHeader",
            "http://example.com/custom");

        if (headerIndex >= 0)
        {
            request.Headers.UnderstoodHeaders.Add(
                request.Headers[headerIndex]);
        }

        return null;
    }

    public void BeforeSendReply(
        ref Message reply,
        object correlationState) { }
}

警告: セキュリティヘッダーを処理せずに「理解済み」とマークすると、セキュリティ脆弱性が生じます。ヘッダーの目的を十分に理解した上でのみ使用してください。

解決策 4: クライアント側で mustUnderstand を 0 に設定する

ヘッダーが情報提供目的であり必須でない場合、mustUnderstand="0" に設定してオプションにできます。

# Python (zeep) — mustUnderstand なしのカスタムヘッダー追加
from lxml import etree
from zeep import Client

client = Client("https://api.example.com/service?wsdl")

header = etree.Element(
    "{http://example.com/custom}TraceId",
    nsmap={"custom": "http://example.com/custom"}
)
header.text = "req-12345"
# mustUnderstand は明示的に設定しない場合デフォルトで 0

response = client.service.GetOrder(
    orderId="12345",
    _soapheaders=[header]
)

デバッグワークフロー

1. 送信 SOAP リクエスト (生 XML) をキャプチャ
        |
2. mustUnderstand="1" のすべての Header 要素をリストアップ
        |
3. 各ヘッダーについて:
   +-- ユースケースに必要か?
   |   +-- はい → サーバーに処理を設定する
   |   +-- いいえ → クライアント設定から除去する
   +-- フレームワークのデフォルトで追加されたか?
       +-- はい → よりシンプルなバインディングに切り替え (例: basicHttpBinding)
       +-- いいえ → mustUnderstand を "0" に設定可能か確認

SOAPless による解決

MustUnderstand fault は、ほぼすべてのケースでフレームワークレベルのヘッダー自動挿入から発生します。SOAP ライブラリがターゲットサービスの想定外のヘッダーを追加してしまうのです。これは異なるプラットフォーム間の SOAP 連携 (WCF から Java サービス、PHP から .NET サービスなど) で特に頻発する問題です。

SOAPless はこれらの差異を吸収するプロトコルブリッジとして機能します。WSDL を登録すると、SOAPless はターゲットサービスが期待するヘッダーのみで SOAP リクエストを構築します。不要な WS-Addressing や予期しない WS-ReliableMessaging は追加されず、WS-Security は明示的に設定した場合のみ含まれます。アプリケーションからはクリーンな REST JSON API で通信し、SOAPless が上流サービスとの SOAP ヘッダーネゴシエーションを処理します。

認証情報は SOAPless ダッシュボードで AES-256-GCM 暗号化により管理され、本番デプロイ前にブラウザから直接操作をテストできます。