Формирование sha256 в UnitPay для проверки платежа

Discussion in 'PHP' started by ceg, 17 Jan 2021.

  1. ceg

    ceg New Member

    Joined:
    2 Aug 2011
    Messages:
    29
    Likes Received:
    4
    Reputations:
    0
    Здравствуйте, ребята. Мучаюсь уже два дня. Никак не могу правильно сформировать sha256

    Цифровая подпись. Образуется как sha256(method + "{up}" + params + "{up}" + secretKey), где sha256 - метод шифрования; "{up}" - разделитель параметров в хеш-функции; method - тип вызова (check, pay, error); params - значения параметров из массива params, объединенные разделителем "{up}". Все параметры должны быть предварительно отсортированы по ключу, в склейке не участвуют параметры sign и signature; secretKey - секретный ключ проекта (доступен в личном кабинете); Пример расчета подписи для запроса http://partnerUrl?method=check & params=bob & params[c]=sam & params[a]=todи секретного ключа "a1b1c1d1" sha256("check{up}tod{up}bob{up}sam{up}a1b1c1d1")

    Ответ UnitPay
    PHP:
    array (
    )
    array (
      
    'action' => 'unitpay',
      
    'method' => 'pay',
      
    'params' =>
      array (
        
    'account' => 'test',
        
    'date' => '2021-01-17 17:50:12',
        
    'ip' => '93.80.3.62',
        
    'isPreauth' => '0',
        
    'operator' => 'mts',
        
    'orderCurrency' => 'RUB',
        
    'orderSum' => '10.00',
        
    'payerCurrency' => 'RUB',
        
    'payerSum' => '10.00',
        
    'paymentType' => 'mc',
        
    'phone' => '0',
        
    'profit' => '8',
        
    'projectId' => '123456',
        
    'signature' => '65f56854115sadfdfa103798a8c34b6cd0ad55ccf9caf91f70e7745ad8bd1e76f93a54aad',
        
    'sum' => '10',
        
    'test' => '1',
        
    'unitpayId' => '175',
      ),
    )
    Вот таким образом у меня правильно формируется подпись, но только для одного метода платежа. Если метод платежа меняется, то параметры могут немного меняться, поэтому подпись уже неверна.
    PHP:
            $canal 'unitpay';
            
    $amount_value $_GET['params']['payerSum']; //сумма платежа
            
    $payment_id_unitpay $_GET['params']['account']; // № транзакции
            
    $CURRENCY Config_Payment::UNITPAY_CURRENCY// валюта. Для проверки платежа
            
    $UNITPAY_PROJECTID Config_Payment::UNITPAY_PROJECTID// номер магазина. Для проверки платежа
            
    $secret_key Config_Payment::UNITPAY_SECRETKEY// секретный ключ
            
    if (stripos($payment_id_unitpay':')) { // передавали uid и транзакцию в одном параметре. Теперь разбираем из ответа
                
    $payment_id_unitpay_2 explode(":"$payment_id_unitpay);
                
    $account = (int) $payment_id_unitpay_2[0]; // id
                
    $billId = (int) $payment_id_unitpay_2[1]; // транзакция
            
    }
         
     

         
            
    // sha256. Старт. Написано для теста. При типе платежа "Мобильная коммерция" ключ совпадает. При других типах массив имеет другие параметры.




            
    $method $_GET['method'];
            
    $date $_GET['params']['date'];
            
    $ip $_GET['params']['ip'];
            
    $isPreauth $_GET['params']['isPreauth'];
            
    $operator $_GET['params']['operator'];
            
    $orderCurrency $_GET['params']['orderCurrency'];
            
    $orderSum $_GET['params']['orderSum'];
            
    $payerCurrency $_GET['params']['payerCurrency'];
            
    $payerSum $_GET['params']['payerSum'];
            
    $paymentType $_GET['params']['paymentType'];
            
    $phone $_GET['params']['phone'];
            
    $profit $_GET['params']['profit'];
            
    $projectId $_GET['params']['projectId'];
            
    $sum $_GET['params']['sum'];
            
    $test $_GET['params']['test'];
            
    $unitpayId $_GET['params']['unitpayId'];
         
            
    $sha256_hash_header $_GET['params']['signature'];
            function 
    getFormSignature($method$payment_id_unitpay$date$ip$isPreauth$operator$orderCurrency$orderSum$payerCurrency$payerSum$paymentType$phone$profit$projectId$sum$test$unitpayId$secret_key) {
                    
    $hashStr $method.'{up}'.$payment_id_unitpay.'{up}'.$date.'{up}'.$ip.'{up}'.$isPreauth.'{up}'.$operator.'{up}'.$orderCurrency.'{up}'.$orderSum.'{up}'.$payerCurrency.'{up}'.$payerSum.'{up}'.$paymentType.'{up}'.$phone.'{up}'.$profit.'{up}'.$projectId.'{up}'.$sum.'{up}'.$test.'{up}'.$unitpayId.'{up}'.$secret_key;
                    return 
    hash('sha256'$hashStr);
            }
            
    $sha256_hash getFormSignature($method$payment_id_unitpay$date$ip$isPreauth$operator$orderCurrency$orderSum$payerCurrency$payerSum$paymentType$phone$profit$projectId$sum$test$unitpayId$secret_key);
         



    // sha256. Финиш
         



            
    if ($sha256_hash_header == $sha256_hash && !empty($sha256_hash_header)) { // Сравнение sha256
                
    $userID = (int) $account;
                
    $defint = (int) $billId;
                
    $amount $amount_value;
            } else {
                die(
    json_encode(array("error" => array("message" => "Invalid data"))));
            }
         
            
    //if($_GET['params']['sum'] != (float) $_GET['params']['orderSum']) {
            //    die(json_encode(array("error" => array("message" => "Invalid amount transferred "))));
            //}
         
            
    if($_GET['params']['orderCurrency'] != $CURRENCY) {
                die(
    json_encode(array("error" => array("message" => "Invalid transferred currency"))));
            }

            if(
    $_GET['params']['projectId'] != $UNITPAY_PROJECTID) {
                die(
    json_encode(array("error" => array("message" => "Invalid project id"))));
            } 
         
            if(
    $_GET['method'] == 'check'){
                die(
    json_encode(array("result" => array("message" => "Successful check"))));
            }
         
            if(
    $_GET['method'] == 'preauth'){
                die(
    json_encode(array("result" => array("message" => "Pre-authorization. Waiting for payment"))));
            }
         
            if(
    $_GET['method'] == 'error'){
                die(
    json_encode(array("result" => array("message" => "Payment error. Expectation"))));
            }
         
            if(
    $_GET['method'] == 'pay'){
                
    $this->addBalance($canal$userID$amount$defint); // Начисляем баланс
                
    die(json_encode(array("result" => array("message" => "Success"))));
            }


    Вот кусок кода из sdk unitpay, но у себя подобное я сделать не смог:
    PHP:
    private $params = array();
    function 
    getSignature(array $params$method null)
        {
            
    ksort($params);
            unset(
    $params['sign']);
            unset(
    $params['signature']);
            
    array_push($params$this->secretKey);

            if (
    $method) {
                
    array_unshift($params$method);
            }

            return 
    hash('sha256'join('{up}'$params));
        }

    list(
    $method$params) = array($_GET['method'], $_GET['params']);

            if (!
    in_array($method$this->supportedPartnerMethods)) {
                throw new 
    UnexpectedValueException('Method is not supported');
            }

            if (!isset(
    $params['signature']) || $params['signature'] != $this->getSignature($params$method)) {
                throw new 
    InvalidArgumentException('Wrong signature');
            }
    https://help.unitpay.ru/payments/payment-handler
     
  2. LStr1ke

    LStr1ke Elder - Старейшина

    Joined:
    29 Jul 2009
    Messages:
    801
    Likes Received:
    145
    Reputations:
    73
    PHP:
    $method filter_input(INPUT_GET'method');
    $params filter_input(INPUT_GET'params'FILTER_DEFAULTFILTER_REQUIRE_ARRAY);
    $secret_key Config_Payment::UNITPAY_SECRETKEY;

    ksort($params);
    unset(
    $params['sign']);
    unset(
    $params['signature']);
    array_push($params$secret_key);
    if( 
    $method )
        
    array_unshift($params$method);

    $sha256_hash hash('sha256'join('{up}'$params));
     
    ceg likes this.
  3. ceg

    ceg New Member

    Joined:
    2 Aug 2011
    Messages:
    29
    Likes Received:
    4
    Reputations:
    0
    Очень очень вам благодарен, добрый человек. Подпись формируется и при сравнении верная.
     
  4. rainer89

    rainer89 New Member

    Joined:
    8 Jul 2021
    Messages:
    1
    Likes Received:
    0
    Reputations:
    0
    Unitpay не выключает теперь проверку подписи и я столкнулся с такой проблемой, при запросе пишет wrong signature, вот сам файл, помогите дописать?
    Буду очень признателен.
    Я так понимаю мне надо запихнуть в функцию эти строки:
    Вот сам код функции:

    Code:
    <?php
    
        function getSha1sign($method, $params)
        {
            ksort($params);
            unset($params['sign']);
            unset($params['signature']);
            array_push($params, Flux::config('up_secret_key'));
            array_unshift($params, $method);
    
            return hash('sha256', join('{up}', $params));
        }
        
        function checkHandlerRequest()
        {
            $ip = $_SERVER['REMOTE_ADDR'];
            if (!isset($_GET['method'])) {
                throw new Exception('Method is null');
            }
            if (!isset($_GET['params'])) {
                throw new InvalidArgumentException('Params is null');
            }
            list($method, $params) = array($_GET['method'], $_GET['params']);
            if (!in_array($method, Flux::config('up_supportedPartnerMethods')->toArray())) {
                throw new UnexpectedValueException('Method is not supported');
            }
            if ($params['signature'] != getSha1sign($_GET['method'], $params)) {
                throw new InvalidArgumentException('Wrong signature');
            }
            /**
             * IP address check
             * @link https://unitpay.ru/doc#overview
             */
            if (!in_array($ip, Flux::config('up_supportedUnitpayIp')->toArray())) {
                throw new InvalidArgumentException('IP address Error');
            }
            return true;
        }
        /**
         * Response for UnitPay if handle success
         *
         * @param $message
         *
         * @return string
         */
        function getSuccessHandlerResponse($message)
        {
            return json_encode(array(
                "result" => array(
                    "message" => $message
                )
            ));
        }
        /**
         * Response for UnitPay if handle error
         *
         * @param $message
         *
         * @return string
         */
        function getErrorHandlerResponse($message)
        {
            return json_encode(array(
                "error" => array(
                    "message" => $message
                )
            ));
        }
     
  5. ceg

    ceg New Member

    Joined:
    2 Aug 2011
    Messages:
    29
    Likes Received:
    4
    Reputations:
    0
    В функции function getSha1sign у вас итак все формируется. Может просто секретный ключ неверный указали в конфиге?

    Плюс юнитпею без разницы проверяете вы хеш или не проверяете. Это нужно только для вас.