ColdFusion CFHTTP с SHA512-hmac подписанным телом запроса REST - программирование
Подтвердить что ты не робот

ColdFusion CFHTTP с SHA512-hmac подписанным телом запроса REST

Я пытаюсь сделать подписанный запрос в торговый API на bitfloor.com(это REST API)

Bitfloor дает мне:

1) Ключ API (то есть 6bd2b780-00be-11e2-bde3-2837371c3c3a)

2) Секретный ключ (т.е. oaFz62YpmbWiXwseMUSod53D8pOjdyVcweNYdiab/TSQqxk6IuemDvimNaQoA ==)

Ниже приведены точные инструкции Bitfloor для запроса:

Запросами должны быть запросы HTTPS POST на порт 443 (https). Каждый запрос должен содержать требуемые заголовки (перечисленные ниже). Заголовки идентифицируют, проверяют и подтверждают ваш запрос, чтобы предотвратить вмешательство. заголовки

bitfloor-key. Это предоставленный бит-полом для уникальной идентификации вашей учетной записи. (то есть 6bd2b780-00be-11e2-bde3-2837371c3c3a)

bitfloor-sign Поле знака представляет собой sha512-hmac тела запроса, используя секретный ключ, соответствующий вашему ключу api.

Чтобы подписать ваш запрос: base64 декодирует секретный ключ в необработанные байты (64 байта). Используйте эти байты для вашего подписания sha512-hmac тела запроса http. Base64 кодирует результат подписи и отправляет это поле заголовка.

bitfloor-passphrase Ключевая фраза, которую вы указали при создании этого ключа api. Мы не можем восстановить ваш пароль, если забыли. Вам нужно будет создать новый ключ API.

bitfloor-version Версия api интересующего вас ресурса. Единственное допустимое значение в настоящее время: 1


После долгих восьми часов проб и ошибок и повторного поиска в Интернете для получения какой-либо информации или информации, следующий код будет настолько близок, насколько я могу прийти к тому, что, по моему мнению, может быть где-то в направлении того, как построить просьба должным образом, увы, независимо от того, что я attmept, я получаю "Invalid Signature", возвращенный их API.

Вот что я до сих пор...

FIRST, я нашел эту функцию в Интернете, которую кто-то написал для подписания SHA512:

<cffunction name="HMAC_SHA512" returntype="binary" access="public" output="false">
    <cfargument name="signKey" type="string" required="true">
    <cfargument name="signMessage" type="string" required="true">

    <cfset var jMsg = JavaCast("string",arguments.signMessage).getBytes("iso-8859-1")>
    <cfset var jKey = JavaCast("string",arguments.signKey).getBytes("iso-8859-1")>
    <cfset var key  = createObject("java","javax.crypto.spec.SecretKeySpec")>
    <cfset var mac  = createObject("java","javax.crypto.Mac")>
    <cfset key  = key.init(jKey,"HmacSHA512")>
    <cfset mac  = mac.getInstance(key.getAlgorithm())>
    <cfset mac.init(key)>
    <cfset mac.update(jMsg)>
    <cfreturn mac.doFinal()>
</cffunction>

Я понятия не имею, что он делает, но, похоже, работает и делает это без ошибок.

Вот моя реализация этой функции и моя попытка сделать запрос: ПРИМЕЧАНИЕ. Значение "nonce" является обязательным параметром, который должен быть отправлен с запросом.

