【问题标题】:Payeezy / Firstdata Invalid signature receivedPayeezy / Firstdata 收到无效签名
【发布时间】:2023-04-02 05:05:01
【问题描述】:

我目前正在开发一个使用 payeezy/firstdata 进行付款的网站。集成起来相当麻烦,因为他们的 API 文档有点弱。

我正在使用 ColdFusion 和 cfhttp 请求。我一直在按照这个来计算我的内容摘要和 hmac 哈希:https://support.payeezy.com/hc/en-us/articles/203731149-API-Security-HMAC-Hash

我终于得到了与演示终端中计算的哈希值相匹配的哈希值,但 我的问题是:我在发送请求时遇到了一个奇怪的错误。我得到错误:

“收到的签名无效'Fgx/lR############'。”

前几个字符每次都会改变。这是我的请求代码:

postAction = https://api.demo.globalgatewaye4.firstdata.com/transaction/v19 key_id,hmac_value, content_digest 都经过测试,都是正确的 x_time = getIsoTimeString(now())

<cfhttp url="#postAction#" method="POST">
            <cfhttpparam name="Authorization" type="header" value="CGGE4_API #key_id#:#hmac_value#">
            <cfhttpparam name="x-gge4-date" type="header" value="#x_time#">
            <cfhttpparam name="x-gge4-content-sha1" type="header" value="#LCase(content_digest)#">
            <cfhttpparam name="content-type" type="header" value="text/xml">
            <cfhttpparam name="accept" type="header" value="text/xml">      
            <cfhttpparam name="transaction_body" type="xml" value="#exact_xml#" />                
        </cfhttp>
<cfdump var="#cfhttp.fileContent#"><cfabort>

提交的xml(不含空格或换行)

<Transaction>
                <ExactID>#exact_id#</ExactID>
                <Password>#password#</Password>
                <Card_Number>#FORM.x_card_num#</Card_Number>
                <CardHoldersName>#FORM.x_first_name# #FORM.x_last_name#</CardHoldersName>
                <Transaction_Type>00</Transaction_Type>
                <Expiry_Date>#FORM.x_exp_date#</Expiry_Date>
                <DollarAmount>#amount#</DollarAmount>
                <Address>
                    <Address1>#FORM.x_address#</Address1>
                    <City>#FORM.x_city#</City>
                    <Zip>#FORM.x_zip#</Zip>
                </Address>
            </Transaction>

我已将授权标头更改为“Payeezy_Gateway_API #key_id#:#hmac_value#”,当正在使用的 hmac 值和密钥 ID 在 payeezy 终端上多次测试时,我收到错误“授权标头错误”。

拜托,非常感谢任何帮助!

【问题讨论】:

  • 只是猜测,但您是否在计算中包含字符集? IIRC,cfhttp 默认添加“UTF-8”。 Payeezy 文档说,“如果内容类型标头中包含字符集,则也必须在计算中使用它(计算器中对此没有规定)”。可能是问题。您使用 Fiddler 查看它正在发送什么,或者失败,将 cfhttp 指向您服务器上的一个 .cfm 页面,该页面执行 GetHTTPRequestData() 的转储。
  • 另外,你确定它是“CGGE4_API”吗?一些示例使用“GGE4_API”代替。不确定哪个是正确的。

标签: xml hash coldfusion cfhttp firstdata


【解决方案1】:

在您链接的支持页面上使用他们的示例 Python 代码进行测试时,CGGE4_API 和 GGE4_API 都对我有用,但我拨打了他们的支持号码,他们告诉我应该使用 GGE4_API。

显然支持页面已过时,使用 Payeezy_Gateway_API 根本不起作用。以下是该页面上的示例 Python 代码如下所示:

from hashlib import sha1
from time import gmtime, strftime
import base64
import hmac
import httplib

payeezy_gateway_date = strftime("%Y-%m-%dT%H:%M:%S", gmtime()) + 'Z'
uri = '/transaction/v19'
key_id = '' # Add your key id here
key = '' # Add your HMAC key here
transaction_body = '' # Add your transaction request body here
method = 'POST'
content_digest = sha1(transaction_body).hexdigest()
content_type = 'text/xml' # Change this to 'application/json' if you're using JSON
host = 'api.demo.globalgatewaye4.firstdata.com'
headers = { 'Content-Type': content_type,
        'x-gge4-content-sha1': content_digest,
        'x-gge4-date': payeezy_gateway_date,
        'Authorization': 'GGE4_API ' + key_id + ':' + base64.b64encode(hmac.new(key, method + "\n" + content_type + "\n" + content_digest + "\n" + payeezy_gateway_date + "\n" + uri.split('?')[0], sha1).digest()) }
conn = httplib.HTTPSConnection(host)
conn.request(method, uri, transaction_body, headers)
print conn.getresponse().read()

