SOAP 訊息在網路上傳輸面臨三大風險:
WS-Security 標準在 SOAP Header 層面提供**簽名**、**加密**、**時間戳**、**安全權杖**等機制,結合公開金鑰加密體系,端到端保護訊息安全,不依賴傳輸層(如 HTTPS)。
XML 空白、屬性順序不影響語義,簽名前必須將 XML 轉為標準形式,使用 Exclusive XML Canonicalization (Exc-C14N) 算法。
keytool 管理金鑰庫。repository/modules/rampart-*.mar 存在。$JAVA_HOME/jre/lib/security/java.security,加入 security.provider.x=org.bouncycastle.jce.provider.BouncyCastleProvider。bcprov-jdk*.jar 放入 Axis2 lib/ 與 Webapp WEB-INF/lib/。build.xml、library.wsdl、Policy 檔、密碼回調類。<wsp:Policy wsu:Id="SignOnly">
<wsp:ExactlyOne><wsp:All>
<sp:AsymmetricBinding>
<wsp:Policy>
<sp:InitiatorToken> <sp:X509Token sp:IncludeToken=".../AlwaysToRecipient"/> </sp:InitiatorToken>
<sp:RecipientToken> <sp:X509Token sp:IncludeToken=".../AlwaysToInitiator"/> </sp:RecipientToken>
<sp:AlgorithmSuite> <sp:TripleDesRsa15/> </sp:AlgorithmSuite>
<sp:Layout> <sp:Strict/> </sp:Layout>
<sp:IncludeTimestamp/>
<sp:OnlySignEntireHeadersAndBody/>
</wsp:Policy>
</sp:AsymmetricBinding>
<sp:SignedParts> <sp:Body/> </sp:SignedParts>
<ramp:RampartConfig>
<ramp:user>clientkey</ramp:user>
<ramp:passwordCallbackClass>com.sosnoski.ws.library.adb.PWCBHandler</ramp:passwordCallbackClass>
<ramp:signatureCrypto>
<ramp:crypto provider="org.apache.ws.security.components.crypto.Merlin">
<ramp:property name="org.apache.ws.security.crypto.merlin.keystore.type">JKS</ramp:property>
<ramp:property name="org.apache.ws.security.crypto.merlin.file">client.keystore</ramp:property>
<ramp:property name="org.apache.ws.security.crypto.merlin.keystore.password">nosecret</ramp:property>
</ramp:crypto>
</ramp:signatureCrypto>
</ramp:RampartConfig>
</wsp:All></wsp:ExactlyOne>
</wsp:Policy>
InitiatorToken:客戶端簽名用的私鑰,憑證隨訊息發送。RecipientToken:服務端回覆簽名用的私鑰,憑證隨回覆發送。AlgorithmSuite:TripleDesRsa15 代表對稱加密 3DES,非對稱 RSA-v1.5,雜湊 SHA-1。SignedParts:僅簽名 SOAP Body。RampartConfig:指定 keystore 別名、密碼回調類、簽名加密提供者。public class PWCBHandler implements CallbackHandler {
public void handle(Callback[] callbacks) {
for (Callback cb : callbacks) {
WSPasswordCallback pwcb = (WSPasswordCallback) cb;
if (pwcb.getUsage() == WSPasswordCallback.SIGNATURE ||
pwcb.getUsage() == WSPasswordCallback.DECRYPT) {
if ("clientkey".equals(pwcb.getIdentifier())) {
pwcb.setPassword("clientpass"); // 私鑰密碼
}
}
}
}
}
<sp:RecipientToken>
<sp:X509Token sp:IncludeToken=".../Never">
<wsp:Policy> <sp:RequireThumbprintReference/> </wsp:Policy>
</sp:X509Token>
</sp:RecipientToken>
<sp:EncryptedParts> <sp:Body/> </sp:EncryptedParts>
<ramp:encryptionUser>serverkey</ramp:encryptionUser>
<ramp:encryptionCrypto> ... 同 signatureCrypto 設定 ... </ramp:encryptionCrypto>
RecipientToken IncludeToken="Never":不傳送服務端憑證,改用 **Thumbprint (SHA-1 雜湊)** 參考,減小訊息體積。EncryptedParts:指定加密 SOAP Body。encryptionUser:指定用於加密的公開金鑰別名(服務端憑證)。encryptionCrypto:指定存放服務端憑證的 keystore。<xenc:EncryptedData>。<xenc:EncryptedKey> 放在 Security Header。混合加密結合非對稱(金鑰交換)與對稱(大量資料)優點,效能與安全並重。
# 產生服務端金鑰對與憑證
keytool -genkey -alias serverkey -keypass serverpass -keyalg RSA -sigalg SHA1withRSA -keystore server.keystore -storepass nosecret
# 產生客戶端金鑰對與憑證
keytool -genkey -alias clientkey -keypass clientpass -keyalg RSA -sigalg SHA1withRSA -keystore client.keystore -storepass nosecret
# 導出服務端憑證並導入客戶端信任庫
keytool -export -alias serverkey -keystore server.keystore -storepass nosecret -file servercert.cer
keytool -import -alias serverkey -keystore client.keystore -storepass nosecret -file servercert.cer
# 導出客戶端憑證並導入服務端信任庫
keytool -export -alias clientkey -keystore client.keystore -storepass nosecret -file clientcert.cer
keytool -import -alias clientkey -keystore server.keystore -storepass nosecret -file clientcert.cer
將產生的 client.keystore 放入客戶端 classpath,server.keystore 放入服務端 classpath。
Header 包含:Timestamp、BinarySecurityToken(客戶端憑證)、Signature(SignedInfo + SignatureValue + KeyInfo)。Body 為明文。
Header 額外包含:EncryptedKey(加密的對稱金鑰 + Thumbprint 參考服務端憑證)。Body 替換為 EncryptedData。
Axis2 + Rampart 提供標準相容的 WS-Security 實作。透過 Policy 驅動配置,分離業務邏輯與安全邏輯。掌握「非對稱加密基礎 → Policy 配置 → Keystore 管理 → 訊息結構」四大支柱,即可建構企業級安全 Web 服務。