Создание подписи (signature)

В данном форуме описаны все API, поддерживаемые нашими услугами.

Re: Создание подписи (signature)

Сообщение boxer483ps » 10 сен 2011, 21:15

Подскажите как будет выглядеть этот алгоритм на c#, что то я не могу с ним разобраться.
Ответьте пожалуйста для чего нужно convertToHex в версии на Java?
boxer483ps
 
Сообщения: 2
Зарегистрирован: 09 сен 2011, 21:17

Re: Создание подписи (signature)

Сообщение alg » 10 сен 2011, 22:10

boxer483ps, в Java эта функция нужна потому, что MD5 возвращается в виде массива с десятичными значениями, а нужна строка с шестнадцатеричными.
У любой аварии есть фамилия, имя и отчество.
Аватара пользователя
alg
Why so serious?
 
Сообщения: 649
Зарегистрирован: 31 июл 2009, 13:11
Откуда: Москва

Re: Создание подписи (signature)

Сообщение alg » 10 сен 2011, 23:12

На C# можно так:

Код: Выделить всё
using System;
using System.Text;
using System.Security.Cryptography;
using System.Collections.Generic;

// Create an MD5 sum string of this string
private static string GetMD5Sum(string str)
{
    // step 1, calculate MD5 hash from input
    MD5 md5           = System.Security.Cryptography.MD5.Create();
    byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(str);
    byte[] hash       = md5.ComputeHash(inputBytes);

    // step 2, convert byte array to hex string
    StringBuilder sb = new StringBuilder();

    for (int i = 0; i < hash.Length; i++)
        sb.Append(hash[i].ToString("X2"));

    return sb.ToString();
}

private static string buildUrlParamsWithSignature(SortedDictionary<string, string> parms, string password)
{
    string url = "";

    foreach (KeyValuePair<string, string> kvp in parms)
    {
        string val = System.Uri.EscapeDataString(kvp.Value);

        url += kvp.Key + "=" + val + "&";
    }

    string sign = GetMD5Sum(url + "&password=" + Uri.EscapeDataString(password));

    url += "signature=" + sign.ToLower();

    return url;
}
У любой аварии есть фамилия, имя и отчество.
Аватара пользователя
alg
Why so serious?
 
Сообщения: 649
Зарегистрирован: 31 июл 2009, 13:11
Откуда: Москва

Re: Создание подписи (signature) Python

Сообщение murfen » 14 ноя 2012, 12:41

Работающий вариант на Python 2.x:
Код: Выделить всё
# -*- coding: utf-8 -*-

import urllib, hashlib
from copy import copy

def sign_request(params, username, password):
    """
    params may be either a dict or a list of (key, value) tuples
    Returns urlencoded signed string for send as GET or POST data
    """
    if isinstance(params,dict):
        p1 = params.items()
    else:
        p1 = copy(params)
    p1.append( ('username', username))
    p1.sort(key= lambda x: x[0])
    url = urllib.urlencode(p1)
    # Примечание: случай, когда пароль содержит пробел, не проверялся
    url1 = "%s&&password=%s" % (url, urllib.quote_plus(password))
    dig = hashlib.md5(url1).hexdigest()
    return  "%s&signature=%s" % (url, dig)
murfen
 
Сообщения: 3
Зарегистрирован: 07 ноя 2012, 13:09

Re: Создание подписи (signature)

Сообщение donexpress_premium » 29 дек 2012, 13:29

Полный мануал по подписи (signature)
Добрый день!

С часик занимался поиском ошибки в коде формирующем подпись. В итоге проблема крылась в более правильной реализации данной функции у себя в коде. Всем кто будет реализовывать функцию формирования подписи (сигнатуры) самостоятельно обратите внимание на следующее:
1. Думаю у всех будет какая-то коллекция/массив строк содержащий связку: ключ=значение.
2. исходя из примера COMTUBE будет функция формирующая на основании коллекции (п.1) СОРТИРОВАННЫЙ по КЛЮЧу список параметров в виде URLа (параметр password приведен для массовки, быть его в параметрах не должно).
Например исходный массив:
Код: Выделить всё
{username='logn', password='mypassword',action='send'}