在我的申请中,我还收到了收到的无效签名。事实证明,我将charset=utf-8 添加到我的Content-Type 标题中,(归功于Leigh's comment)。删除使我的请求被接受。

【讨论】:

  • 是的,我已经在coding ground 上测试了 python 和 C# 示例。由于它们都有效,因此它表明 cfhttp 标头中的文本前缀或额外字符集存在问题,但在没有询问者确认的情况下,它似乎不足以作为答案发布。希望他们会以“是或否”回复。
  • 换句话说,听起来我们都得出了相同的结论;-)
  • 说实话,我写的大部分内容都来自您的评论。在确认我的支持电话中的详细信息后,我只是想为未来的访问者添加一个更明确的答案。所以给你的道具,@Leigh。
  • 希望它会促使提问者做出回应,因为老实说,在查看和测试示例后,我对问题的解决方案有点好奇:-)
  • 不相关的注释,但肯定有人会碰到它。如果您收到无法描述的 500 错误,则可能是由于您的请求正文中的 JSON 格式错误。至少,这就是发生在我身上的事情。
【解决方案2】:

我也试图用 Payeezy 解决这个问题。我可能迟到了一天,还少了一美元,但是我得到了这个工作。我对我遇到的问题和/或 Nick 的原始代码进行了一些更改:

  1. 删除了事务 xml 中的字符集声明;
  2. 将“文本”更改为“应用程序”
  3. 为了让加密与网站的测试加密相匹配,我将回车改为char(10),然后
  4. 将第一个标头条目从“CGGE4_API”更改为“GGE_API”

仅供参考,如果您使用的是 v11,则不需要任何标头或哈希代码,只需 xml。

这是我的整个测试代码,包括一些分解返回 xml 的代码。

请求代码:

<cfset hmac_key="WO9QVjnis6eBb5oOYmA_DSShc82gteFw">
<cfset trans="<?xml version='1.0' ?><Transaction><ExactID>XX55555-55</ExactID><Password>testtest11</Password><Card_Number>5454545454545454</Card_Number><CardHoldersName>Bix Dirigible</CardHoldersName><Transaction_Type>00</Transaction_Type><Expiry_Date>0916</Expiry_Date><DollarAmount>12.03</DollarAmount></Transaction>">

<cfset key_id="555555">
<cfset content_digest=lcase(Hash(trans,"SHA"))>

<cfset curDate = Now()> 
<cfset utcDate = DateConvert("local2utc", curDate)> 
<cfset udate=dateformat(utcdate,"yyyy-mm-dd")><cfset utime=timeformat(utcdate,"HH:mm:ss")>
<cfset x_time=udate&"T"&utime&"Z" >

<cfset submitfinalhmac="POST"&chr(10)&"application/xml"&chr(10)&content_digest&chr(10)&x_time&chr(10)&"/transaction/v12">


<cfoutput>
    content_digest: #content_digest#<BR />
    <BR />

    <!--- Ben Nadel's encrypting code, http://www.bennadel.com/blog/1971-authenticating-twilio-request-signatures-using-coldfusion-and-hmac-sha1-hashing.htm --->
    <cfset secretKeySpec = createObject("java", "javax.crypto.spec.SecretKeySpec" ).init( toBinary( toBase64( hmac_key ) ), "HmacSHA1" )/>
    <cfset mac = createObject( "java", "javax.crypto.Mac" ).getInstance( "HmacSHA1" )/> 
    <cfset mac.init( secretKeySpec ) />
    <cfset encryptedBytes = mac.doFinal( toBinary( toBase64( submitfinalhmac ) )  ) /> 
    <cfset secureSignature = createObject( "java", "org.apache.commons.codec.binary.Base64" ).encodeBase64( encryptedBytes ) /> 
    <cfset hmac_value = toString( secureSignature ) />
    #hmac_value#
    <BR /><BR />
 </cfoutput>    

 <cfhttp method="Post" url="https://api.demo.globalgatewaye4.firstdata.com/transaction/v12"
    useragent="Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.1599.69 Safari/537.36">
     <cfhttpparam name="Authorization" type="header" value="GGE4_API #key_id#:#hmac_value#">
     <cfhttpparam name="x-gge4-date" type="header" value="#x_time#">
     <cfhttpparam name="x-gge4-content-sha1" type="header" value="#content_digest#">
     <cfhttpparam name="content-type" type="header" value="application/xml">
     <cfhttpparam name="accept" type="header" value="application/xml">
     <cfhttpparam name="transaction_body" type="xml" value="#trans#" />  
</cfhttp>

响应码:

<cfset postresult=HTMLEditFormat(cfhttp.fileContent)>
<cfset postresult=replace(postresult,"&lt;","<","all")>
<cfset postresult=replace(postresult,"&gt;",">","all")>
<cfset postresult=replace(postresult,"##","-","all")>

