【问题标题】:Creating secure web services with ColdFusion使用 ColdFusion 创建安全的 Web 服务
【发布时间】:2011-06-22 14:16:39
【问题描述】:

我使用使用内联身份验证的 ColdFusion 创建了一个带有 Web 服务的现有 API,但我想使用某种身份验证来保护它,但我不知道从哪里开始。

Web 服务是由 ColdFusion 通过将 ?wsdl 添加到我的 cfcs 末尾自动生成的。

当我说“”时,我的意思是对于每个 Web 服务调用,客户端必须在soapenv:body 中传递一个键/传递,如下所示:

<apiKey xsi:type="xsd:string">test</apiKey>
<apiPass xsi:type="xsd:string">test!ng</apiPass>

但我想我想使用 WS-Security 或基本身份验证,但我不知道我在做什么。

在 CF 社区中似乎没有人按照我的要求行事,这似乎很奇怪。

【问题讨论】:

    标签: web-services security coldfusion wsdl ws-security


    【解决方案1】:

    我一般不喜欢 WSE (http://oasis-open.org/) 或 SOAP,但它在集成情况下很有用,例如,我们在使用 .NET Web 服务时使用过它。

    我的偏好是在与 Web 服务相同的目录中使用Application.cfc,以通过 IP 和安全令牌或用户名/密码对请求进行身份验证。我们将其用于其他人使用的 RESTful Web 服务。或者,您可以将身份验证代码作为 Web 服务处理本身的一部分。

    如果您必须使用 WSE,您需要在发送 SOAP 数据包时使用 addSOAPRequestHeader() 添加一堆 SOAP 标头,然后在收到响应时检查这些相同的标头。这可能很混乱,但这里有一些对我们有用的代码:

    <cffunction name="AddSecurityHeaders" access="public" returntype="any" hint="This adds the security headers as defined in the WS Security section of the WSS standard. Username and password are unencrypted." output="Yes">
            <cfargument name="webSvc" required="Yes" type="any" hint="This must be a vaild web service."> 
            <cfargument name="username" required="Yes" type="string" hint="Username required by webservice being called."> 
            <cfargument name="password" required="Yes" type="string" hint="Password required by web service being called."> 
            <cfargument name="action" required="Yes" type="string" hint="Value to be inseted into wsa:Action node."> 
            <cfargument name="to" required="Yes" type="string" hint="Value to be inseted into wsa:To node."> 
            <cfargument name="mustUnderstandSecurityHdr" required="No" type="boolean" default="false" hint="This value will be inserted into the <wsse:Security> header as the 'mustUnderstand' value."> 
    
            <cfscript>
    
            var rightNow = "" ;
            var expiryTime = "" ;
            var objXmlAction = "" ;
            var objXmlMessageID = "" ;
            var objXmlTo = "" ;
            var objXmlSecurity = "" ;
            var objXmlReplyTo = "" ;
            var objTimezone = CreateObject("component", "com.utils.timezone") ;
    
            // Setup times (UTC/GMT only!)
            rightNow = objTimezone.castToUTC(Now()) ;
            expiryTime = DateAdd("n", 5, rightNow) ;
    
            // Create XML doument and add required nodes starting with <wsa:Action>
            objXmlAction = XmlNew() ;
            objXmlAction.XmlRoot = XmlElemNew(objXmlAction,  "http://schemas.xmlsoap.org/ws/2004/03/addressing", "wsa:Action") ;
            objXmlAction.XmlRoot.XmlText = ARGUMENTS.action ;
    
            // ..then <wsa:MessageID>
            objXmlMessageID = XmlNew() ;
            objXmlMessageID.XmlRoot = XmlElemNew(objXmlMessageID,  "http://schemas.xmlsoap.org/ws/2004/03/addressing", "wsa:MessageID") ;
            objXmlMessageID.XmlRoot.XmlText = "uuid:" & CreateUUID() ;
    
            // ...then <wsa:Address>
            objXmlReplyTo = XmlNew() ;
            objXmlReplyTo.XmlRoot = XmlElemNew(objXmlReplyTo,  "http://schemas.xmlsoap.org/ws/2004/03/addressing", "wsa:ReplyTo") ;
            objXmlReplyTo.XmlRoot.XMLChildren[1] = XmlElemNew(objXmlReplyTo,  "wsa:Address") ;
            objXmlReplyTo.XmlRoot.XMLChildren[1].XmlText = "http://schemas.xmlsoap.org/ws/2004/03/addressing/role/anonymous" ;
    
            // ..then <wsa:To>
            objXmlTo = XmlNew() ;
            objXmlTo.XmlRoot = XmlElemNew(objXmlTo,  "http://schemas.xmlsoap.org/ws/2004/03/addressing", "wsa:To") ;
            objXmlTo.XmlRoot.XmlText = ARGUMENTS.to ;
    
            // ..then the main <wsse:Security> node which contains further info...
            objXmlSecurity = XmlNew(true) ;
            objXmlSecurity.XmlRoot = XmlElemNew(objXmlSecurity,  "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "wsse:Security") ;
            // ...note: this namespace is added as it is used in children nodes and this can help avoid XmlSearch errors in CFMX
            //StructInsert(objXmlSecurity.XmlRoot.XmlAttributes, "xmlns:wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd") ;
    
             // ...Timestamp, it's children and attributes
            objXmlSecurity.XmlRoot.XMLChildren[1] = XmlElemNew(objXmlSecurity,  "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "wsu:Timestamp") ;
            StructInsert(objXmlSecurity.XmlRoot.XMLChildren[1].XmlAttributes, "wsu:Id", "Timestamp-#CreateUUID()#") ;
    
            objXmlSecurity.XmlRoot.XMLChildren[1].XmlChildren[1] = XmlElemNew(objXmlSecurity, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "wsu:Created") ;
            objXmlSecurity.XmlRoot.XMLChildren[1].XmlChildren[1].XmlText = DateFormat(rightNow, "YYYY-MM-DD") & "T" & TimeFormat(rightNow, "HH:mm:ss") & "Z" ;
            objXmlSecurity.XmlRoot.XMLChildren[1].XmlChildren[2] = XmlElemNew(objXmlSecurity, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "wsu:Expires") ;
            objXmlSecurity.XmlRoot.XMLChildren[1].XmlChildren[2].XmlText = DateFormat(expiryTime, "YYYY-MM-DD") & "T" & TimeFormat(expiryTime, "HH:mm:ss") & "Z" ;
            // ...Username token, attributes and children 
            objXmlSecurity.XmlRoot.XMLChildren[2] = XmlElemNew(objXmlSecurity,  "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "wsse:UsernameToken") ;
            StructInsert(objXmlSecurity.XmlRoot.XMLChildren[2].XmlAttributes, "xmlns:wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd") ;
            StructInsert(objXmlSecurity.XmlRoot.XMLChildren[2].XmlAttributes, "wsu:Id", "SecurityToken-#CreateUUID()#") ;
            // ...UsernameToken.Username
            objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[1] = XmlElemNew(objXmlSecurity, "wsse:Username") ;
            objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[1].XmlText = Trim(ARGUMENTS.username) ;
            // ...UsernameToken.Password 
            objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[2] = XmlElemNew(objXmlSecurity, "wsse:Password") ;
            StructInsert(objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[2].XmlAttributes, "Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0##PasswordText") ; 
            objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[2].XmlText = Trim(ARGUMENTS.password) ;
            // ... Nonce 
            objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[3] = XmlElemNew(objXmlSecurity, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "wsse:Nonce") ;
            objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[3].XmlText = ToBase64(CreateUUID()) ;
            // ...Created 
            objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[4] = XmlElemNew(objXmlSecurity, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "wsu:Created") ;
            objXmlSecurity.XmlRoot.XMLChildren[2].XmlChildren[4].XmlText = DateFormat(rightNow, "YYYY-MM-DD") & "T" & TimeFormat(rightNow, "HH:mm:ss") & "Z" ;
    
            // Add the created headers to the soap requests - note that the 2nd and 3rd parameters have no significance in this instance
            addSOAPRequestHeader(ARGUMENTS.webSvc, "sia1", "hd1", "#objXmlAction#", false) ;
            addSOAPRequestHeader(ARGUMENTS.webSvc, "sia1", "hd1", "#objXmlMessageID#", false) ;
            addSOAPRequestHeader(ARGUMENTS.webSvc, "sia1", "hd1", "#objXmlReplyTo#", false) ;
            addSOAPRequestHeader(ARGUMENTS.webSvc, "sia1", "hd1", "#objXmlTo#", false) ;
            addSOAPRequestHeader(ARGUMENTS.webSvc, "sia1", "hd1", "#objXmlSecurity#", ARGUMENTS.mustUnderstandSecurityHdr) ;
    
            return ARGUMENTS.webSvc ;
    
            </cfscript>
    
        </cffunction>
    

    这是一个使用示例:

    // Create web service
    objWebSvc = CreateObject("webservice", "remoteWebService?WSDL") ;
    
    // Create security object and add the security header to our SOAP request
    objWSESecurity = CreateObject("component", "wse") ;
    
    objWebSvc = objWSESecurity.AddSecurityHeaders(
        webSvc=objWebSvc,
        username="xxx", 
        password="yyy", 
        action="remoteAction", 
        to="remoteWebService", 
        mustUnderstandSecurityHdr=false
    ) ;
    

    你看 - 很多代码 :) 无论如何希望它有所帮助。

    【讨论】:

    • 感谢您的回复!我了解您的函数的作用,但我不确定将其放置在何处或如何调用它。我正在像mysite.com/news.cfc?wsdl 这样提供我的网络服务 - 现在我如何获得这个函数来拦截对 cfc 的调用?对不起,我的困惑,再次感谢。
    • 我已经更新了上面的代码,但有趣的是,我们已经通过这种集成远离了 WSE - 它被视为麻烦的根源,不值得付出努力。他们现在根据我们传递的身份验证凭据作为其服务请求的一部分进行身份验证。
    猜你喜欢
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2021-12-21
    • 1970-01-01
    • 1970-01-01
    • 2010-09-14
    • 2010-10-02
    • 1970-01-01
    相关资源
    最近更新 更多