Будет привен к виду:
Код: Выделить всё
action=send&password=mypassword&username=login&

Особо обратите внимание на конечный амперсанд. Именно на нем я и прокололся... Обычно подобные строки я формирую так:
Код: Выделить всё
$res .= ($res == '' ? '' : '&') . $value;
в итоге получаем строку без конечного амперсанда, что более красиво с моей точки зрения.
Каждый параметр должен быть обработан аналогом функции urlencode из php. Для поиска подходящего варианта привожу пример рабочих вариантов:
Код: Выделить всё
строка "Тестовый" => "%D0%A2%D0%B5%D1%81%D1%82%D0%BE%D0%B2%D1%8B%D0%B9"
"english123456" => "english123456"

Ищите аналоги в своей среде.
3. В предыдущих шагах мы получили параметры которые надо подписать. Не весь URL а только параметры, которые мы будем ставить после знака "?" (так называемый QUERY_STRING). Вычисляем сигнатуру. Для этого вычисляем md5 хэш для строки вида: "params . '&password=mypassword'". Вот ОНО. Мы получаем криворукую строку для вычисления подписи вида:
Код: Выделить всё
action=send&password=mypassword&username=login&&password=mypassword

Видим 2 подряд идущих амперсанда. В моем коде был один, соответственно отлаживая код я был уверен что делаю все верно.

Далее рассмотрим реальные значения для отладки вашего кода:
1. Отсортированные параметры ввиде параметров:
Код: Выделить всё
action=send&message=%D0%A2%D0%B5%D1%81%D1%82%D0%BE%D0%B2%D1%8B%D0%B9&number=791701234567&senderid=tasktest&username=DEMOLOGIN&

2. Сигнатура с паролем: "demoPASS" (не забудьте, что пароль тоже на отurlencoдить :) ):
Код: Выделить всё
99b38a7d2b5c9497222ebb0f5bf0e48c

3. Общая строка для отправки серверу:
Код: Выделить всё
http://api.comtube.ru/scripts/api/sms.php?action=send&message=%D0%A2%D0%B5%D1%81%D1%82%D0%BE%D0%B2%D1%8B%D0%B9&number=79871234567&senderid=tasktest&username=DEMOLOGIN&signature=99b38a7d2b5c9497222ebb0f5bf0e48c


Подводя итог можно сделать вывод: разрабочики сильно торопились/поленились/не придали значения, а когда увидели (увидят после поста :) ) то - поздно - поезд ушел: тысячи клиентов формируют подписи по корявым строкам.
Надеюсь пост поможет вам сохранить свое время.
Последний раз редактировалось donexpress_premium 03 дек 2015, 21:45, всего редактировалось 2 раз(а).
donexpress_premium
 
Сообщения: 69
Зарегистрирован: 15 июл 2011, 16:06

Re: Создание подписи (signature)

Сообщение donexpress_premium » 29 дек 2012, 13:32

Пример вычисления сигнатуры на VB.NET на примере отправки SMS:
https://www.comtube.com/forum/viewtopic.php?f=33&t=494&p=17908&sid=11593c1ee777939c891a9b6d2fe73d4e&sid=11593c1ee777939c891a9b6d2fe73d4e#p17908
Всем кто воспользовался примером от уважемого alg на C# идем по так же по ссылке и смотрим про грабли: uri.EscapeDataString
Последний раз редактировалось donexpress_premium 29 дек 2012, 14:54, всего редактировалось 7 раз(а).
donexpress_premium
 
Сообщения: 69
Зарегистрирован: 15 июл 2011, 16:06

Re: Создание подписи (signature)

Сообщение sd » 29 дек 2012, 13:40

donexpress_premium писал(а):Подводя итог можно сделать вывод: разрабочики сильно торопились/поленились/не придали значения, а когда увидели (увидят после поста :) ) то - поздно - поезд ушел: тысячи клиентов формируют подписи по корявым строкам.
Надеюсь пост поможет вам сохранить свое время.

Да, когда это начиналось, то делали в спешке и не обратили внимания на этот двойной &. Заметили уже давно, но поезд ушел, как вы правильно заметили. Тогда уже было достаточно клиентов, которые использовали API. Решили так и оставить.

