Golang中Soap、x509与wsse的实现与应用

Golang中Soap、x509与wsse的实现与应用 你好

我正在寻找是否存在任何Go语言库,其中已经实现了SOAP的WSSE安全功能? 我需要这个用于一个项目。

谢谢

1 回复

更多关于Golang中Soap、x509与wsse的实现与应用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go语言中,实现SOAP的WSSE(WS-Security)安全功能通常需要结合多个库来处理SOAP协议、XML签名和x509证书。虽然Go标准库和第三方库没有直接提供完整的WSSE实现,但可以通过以下方式构建:

  1. SOAP处理:使用第三方库如github.com/hooklift/gowsdl生成SOAP客户端代码,或手动构建SOAP信封。
  2. WSSE头生成:手动创建WSSE安全头,包括UsernameToken或x509证书信息。
  3. x509证书处理:使用Go标准库crypto/x509crypto/tls加载和验证证书。
  4. XML签名:使用github.com/russellhaering/goxmldsig库进行XML签名和验证,这是WSSE的核心部分。

下面是一个示例代码,展示如何构建一个简单的SOAP请求,并添加WSSE安全头(使用UsernameToken)。注意,这只是一个基础示例,实际WSSE实现可能更复杂,涉及时间戳、非ce和签名。

package main

import (
    "bytes"
    "crypto/sha1"
    "encoding/base64"
    "encoding/xml"
    "fmt"
    "io/ioutil"
    "net/http"
    "time"
)

// 定义SOAP信封结构
type Envelope struct {
    XMLName xml.Name `xml:"soap:Envelope"`
    Soap    string   `xml:"xmlns:soap,attr"`
    Header  Header   `xml:"soap:Header"`
    Body    Body     `xml:"soap:Body"`
}

type Header struct {
    Security Security `xml:"wsse:Security"`
}

type Security struct {
    XMLName   xml.Name  `xml:"wsse:Security"`
    Wsse      string    `xml:"xmlns:wsse,attr"`
    Timestamp Timestamp `xml:"wsu:Timestamp"`
    Token     UsernameToken
}

type Timestamp struct {
    XMLName xml.Name `xml:"wsu:Timestamp"`
    Wsu     string   `xml:"xmlns:wsu,attr"`
    Created string   `xml:"wsu:Created"`
    Expires string   `xml:"wsu:Expires"`
}

type UsernameToken struct {
    XMLName  xml.Name `xml:"wsse:UsernameToken"`
    Username string   `xml:"wsse:Username"`
    Password Password `xml:"wsse:Password"`
    Nonce    Nonce    `xml:"wsse:Nonce"`
    Created  string   `xml:"wsu:Created"`
}

type Password struct {
    Type  string `xml:"Type,attr"`
    Value string `xml:",chardata"`
}

type Nonce struct {
    Type  string `xml:"EncodingType,attr"`
    Value string `xml:",chardata"`
}

type Body struct {
    Content string `xml:",innerxml"` // 替换为实际SOAP体内容
}

// 生成WSSE头(使用UsernameToken)
func generateWSSEHeader(username, password string) Security {
    nonce := make([]byte, 16)
    // 在实际应用中,应使用crypto/rand生成随机nonce
    // rand.Read(nonce)
    nonceEncoded := base64.StdEncoding.EncodeToString(nonce)
    created := time.Now().UTC().Format("2006-01-02T15:04:05Z")
    expires := time.Now().Add(5 * time.Minute).UTC().Format("2006-01-02T15:04:05Z")
    
    // 计算密码摘要(WSSE规范)
    hasher := sha1.New()
    hasher.Write(nonce)
    hasher.Write([]byte(created))
    hasher.Write([]byte(password))
    passwordDigest := base64.StdEncoding.EncodeToString(hasher.Sum(nil))

    return Security{
        Wsse: "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
        Timestamp: Timestamp{
            Wsu:     "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd",
            Created: created,
            Expires: expires,
        },
        Token: UsernameToken{
            Username: username,
            Password: Password{
                Type:  "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest",
                Value: passwordDigest,
            },
            Nonce: Nonce{
                Type:  "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary",
                Value: nonceEncoded,
            },
            Created: created,
        },
    }
}

func main() {
    username := "your-username"
    password := "your-password"
    
    // 构建SOAP信封
    envelope := Envelope{
        Soap: "http://schemas.xmlsoap.org/soap/envelope/",
        Header: Header{
            Security: generateWSSEHeader(username, password),
        },
        Body: Body{
            Content: "<your-soap-body>Replace with actual SOAP body content</your-soap-body>",
        },
    }

    // 序列化为XML
    xmlData, err := xml.MarshalIndent(envelope, "", "  ")
    if err != nil {
        panic(err)
    }

    // 发送SOAP请求
    client := &http.Client{}
    req, err := http.NewRequest("POST", "https://your-soap-endpoint.com", bytes.NewBuffer(xmlData))
    if err != nil {
        panic(err)
    }
    req.Header.Set("Content-Type", "text/xml; charset=utf-8")
    req.Header.Set("SOAPAction", "your-soap-action") // 如果端点需要

    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Println("Response:", string(body))
}

对于x509证书的WSSE实现,需要使用crypto/x509加载证书和私钥,并通过goxmldsig库进行XML签名。以下是添加x509签名的简要示例:

import (
    "crypto/x509"
    "encoding/pem"
    "github.com/russellhaering/goxmldsig"
)

// 加载x509证书和私钥
func loadCertificateAndKey(certPath, keyPath string) (*x509.Certificate, interface{}, error) {
    certPEM, err := ioutil.ReadFile(certPath)
    if err != nil {
        return nil, nil, err
    }
    block, _ := pem.Decode(certPEM)
    cert, err := x509.ParseCertificate(block.Bytes)
    if err != nil {
        return nil, nil, err
    }

    keyPEM, err := ioutil.ReadFile(keyPath)
    if err != nil {
        return nil, nil, err
    }
    keyBlock, _ := pem.Decode(keyPEM)
    privateKey, err := x509.ParsePKCS1PrivateKey(keyBlock.Bytes) // 或使用其他解析方法
    if err != nil {
        return nil, nil, err
    }

    return cert, privateKey, nil
}

// 使用goxmldsig签名SOAP体
func signSOAPBody(bodyContent string, cert *x509.Certificate, privateKey interface{}) (string, error) {
    ctx := dsig.NewDefaultSigningContext(dsig.TLSCertKeyStore(cert, privateKey))
    signed, err := ctx.SignString(bodyContent)
    if err != nil {
        return "", err
    }
    return signed, nil
}

在实际项目中,您需要根据WSSE规范调整这些代码,并可能处理更复杂的安全策略。建议参考OASIS WSSE标准文档以确保兼容性。

回到顶部