<cfoutput> 
    #postresult#<BR />
    <cfset badtransaction=0><cfset badtransactionmessage="">
    <cfset rawerror="">
    <cfif findnocase("bad request",postresult)><cfset rawerror=trim(gettoken(postresult,2,"-"))>
        <cfset badtransactionmessage=badtransactionmessage&rawerror>
        <cfset badtransaction=1>
    </cfif>
    <cfif findnocase("unauthorized request",postresult)><cfset rawerror=trim(gettoken(postresult,2,"."))>
        <cfset badtransactionmessage=badtransactionmessage&rawerror>
        <cfset badtransaction=1>
    </cfif>

    <cfset resultarray=arraynew(2)>
    <cfset line=1>
    <cfset enterflag=0>
    <cfset startflag=0>
    <cfloop index="getchar" from="1" to="#len(postresult)-22#">
        <cfif mid(postresult,getchar,9) is "<exactid>" ><cfset startflag=1></cfif>
        <cfif mid(postresult,getchar,19) is "</TransactionResult>" ><cfset startflag=0></cfif>

        <cfif startflag is 1>
            <cfif enterflag is 2>
                <cfif mid(postresult,getchar,1)  is "<"><cfset enterflag=0><cfset line++>
            <cfelse>
                <cfset resultarray[line][2]=resultarray[line][2]&mid(postresult,getchar,1)>
            </cfif>
        </cfif>

        <cfif enterflag is 1>
            <cfif mid(postresult,getchar,1)  is ">" >
                <cfset enterflag=2>
            <cfelse>
                <cfset resultarray[line][1]=resultarray[line][1]&mid(postresult,getchar,1)>
            </cfif>
        </cfif>

        <cfif enterflag is 0>
            <cfif mid(postresult,getchar,1)  is "<" and mid(postresult,getchar+1,1) is not "/">
                <cfset enterflag=1>
                <cfset resultarray[line][1]="">
                <cfset resultarray[line][2]="">
            </cfif>
        </cfif>
    </cfif>
   </cfloop>

    <cfdump var="#resultarray#">

    <cfset transactiontag="">
    <cfset authorizationnum="">
    <cfset transactionapproved="">
    <cfset exactmessage="">
    <cfset exactresponsecode="">
    <cfset sequenceno="">
    <cfset retrievalrefno="">
    <cfset cardtype="">
    <cfset bankmessage="">

    <cfloop index="getresponses" from="1" to ="#arraylen(resultarray)#">
        <cfif resultarray[getresponses][1] is "Transaction_Tag"><cfset transactiontag=resultarray[getresponses][2]></cfif>
        <cfif resultarray[getresponses][1] is "Authorization_Num"><cfset AuthorizationNum=resultarray[getresponses][2]></cfif>
        <cfif resultarray[getresponses][1] is "Transaction_Approved"><cfset TransactionApproved=resultarray[getresponses][2]></cfif>
        <cfif resultarray[getresponses][1] is "EXact_Message"><cfset EXactMessage=resultarray[getresponses][2]></cfif>
        <cfif resultarray[getresponses][1] is "EXact_Resp_Code"><cfset EXactResponseCode=resultarray[getresponses][2]></cfif>
        <cfif resultarray[getresponses][1] is "SequenceNo"><cfset SequenceNo=resultarray[getresponses][2]></cfif>
        <cfif resultarray[getresponses][1] is "Retrieval_Ref_No"><cfset RetrievalRefNo=resultarray[getresponses][2]></cfif>
        <cfif resultarray[getresponses][1] is "CardType"><cfset CardType=resultarray[getresponses][2]></cfif>
        <cfif resultarray[getresponses][1] is "bank_message"><cfset bankmessage=resultarray[getresponses][2]></cfif>
  </cfloop>

    <BR />
    #transactiontag#<BR />
    #authorizationnum# <BR />
    #transactionapproved# <BR />
    #exactmessage#<BR />
    #exactresponsecode#<BR />
    #sequenceno#<BR />
    #retrievalrefno#<BR />
    #cardtype#<BR />
    #bankmessage#<BR />

    <cfif trim(transactionapproved) is not "true" and trim(transactionapproved) is not "">
        <cfset badtransaction=2>
        <cfset badtransactionmessage=badtransactionmessage&bankmessage>
    </cfif>

    <cfif badtransaction gt 0>
        ---#badtransactionmessage#<BR />
    </cfif>

</cfoutput>

【讨论】:

  • 总是很高兴听到问题解决了。那么哪些步骤产生了影响呢?
  • 嗨,我对我遇到的问题和/或 Nick 的原始代码进行了一些更改:1)删除了事务 xml 中的字符集声明; 2) 将 'text' 更改为 'application',3) 为我获取哈希以匹配网站的测试哈希,我将回车更改为 char(10),以及 4) 将第一个标题条目从 'CGGE4_API' 更改为'GGE_API' -- 仅供参考,如果您使用的是 v11,则不需要任何标头或哈希代码,只需 xml。
  • (Edit) 关于响应处理,为什么要使用 HTMLEditFormat(cfhttp.fileContent)?只是猜测,但如果响应是 XML,则将其解析为文档可能更容易,即XMLParse。然后您可以使用点符号更轻松地提取相关部分,即yourDoc.TransactionResult.someKeyName :)
猜你喜欢
  • 2018-04-14
  • 2020-11-23
  • 2019-03-24
  • 1970-01-01
  • 1970-01-01
  • 2012-08-03
  • 2017-07-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多