Кстати, спасибо вам за подробную статью. У меня все никак руки не доходили написать такую. Небольшой бонус вам полагается за это ;)

С наступающим вас Новым Годом!

P.S. Об этом амперсанде двойном уже где-то тут писали и не раз. Надо было еще тогда внести изменения в описание. Поленился, и из-за этого много пользователей просто тратят попусту время выясняя, почему у них ничего не работает.
Аватара пользователя
sd
 
Сообщения: 5184
Зарегистрирован: 31 июл 2009, 13:11

Re: Создание подписи (signature)

Сообщение donexpress_premium » 05 янв 2013, 08:49

правильный (полностью совместимый с PHP) urlencode на C#:
Код: Выделить всё
        public String urlencode(String src){
            String[] p = System.Web.HttpUtility.UrlEncode(src).Split('%');
            String res = p[0];

            for (int x = 1; x < p.Length - 1; x++)
            {
                res += "%" + p[x].Substring(0, 2).ToUpper() + (p[x].Length > 2 ? p[x].Substring(2) : "");
            }
           
            return res;
        }
donexpress_premium
 
Сообщения: 69
Зарегистрирован: 15 июл 2011, 16:06

Re: Создание подписи (signature)

Сообщение shumilov_vv » 26 окт 2014, 22:06

Публикую функции для Perl
Главная засада в том что uri_escape конвертирует пробел в %20, а php urlencode просто в +
И еще во всех примерах в инете в качестве аналога php urlencode приводится строка преобразования, где
sprintf("%%%02x",ord($1)) дает преобразование шестнадцатиричной цифры в нижнем регистре, что тоже оказывается важно ((((((((((((((
Поэтому urlencode будет выглядеть примерно так:
sub urlencode {
my ($str)=@_;
$str =~ s/([^a-zA-Z0-9\%\&\?\:\;\/\=\.\,\#\-\_]{1})/uc(sprintf("%%%02x",ord($1)))/eg;
$str =~ s/%20/\+/g;
return $str
}
Сама подпись где-то так:

sub BuildUrlParamsWithSignature{
my $params = shift;
my $password = shift;

my $url = '';
foreach my $key (sort(keys %{$params})) {
print urlencode($params->{$key})."\t".uri_escape($params->{$key})."\n";
$url .= $key . "=" . urlencode($params->{$key}) . "&";
}

$signature = md5_hex($url . "&password=".urlencode($password));
$url .= "signature=" . $signature;

return $url;
}
Ну и пользуемся примерно так:

use LWP::UserAgent;
use HTTP::Request;
use HTTP::Response;
use Unicode::Map();
use Encode;
use Digest::MD5 qw(md5_hex);
use URI::Escape;

my $phone = '79031234567';
my $login = "shumilov_vv";
my $password = "12345";
my $message="Тест на русском 4!";

my $url_comtube = "http://api.comtube.ru/scripts/api/sms.php";
my %h;
$h{username} = $login;
$h{action} = "send";
$h{number} = $phone;
$h{senderid} = "74832607067";
$h{charset} = "utf-8";
Encode::from_to($message, 'cp1251','utf8');
$h{message} = $message;

my $hdrs=new HTTP::Headers(Accept=>'application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5',Connection=>'Keep-Alive','Content-Type'=>'application/x-www-form-urlencoded;charset=UTF-8');
my $ua = new LWP::UserAgent;
$ua->agent("Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16");
my $flag = 0;

print $url_comtube."&".BuildUrlParamsWithSignature(\%h,$password);
my $request = new HTTP::Request('GET', $url_comtube."?".BuildUrlParamsWithSignature(\%h,$password),$hdrs);
my $response = $ua->request($request);
if($response->is_success){
print $response->content."\n";
}else{
print $response->headers_as_string."\n";
print $response->content."\n";
}
shumilov_vv
 
Сообщения: 1
Зарегистрирован: 27 сен 2013, 13:02

Пред.

Вернуться в API

Просмотр страницы «Кто сейчас на форуме COMTUBE»

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5