<cffunction name="myorders">
    <cfset nonce        = dateDiff("s",createDateTime(2012,01,01,0,0,0),now())>
    <cfset requestbody  = "?nonce=#nonce#">
    <cfset key      = "oaFz62YpmbWiXwseMUSod53D8pOjdyVcweNYdiab/TSQqxk6IuemDvimNaQoA==">
    <cfset sign     = HMAC_SHA512(key,requestbody)>
    <cfset signed       = binaryEncode(sign,"Base64")>

    <!--- HTTP REQUEST --->
    <cfhttp url = "https://api.bitfloor.com/orders#requestbody#"
        method  = "post"
        result  = "bitfloor">

    <!--- HEADERS --->
    <cfhttpparam
        type    = "body"
        value   = requestbody>
    <cfhttpparam
        type    = "header"
        name    = "bitfloor-key"
        value   = "6bd2b780-00be-11e2-bde3-2837371c3c3a">
    <cfhttpparam
        type    = "header"
        name    = "bitfloor-sign"
        value   = signed>
    <cfhttpparam
        type    = "header"
        name    = "bitfloor-passphrase"
        value   = "mysecretpassphrase">
    <cfhttpparam
        type    = "header"
        name    = "bitfloor-version"
        value   = "1">
    </cfhttp>
</cffunction>

Я думаю, что большая часть моей путаницы исходит из того, что я точно не знаю, что такое "тело запроса". Я чувствую, что, возможно, я не подхожу правильно.

Надеюсь, есть программист Coldfusion, который знаком с подписанными запросами. Я нахожусь на своем конце.

Пожалуйста, помогите! Namaste

4b9b3361

Ответ 1

Я не использовал этот api, но я провел несколько тестов и, похоже, работал со следующими настройками:

  • Поскольку значение secretKey кодируется base64, ваша функция подписи должна использовать binaryDecode для правильного извлечения байтов. Использование String.getBytes(...) дает совершенно другой (и неправильный) результат.

  • Ожидаемое значение тела запроса равно: nonce=#nonceValue# (без ведущего "?")

  • Кажется, что требуется заголовок Content-Type=application/x-www-form-urlencoded, иначе он не сможет проанализировать содержимое и ответ будет следующим: { "error": "no nonce specified" }

Код

 <cfset apiKey = "6bd2b780-00be-11e2-bde3-2837371c3c3a">
 <cfset secretKey = "oaFz62YpmbWiXwseMUSod53D8pOjdyVcweNYdiab/TSQqxk6IuemDvimNaQoA==">
 <cfset passphrase = "your secret phrase">

 <cfset requestBody  = "nonce="& now().getTime()>
 <cfset signBytes    = HMAC_SHA512(secretKey, requestbody)>
 <cfset signBase64   = binaryEncode(signBytes, "base64")>

 <cfhttp url="https://api.bitfloor.com/orders" method="post" port="443" result="bitfloor">
    <cfhttpparam type="header" name="Content-Type" value="application/x-www-form-urlencoded">
    <cfhttpparam type="header" name="bitfloor-key" value="#apiKey#">
    <cfhttpparam type="header" name="bitfloor-sign" value="#signBase64#">
    <cfhttpparam type="header" name="bitfloor-passphrase" value="#passphrase#">
    <cfhttpparam type="header" name="bitfloor-version" value="1">
    <cfhttpparam type="body" value="#requestBody#">
 </cfhttp>

 <cfdump var="#bitfloor#" label="Response">

<cffunction name="HMAC_SHA512" returntype="binary" access="public" output="false">
    <cfargument name="base64Key" type="string" required="true">
    <cfargument name="signMessage" type="string" required="true">
    <cfargument name="encoding" type="string" default="UTF-8">

     <cfset var messageBytes = JavaCast("string",arguments.signMessage).getBytes(arguments.encoding)>
     <cfset var keyBytes = binaryDecode(arguments.base64Key, "base64")>
     <cfset var key  = createObject("java","javax.crypto.spec.SecretKeySpec")>
     <cfset var mac  = createObject("java","javax.crypto.Mac")>
     <cfset key  = key.init(keyBytes,"HmacSHA512")>
     <cfset mac  = mac.getInstance(key.getAlgorithm())>
     <cfset mac.init(key)>
     <cfset mac.update(messageBytes)>

     <cfreturn mac.doFinal()>
</cffunction>