Показать/Скрыть содержание

    Подпись HTTP сообщений

    В качестве дополнительной защиты от подмены сообщения в TLS-канале отправляемое сообщение может быть подписано.

    Формирование подписи

    Клиент формирует подпись отправляемого сообщения следующим образом.

    1. Создаётся случайный ключ K.
    2. На основе отправляемого HTTP сообщения формируется строка M.
    3. Вычисляется подпись S на ключе K от строки M: BASE64(HMAC(K, UTF8.GetBytes(M)).
    4. Формируется заголовок CP-Signature, содержащий S и K, и добавляется к HTTP запросу.

    Проверка подписи

    Сервер проверяет подпись следующим образом.

    1. Из заголовка CP-Signature извлекается ключ K и подпись S.
    2. На основе полученного HTTP сообщения формируется строка M.
    3. Вычисляется подпись S' на ключе K от строки M: BASE64(HMAC(K, UTF8.GetBytes(M)).
    4. Подпись S' сравнивается с S. Если значения совпадают, то подпись верна, иначе в сообщении что-то было изменено.

    Формирование строки M

    Строка M формируется на основе заголовков HTTP сообщения и его содержимого. Целевой URL считается псевдозаголвком (request-target).

    Строка M представляет собой конкатенацию двух строк: headers и body.

    Формирование строки headers

    Для каждого подписываемого заголовка (какие заголовки будут подписаны определяется клиентом) вычисляются строки header-name: header-value, где header-name - это название заголовка в нижнем регистре, а header-value значение заголовка без лидирующих и конечных пробелов.

    Если заголовком является (request-target), то его значение вычисляется как method URL, где method - название HTTP метода в нижнем регистре, а URL - целевой URL запроса (без изменений).

    Все сформированные строки конкатенируются через символ новой строки \n. После последней строки символа \n нет.

    Пример

    Для HTTP запроса

    POST /SignServer/rest/api/transactions HTTP/1.1
    Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Im5qdWFKbEtHMDlwblF1cDVyUUdxLW1TTkVsUSJ9.eyJ1bmlxdWVfbmFtZSI6InNnYSIsIm5hbWVpZCI6ImMxMDNhYjhlLTIzNDUtNDk3OS1hODg1LWQxNmIwZjNjYWQ0MiIsImRzc19pc3MiOiJyZWFsc3RzIiwiZHNzX3V1aWQiOiI0OXBEWmZ4VXdGamVIaFlTc3JTWDJMdmRTeEE9IiwiZW1haWwiOiJnLmEuc2Fkb2ZpZXZAZ21haWwucnUiLCJyb2xlIjoiVXNlcnMiLCJodHRwOi8vZHNzLmNyeXB0b3Byby5ydS9pZGVudGl0eS9jbGFpbXMvYWN0aW9uL2lzc3VlIjoidGZhOmZhbHNlIiwiaHR0cDovL2Rzcy5jcnlwdG9wcm8ucnUvaWRlbnRpdHkvY2xhaW1zL2FjdGlvbi9zaWduZG9jdW1lbnQiOiJ0ZmE6dHJ1ZSIsImh0dHA6Ly9kc3MuY3J5cHRvcHJvLnJ1L2lkZW50aXR5L2NsYWltcy9hY3Rpb24vc2lnbmRvY3VtZW50cyI6InRmYTpmYWxzZSIsImh0dHA6Ly9kc3MuY3J5cHRvcHJvLnJ1L2lkZW50aXR5L2NsYWltcy9hY3Rpb24vZGVjcnlwdGRvY3VtZW50IjoidGZhOmZhbHNlIiwiaHR0cDovL2Rzcy5jcnlwdG9wcm8ucnUvaWRlbnRpdHkvY2xhaW1zL2FjdGlvbi9jcmVhdGVyZXF1ZXN0IjoidGZhOnRydWUiLCJodHRwOi8vZHNzLmNyeXB0b3Byby5ydS9pZGVudGl0eS9jbGFpbXMvYWN0aW9uL2NoYW5nZXBpbiI6InRmYTpmYWxzZSIsImh0dHA6Ly9kc3MuY3J5cHRvcHJvLnJ1L2lkZW50aXR5L2NsYWltcy9hY3Rpb24vcmVuZXdjZXJ0aWZpY2F0ZSI6InRmYTpmYWxzZSIsImh0dHA6Ly9kc3MuY3J5cHRvcHJvLnJ1L2lkZW50aXR5L2NsYWltcy9hY3Rpb24vcmV2b2tlY2VydGlmaWNhdGUiOiJ0ZmE6ZmFsc2UiLCJodHRwOi8vZHNzLmNyeXB0b3Byby5ydS9pZGVudGl0eS9jbGFpbXMvYWN0aW9uL2hvbGRjZXJ0aWZpY2F0ZSI6InRmYTpmYWxzZSIsImh0dHA6Ly9kc3MuY3J5cHRvcHJvLnJ1L2lkZW50aXR5L2NsYWltcy9hY3Rpb24vdW5ob2xkY2VydGlmaWNhdGUiOiJ0ZmE6ZmFsc2UiLCJodHRwOi8vZHNzLmNyeXB0b3Byby5ydS9pZGVudGl0eS9jbGFpbXMvYWN0aW9uL2RlbGV0ZWNlcnRpZmljYXRlIjoidGZhOmZhbHNlIiwiaHR0cDovL2Rzcy5jcnlwdG9wcm8ucnUvaWRlbnRpdHkvY2xhaW1zL2FjdGlvbi9wcml2YXRla2V5YWNjZXNzIjoidGZhOmZhbHNlIiwiZHNzX2dyb3VwIjoiRGVmYXVsdCIsImh0dHA6Ly9kc3MuY3J5cHRvcHJvLnJ1L2lkZW50aXR5L2NsYWltcy9hY2Nlc3Nwb2xpY3kiOiIwIiwiZHNzX3NodHRwIjoiKHJlcXVlc3QtdGFyZ2V0KSBjb250ZW50LXR5cGUgY29udGVudC1sZW5ndGggYXV0aG9yaXphdGlvbiAocmVxdWVzdC1ib2R5KSIsImlzcyI6InJlYWxzdHMiLCJleHAiOjE1MzM1NDE2NjQsIm5iZiI6MTUzMzU0MTM2NH0.N4N4e3re_lZM9k1Kyeijhnm6mBlV9KpNxexv7pHnpIAf3dT3n9qA1HCtmmwipzwEm04F5SE4cJwFG7nleozfG2R_RMm-voG7YCmjCeNyAR9SMaHqwVwNkVN3_162JF8lzQ4h6ZJW2tKE7whSZRkdfxI8NAEyiYaFSezulmSg8_Ks8MKkkYipsOuKlkh6tAcLiMP1Xn0sgeXO-dDyz8F5hfBFAEmTMsGH1_Va-a7pI4X-SzA6ZYMFvvBnCw9DZ1CQDl42RIirqi_axXzllP9TTJKxVNXeWThC8bHHi-t42IrQXXYf-w8zABlMop6DdemWJXql5MqopcJCAVSJW_6H64BRA85lTqOX3iOjimyZRPwFBBlYn8jqgQBQaBDBxnETT8jCHRQMkwYSrFUMkQWDeKsRGRVEJ2WJoAE2DqeRVkC2ENS4SBFxLITTFmDEi6-PjCUNGqU30IjGRCOvdBadnHfgqHeQK0MVU03pqzHrk-aIBhp0_EdmLY1l348gQFzqy1kJlTviZdFq7OIWlDB98y1ovKA5lE-AGnqcU32EMFqAMCWMPV-4VTzFxvBbVbDliNRv2zavBiNrq5lJlUfrs-EerJqFCAIsA3bJaTz_Sqo4r_dJmBdhICtl5slfXLpYfdR4zxT20-dx_-VvyCdGYBspoigCLo5zaCaW2hsuqoE
    Content-Type: application/json; charset=utf-8
    Content-Length: 179
    
    {"OperationCode":"SignDocument","Document":"AQI=","Parameters":[{"Name":"SignatureType","Value":"CMS"},{"Name":"CertificateID","Value":"0"},{"Name":"DocumentInfo","Value":"aaa"}]}
    

    Будет сформирована следующая строка headers:

    (request-target): post /SignServer/rest/api/transactions
    content-length: 179
    content-type: application/json; charset=utf-8
    authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Im5qdWFKbEtHMDlwblF1cDVyUUdxLW1TTkVsUSJ9.eyJ1bmlxdWVfbmFtZSI6InNnYSIsIm5hbWVpZCI6ImMxMDNhYjhlLTIzNDUtNDk3OS1hODg1LWQxNmIwZjNjYWQ0MiIsImRzc19pc3MiOiJyZWFsc3RzIiwiZHNzX3V1aWQiOiI0OXBEWmZ4VXdGamVIaFlTc3JTWDJMdmRTeEE9IiwiZW1haWwiOiJnLmEuc2Fkb2ZpZXZAZ21haWwucnUiLCJyb2xlIjoiVXNlcnMiLCJodHRwOi8vZHNzLmNyeXB0b3Byby5ydS9pZGVudGl0eS9jbGFpbXMvYWN0aW9uL2lzc3VlIjoidGZhOmZhbHNlIiwiaHR0cDovL2Rzcy5jcnlwdG9wcm8ucnUvaWRlbnRpdHkvY2xhaW1zL2FjdGlvbi9zaWduZG9jdW1lbnQiOiJ0ZmE6dHJ1ZSIsImh0dHA6Ly9kc3MuY3J5cHRvcHJvLnJ1L2lkZW50aXR5L2NsYWltcy9hY3Rpb24vc2lnbmRvY3VtZW50cyI6InRmYTpmYWxzZSIsImh0dHA6Ly9kc3MuY3J5cHRvcHJvLnJ1L2lkZW50aXR5L2NsYWltcy9hY3Rpb24vZGVjcnlwdGRvY3VtZW50IjoidGZhOmZhbHNlIiwiaHR0cDovL2Rzcy5jcnlwdG9wcm8ucnUvaWRlbnRpdHkvY2xhaW1zL2FjdGlvbi9jcmVhdGVyZXF1ZXN0IjoidGZhOnRydWUiLCJodHRwOi8vZHNzLmNyeXB0b3Byby5ydS9pZGVudGl0eS9jbGFpbXMvYWN0aW9uL2NoYW5nZXBpbiI6InRmYTpmYWxzZSIsImh0dHA6Ly9kc3MuY3J5cHRvcHJvLnJ1L2lkZW50aXR5L2NsYWltcy9hY3Rpb24vcmVuZXdjZXJ0aWZpY2F0ZSI6InRmYTpmYWxzZSIsImh0dHA6Ly9kc3MuY3J5cHRvcHJvLnJ1L2lkZW50aXR5L2NsYWltcy9hY3Rpb24vcmV2b2tlY2VydGlmaWNhdGUiOiJ0ZmE6ZmFsc2UiLCJodHRwOi8vZHNzLmNyeXB0b3Byby5ydS9pZGVudGl0eS9jbGFpbXMvYWN0aW9uL2hvbGRjZXJ0aWZpY2F0ZSI6InRmYTpmYWxzZSIsImh0dHA6Ly9kc3MuY3J5cHRvcHJvLnJ1L2lkZW50aXR5L2NsYWltcy9hY3Rpb24vdW5ob2xkY2VydGlmaWNhdGUiOiJ0ZmE6ZmFsc2UiLCJodHRwOi8vZHNzLmNyeXB0b3Byby5ydS9pZGVudGl0eS9jbGFpbXMvYWN0aW9uL2RlbGV0ZWNlcnRpZmljYXRlIjoidGZhOmZhbHNlIiwiaHR0cDovL2Rzcy5jcnlwdG9wcm8ucnUvaWRlbnRpdHkvY2xhaW1zL2FjdGlvbi9wcml2YXRla2V5YWNjZXNzIjoidGZhOmZhbHNlIiwiZHNzX2dyb3VwIjoiRGVmYXVsdCIsImh0dHA6Ly9kc3MuY3J5cHRvcHJvLnJ1L2lkZW50aXR5L2NsYWltcy9hY2Nlc3Nwb2xpY3kiOiIwIiwiZHNzX3NodHRwIjoiKHJlcXVlc3QtdGFyZ2V0KSBjb250ZW50LXR5cGUgY29udGVudC1sZW5ndGggYXV0aG9yaXphdGlvbiAocmVxdWVzdC1ib2R5KSIsImlzcyI6InJlYWxzdHMiLCJleHAiOjE1MzM1NDE2NjQsIm5iZiI6MTUzMzU0MTM2NH0.N4N4e3re_lZM9k1Kyeijhnm6mBlV9KpNxexv7pHnpIAf3dT3n9qA1HCtmmwipzwEm04F5SE4cJwFG7nleozfG2R_RMm-voG7YCmjCeNyAR9SMaHqwVwNkVN3_162JF8lzQ4h6ZJW2tKE7whSZRkdfxI8NAEyiYaFSezulmSg8_Ks8MKkkYipsOuKlkh6tAcLiMP1Xn0sgeXO-dDyz8F5hfBFAEmTMsGH1_Va-a7pI4X-SzA6ZYMFvvBnCw9DZ1CQDl42RIirqi_axXzllP9TTJKxVNXeWThC8bHHi-t42IrQXXYf-w8zABlMop6DdemWJXql5MqopcJCAVSJW_6H64BRA85lTqOX3iOjimyZRPwFBBlYn8jqgQBQaBDBxnETT8jCHRQMkwYSrFUMkQWDeKsRGRVEJ2WJoAE2DqeRVkC2ENS4SBFxLITTFmDEi6-PjCUNGqU30IjGRCOvdBadnHfgqHeQK0MVU03pqzHrk-aIBhp0_EdmLY1l348gQFzqy1kJlTviZdFq7OIWlDB98y1ovKA5lE-AGnqcU32EMFqAMCWMPV-4VTzFxvBbVbDliNRv2zavBiNrq5lJlUfrs-EerJqFCAIsA3bJaTz_Sqo4r_dJmBdhICtl5slfXLpYfdR4zxT20-dx_-VvyCdGYBspoigCLo5zaCaW2hsuqoE
    

    Формирование строки body

    Строка body представляет собой содержимое HTTP запроса (без каких-либо изменений).

    Формирование заголовка CP-Signature

    Заголовок CP-Signature имеет вид (для предыдущего примера): Здесь переносы строк добавлены только для наглядности.

    CP-Signature: headers="(request-target) content-length content-type authorization",
    key="QH5xtLRVDncY50KC82RprzX9AIhaDNioX4wzb9PlGn8=",
    signature="8z8qEydpfZdnzOwRn8eVvxSmIUwx3akScU6azm3SNUc="
    

    В параметре key передаётся значение ключа K в BASE64, в параметре headers передаётся перечень всех подписываемых заголовков, в параметре signature - значение подписи S в BASE64.

    В начало © ООО "КРИПТО-ПРО", 2000–2025