You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python可用的加密passphrase在Haskell请求KuCoin API时无效

KuCoin期货API签名认证passphrase校验失败问题排查

问题现象

向KuCoin期货API发起携带签名头的GET请求时,所有签名计算逻辑与可正常运行的Python代码对齐,但接口返回{"code":"400004","msg":"Invalid KC-API-PASSPHRASE"}错误。

  • 其余签名相关字段(KC-API-SIGN、KC-API-TIMESTAMP、KC-API-KEY)校验均正常
  • 已尝试添加BangPatterns扩展排除惰性求值影响,问题未解决
  • 两端生成的passphrase打印值对比如下:
    • Python输出:b'e3GO2zT3kWv1oVrAhAF1TByq0u8ExNMw/76KrsFGnls='
    • Haskell输出:e3GO2zT3kWv1oVrAhAF1TByq0u8ExNMw/76KrsFGnls=

    注:Python输出的b''是字节串类型的打印标记,两端实际生成的passphrase字符串内容完全一致,计算逻辑无错误。

参考实现(可正常运行的Python代码)

api_passphrase = "passphrase"
api_secret = "secret"
api_key = "key"

url = 'https://api-futures.kucoin.com/api/v1/position?symbol=XBTUSDM'
now = int(time.time() * 1000)
str_to_sign = str(now) + 'GET' + '/api/v1/position?symbol=XBTUSDM'
signature = base64.b64encode(
    hmac.new(api_secret.encode('utf-8'), str_to_sign.encode('utf-8'), hashlib.sha256).digest())
passphrase = base64.b64encode(hmac.new(api_secret.encode('utf-8'), api_passphrase.encode('utf-8'), hashlib.sha256).digest())
headers = {
    "KC-API-SIGN": signature,
    "KC-API-TIMESTAMP": str(now),
    "KC-API-KEY": api_key,
    "KC-API-PASSPHRASE": passphrase,
    "KC-API-KEY-VERSION": "2"
}
response = requests.request('get', url, headers=headers)
print(passphrase)

异常实现(Haskell代码)

import qualified Config                    as C
import           Control.Lens
import           Control.Monad
import           Control.Monad.Catch
import           Control.Monad.IO.Class
import qualified Crypto.Hash.SHA256        as H
import qualified Data.Aeson                as A
import           Data.Aeson.Lens           as AL
import qualified Data.ByteString           as B
import qualified Data.ByteString.Base64    as U
import qualified Data.ByteString.Char8     as BC
import qualified Data.ByteString.Lazy      as BL
import qualified Data.ByteString.Lazy.UTF8 as BU
import           Data.Monoid
import qualified Data.Text                 as T
import           Data.Text.Encoding        (encodeUtf8)
import qualified Data.Time.Clock.POSIX     as TI
import           GHC.Generics
import           Network.Wreq


apiSign :: BC.ByteString -> BC.ByteString -> BC.ByteString -> TI.POSIXTime -> IO BC.ByteString
apiSign method endpoint body time = do
  timeStamp <- apiTimeStamp' time
  let message = mconcat [timeStamp,method,endpoint,body]
  let hash = H.hmac (BC.pack C.apiSecret) message
  return $ (encodeUtf8 . U.encodeBase64) hash

apiTimeStamp' :: TI.POSIXTime -> IO BC.ByteString
apiTimeStamp' = return . BC.take 13 . BC.pack . show . (* 1000)

apiPassphrase :: BC.ByteString
apiPassphrase = U.encodeBase64' $ H.hmac (BC.pack C.apiSecret) (BC.pack C.apiPassphrase)

apiKeyVersion :: BC.ByteString
apiKeyVersion = BC.pack C.apiVersion

main' :: IO ()
main' = do
  time <- TI.getPOSIXTime
  timeStamp <- apiTimeStamp' time
  apiSignValue <- apiSign "GET" "/api/v1/position?symbol=XBTUSDM" "" time
  let opt = defaults & header "Accept" .~ ["*/*"]
                     & header "KC-API-VERSION" .~ ["2"]
                     & header "KC-API-KEY" .~ [BC.pack C.apiKey]
                     & header "KC-API-TIMESTAMP" .~ [timeStamp]
                     & header "KC-API-PASSPHRASE" .~ [apiPassphrase]
                     & header "KC-API-SIGN" .~ [apiSignValue]
                     & param "symbol" .~ ["XBTUSDM"]

  r <- getWith opt (kucoin ++ "position")
  let response = r ^. responseBody
  print response

根因分析

问题出在请求头名称拼写错误:

  • Python正确代码中,标识密钥版本的请求头名为KC-API-KEY-VERSION,值为2,代表使用V2版本签名逻辑,此时KC-API-PASSPHRASE需要传API密钥加密后再base64编码的值。
  • Haskell代码中误将该请求头写为KC-API-VERSION,服务端无法识别到V2版本标记,默认回退到V1版本签名校验逻辑,V1逻辑要求KC-API-PASSPHRASE传递明文的passphrase值,和传入的加密后值不匹配,因此返回passphrase无效的错误。

修复方案

修改Haskell代码中请求头的键名,将错误的KC-API-VERSION替换为正确的KC-API-KEY-VERSION即可,修改后的配置段如下:

let opt = defaults & header "Accept" .~ ["*/*"]
                   -- 修正头名拼写
                   & header "KC-API-KEY-VERSION" .~ ["2"]
                   & header "KC-API-KEY" .~ [BC.pack C.apiKey]
                   & header "KC-API-TIMESTAMP" .~ [timeStamp]
                   & header "KC-API-PASSPHRASE" .~ [apiPassphrase]
                   & header "KC-API-SIGN" .~ [apiSignValue]
                   & param "symbol" .~ ["XBTUSDM"]

其余签名计算、passphrase生成逻辑均正确,无需修改。


内容的提问来源于stack exchange,提问作者artin ghasivand

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 07:42:14