WS-Security: authentication, signing and encryption

Message-level security protects the payload through intermediaries, which is exactly what TLS cannot do once a gateway terminates the connection.

UsernameToken and timestamps

<soap:Header xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
             xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
             xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
  <wsse:Security soap:mustUnderstand="1">
    <wsu:Timestamp wsu:Id="TS-1">
      <wsu:Created>2026-09-18T10:00:00Z</wsu:Created>
      <wsu:Expires>2026-09-18T10:05:00Z</wsu:Expires>
    </wsu:Timestamp>
    <wsse:UsernameToken wsu:Id="UT-1">
      <wsse:Username>svc-orders</wsse:Username>
      <!-- Digest form, never a plain-text Password element -->
      <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">Q2hhbmdlTWU=</wsse:Password>
      <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">bG9uZ25vbmNl</wsse:Nonce>
      <wsu:Created>2026-09-18T10:00:00Z</wsu:Created>
    </wsse:UsernameToken>
  </wsse:Security>
</soap:Header>
  • The digest is base64 of SHA1 over nonce + created + password, so the password itself never travels.
  • A timestamp with an expiry is what makes replay impractical. A server that ignores the timestamp accepts a captured token forever.
  • Digest still leaves the message readable, so WS-Security is usually combined with TLS rather than replacing it.
  • Server clocks must be close. A few minutes of skew is the usual allowance, and more than that is a security downgrade.

Signing and encryption

<!-- A signature over the body, referenced by wsu:Id -->
<soap:Body wsu:Id="BODY-1" xmlns:wsu="...">
  <PlaceOrder xmlns="urn:example:orders"><sku>A-1</sku><qty>2</qty></PlaceOrder>
</soap:Body>

<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <ds:SignedInfo>
    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
    <ds:Reference URI="#BODY-1">
      <ds:Transforms>
        <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
      </ds:Transforms>
      <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
      <ds:DigestValue>...</ds:DigestValue>
    </ds:Reference>
  </ds:SignedInfo>
  <ds:SignatureValue>...</ds:SignatureValue>
  <ds:KeyInfo><ds:SecurityTokenReference>...</ds:SecurityTokenReference></ds:KeyInfo>
</ds:Signature>
ThreatControlNotes
EavesdroppingTLS, plus XML Encryption for the payloadEncryption survives a gateway that terminates TLS
Tampering in transitSignature over the bodyCanonicalisation must match on both sides
ReplayTimestamp plus nonce cacheCache nonces for at least the timestamp window
Credential theftClient certificate or SAML assertion instead of a shared passwordKeys in an HSM or key store, never in config
RepudiationLong-lived signature with a verifiable chainKeep the signed original, not a re-serialised copy
⚠️
XML signature wrapping is the classic WS-Security attack: an attacker adds a second element with the same ID so the signature verifies against one copy while the application reads another. Defend by rejecting duplicate IDs in the message and by validating the signed part before any business logic runs.

FAQ

Is WS-Security still needed if everything is over HTTPS?
It is needed whenever the message must stay protected beyond the TLS endpoint, for example through an ESB or a store-and-forward queue, or when a partner requires an XML signature for non-repudiation.
Why do signatures fail between Java and .NET?
Almost always canonicalisation or namespace prefix differences producing a different byte sequence. Pin the exclusive canonicalisation algorithm on both sides and test with a fixed fixture.

SOAP headers and the WS-* standards SOAP in the enterprise: ESBs, gateways and middleware

Last refreshed 2026-09-18.