Загадочные пользовательские данные в маленькой программе

внешний интерфейс алгоритм WeChat JavaScript

Передний

предыдущий постРука об руку научит вас аутентификации при входе в апплетПредставляет, как апплет выполняет аутентификацию при входе в систему, затем идентификатор пользователя общего апплета может использовать идентификатор, предоставленный WeChat, упомянутый выше.jscode2sessionВ обмен на интерфейс апплет также предоставляетgetUserInfoAPI для получения пользовательских данных, эти пользовательские данные также могут содержать текущий идентификатор пользователя openid. Эта статья оКак получить пользовательские данные и честь целостности данных в апплетеи т. д., чтобы расширить детали

Введение в API

wx.getUserInfoЭто интерфейс API, используемый для получения информации о пользователе. Ниже приведены соответствующие поля параметров:

поле Типы Требуется ли
withCredentials Boolean нет
lang String нет
timeout Number нет
success Function нет
fail Function нет
complete Function нет

lang

lang указывает язык, на котором возвращается пользовательская информация, с тремя значениями:

  • zh_CN Упрощенный китайский
  • zh_TW Традиционный китайский
  • en Английский, по умолчанию en

timeout

timeout указывает время ожидания для вызова API,getUserInfoПо сути, нижний уровень API заключается в том, что клиент инициирует http-запрос для получения соответствующих данных пользователя и возвращает их апплету после инкапсуляции, которая будет подробно представлена ​​позже.

withCredentials

withCredentials Это поле является логическим значением, которое определяет, включается ли информация о статусе входа в данные, возвращаемые апплетом при вызове API.Если оно не заполнено, значением по умолчанию для этого поля являетсяtrue

Тогда результат, возвращаемый API в это время:

поле Типы описывать
encryptedData String зашифрованные данные пользователя
iv String Вектор алгоритма расшифровки
rawData String Открытые данные пользователя
signature String подписать
userInfo Object Открытые данные пользователя

Если значение этого поляfalse, указанные выше два поля не будут возвращены:encryptedData, iv.

  • зашифрованные данные — это зашифрованные данные полной информации о пользователе, включая конфиденциальные данные. Конфиденциальные данные включаютopenidа такжеunionidЖдать. Тогда алгоритм, используемый для шифрования данных,AES-128-CBCБлочный симметричный алгоритм шифрования и дешифрования, этот алгоритм шифрования мы подробно разберем позже.

  • iv — начальный вектор алгоритма описанного выше алгоритма дешифрования. Также мы представим его подробно позже.

  • rawData — объектная строка, содержащая некоторые открытые данные пользователя, а именно:nickName(微信昵称),province(所属省份),language(微信客户端内设置的语言类型),gender(用户性别),country(所在国家),city(所在城市),avatarUrl(微信头像地址)

  • подпись Чтобы гарантировать достоверность и безопасность данных, апплет подписывает данные открытого текста. Это значениеsha1(rawData + session_key)расчетное значение,sha1Это криптографическая хеш-функция, по сравнению сmd5Хеш-функции более устойчивы к атакам.

  • Поле userInfo представляет собой объект и данные, открытые пользователем, которые соответствуют содержимому, отображаемому rawData, за исключением того, что rawData сериализует объект в строку в качестве возвращаемого значения.

HTTP-запрос API

Я говорил вам ранее о вызове клиентаgetUserInfoКогда используется API, клиент WeChat отправит запрос на сервер WeChat.В инструменте разработчика WeChat вы можете увидеть через захват пакета HTTP-запроса, что запрос был отправлен.https://servicewechat.com/wxa-dev-logic/jsoperatewxdataтакой http запрос.

тело запросаОн содержит несколько важных параметров, в том числеdata, grant_typeи т. д., поле данных представляет собой строку JSON с полем в нейapi_name, значение которого — «webapi_userinfo». Поле grant_type также соответствует значению «webapi_userinfo».

тело ответавозвращает объект JSON, сначалаbaseresponseполе, содержащее код возврата вызова интерфейсаerrcodeи результат вызоваerrmsg. Объект также возвращаетdataполе, это поле данных соответствует строке JSON, которая содержит всю информацию о пользовательских данных, полученную при вызове API. В инструментах разработчика мы также видим, чтоdebug_infoполе, которое также содержит данные пользователяdata, но здесьdataТакже возвращается openid пользователя и учетные данные пользователя для входа в систему session_key.

Как правило, мы можем отлаживать достоверность некоторой информации, включая данные пользователя.session_keyа такжеopenid.

Алгоритм шифрования AES-128-CBC

Как мы сказали выше, полная информация о пользователе, полученная через API в апплетеencryptedData, надо пройтиAES-128-CBCалгоритм шифрования и дешифрования. Сначала разберемся, что такоеAES-128-CBC:

Полное имя AES является расширенным стандартом шифрования. Это спецификация шифрования для электронных данных, установленных Национальным институтом стандартов и технологий (NIST) в 2001 году. Это стандарт шифрования блока. Каждый размер блока шифрования составляет 128 бит. Длина 128, 192 и 256 бит.

Существует пять режимов блочного шифрования, а именно

Режим кодовой книги ECB (Electronic Codebook Book)

CBC (Cipher Block Chaining) Режим цепочки шифровальных блоков

Режим калькулятора CTR (счетчик)

CFB (Cipher FeedBack) Режим обратной связи по шифру

OFB (Output FeedBack) Режим обратной связи на выходе

Здесь мы в основном рассматриваемAES-128-CBCАлгоритм блочного шифрования заключается в использовании одного и того же набора ключей для преобразования открытого текста и зашифрованного текста, где 128 бит — это группа, 128 бит — это 16 байт, а затем каждые 16 байтов открытого текста в виде группы соответствуют зашифрованному 16-байтовому паролю. Если последнего оставшегося открытого текста не хватает на 16 байт, его необходимо заполнить, обычно используяPKCS#7(PKCS#5 поддерживает заполнение только 8-байтовых блоков данных, тогда как PKCS#7 поддерживает байтовые блоки от 1 до 255) для заполнения.

Если последний оставшийся открытый текст составляет 13 байт, то есть 3 байта отсутствуют для формирования группы, то в это время необходимо заполнить 3 байта 0x03:

明文数据:   05 05 05 05 05 05 05 05 05 05 05 05 05
PKCS#7填充: 05 05 05 05 05 05 05 05 05 05 05 05 05 03 03 03

Если открытый текст представляет собой целое число, кратное 16 байтам, в конце для шифрования следует добавить 16-байтовую группу 0x10.

Таким образом, мы находим две характеристики заполнения PKCS#7:

  • Байты заполнения - это один и тот же байт

  • Значение этого байта — количество байтов, которые необходимо заполнить.

Давайте еще раз посмотрим на процесс шифрования открытого текста. В режиме CBC каждый зашифрованный блок подвергается операции XOR с зашифрованным текстом предыдущего зашифрованного блока перед шифрованием, а затем результат будет зашифрован шифровальщиком. такой же, как тот, который мы описали ранееiv初始化向量Блок данных подвергается операции XOR. Как показано ниже (картинка из википедии):

1

Но нужно четко указать, что этот API возвращаетivявляется вектором инициализации, соответствующим алгоритму расшифровки, а не вектором инициализации, соответствующим алгоритму шифрования. Таким образом, вы, должно быть, догадались, что первый блок шифра также необходимо подвергнуть операции XOR с вектором инициализации при расшифровке в режиме CBC. Как показано ниже (картинка из википедии):

2

В апплете зашифрованные и расшифрованные шифры — это шифры в кодировке base64, полученные в нашей предыдущей статье.session_key.

Приложения в мини-программах

Затем, когда у нас есть общее представление о том, как пользовательские данные шифруются в апплете, давайте возьмем в качестве примера nodejs, чтобы увидеть, как расшифровать пользовательские данные на стороне сервера и проверить целостность расшифрованных данных:

В файле util.js определены два метода:

decryptByAESМетод заключается в использовании сервера, предоставленного WeChat, при входе в систему.jscode2sessionполучено из интерфейсаsession_keyи что будет возвращено после вызова wx.getUserInfoivвектор инициализации для расшифровкиencryptedData.

encryptedBySha1метод черезsha1хеш-алгоритм для шифрованияsession_keyСгенерируйте идентификатор статуса входа пользователя самого приложения апплета, чтобы убедиться, чтоsession_keyбезопасность.

// util.js
const crypto = require('crypto');
module.exports = {
    decryptByAES: function (encrypted, key, iv) {
        encrypted = new Buffer(encrypted, 'base64');
        key = new Buffer(key, 'base64');
        iv = new Buffer(iv, 'base64');
        const decipher = crypto.createDecipheriv('aes-128-cbc', key, iv)
        let decrypted = decipher.update(encrypted, 'base64', 'utf8')
        decrypted += decipher.final('utf8');
        return decrypted
    },
    encryptBySha1: function (data) {
        return crypto.createHash('sha1').update(data, 'utf8').digest('hex')
    }
};

В файле auth.js вызывается метод из предыдущей статьиgetSessionKeyметод получения пользователемopenidа такжеsession_keyПосле получения как зашифрованных данных является расшифрованная рабочая операция пользователя, в то время как пользовательские данные и дешифрованные пользователем Session_key Skey и сохраненные таблицы данных.

Здесь следует отметить одну вещь: если текущий апплет привязан к мобильному приложению или веб-приложению открытой платформы, официальной учетной записи публичной платформы и т. д., тоencryptedDataвернет еще одинunionIdполе, этот unionId может различать уникальность пользователей между мини-программами и другими связанными платформами, то естьУ одного и того же пользователя один и тот же unionid для разных приложений на одной и той же открытой платформе WeChat.. Как правило, мы можем использовать unionId для получения состояния входа пользователя между апплетом и другими приложениями.

// auth.js
const { decryptByAES, encryptBySha1 } = require('../util');
return getSessionKey(code, appid, secret)
    .then(resData => {
        // 选择加密算法生成自己的登录态标识
        const { session_key } = resData;
        const skey = encryptBySha1(session_key);

        let decryptedData = JSON.parse(decryptByAES(encryptedData, session_key, iv));
        // 存入用户数据表中
        return saveUserInfo({
            userInfo: decryptedData,
            session_key,
            skey
        })
    })
    .catch(err => {
        return {
            result: -10003,
            errmsg: JSON.stringify(err)
        }
    })

Проверка целостности и достоверности данных

После того, как мы получим полные данные пользователя посредством расшифровки, мы можем проверить целостность и достоверность полученных данных, чтобы предотвратить злонамеренное изменение данных пользователя. Вот как выполнить проверку связанных данных:

Проверка действительности: Ранее мы говорили, что когдаwithCredentialsЕсли установлено значение true, возвращаемые данные также будут включатьsignatureполе, значение которогоsha1(rawData + session_key)В результате разработчик может использовать тот же алгоритм sha1 для вычисления соответствующей подписи2 на стороне сервера полученной подписи, то есть

signature2 = encryptedBySha1(rawData + session_key);

Целостность пользовательских данных определяется путем сравнения соответствия подписи и подписи2.

Проверка целостности: Попасть передencryptedDataИ после соответствующей операции расшифровки вы увидите, что в объекте объекта пользовательских данных есть объектwatermarkПоле, официально называемое водяным знаком данных, структура этого поля такова:

"watermark": {
    "appid":"APPID",
    "timestamp":TIMESTAMP
}

Здесь разработчики могут проверить, соответствует ли appid в водяном знаке их собственному appid, а также отметке времени, полученной из данных в водяном знаке, чтобы проверить своевременность данных.

наконец

Итак, вышеизложенное является введением в то, как шифровать и расшифровывать пользовательские данные в апплете, а также как обрабатывать и проверять пользовательские данные.Пожалуйста, посоветуйте!

Справочная статья:

Подробное объяснение криптографических алгоритмов — AES

Пять режимов шифрования AES (CBC, ECB, CTR, OCF, CFB)

Некоторое понимание алгоритма шифрования AES-128-CBC

Режимы работы Advanced Encryption Standard AES (ECB, CBC, CFB, OFB)


Технологический еженедельник IVWEBШок в сети, обратите внимание на публичный номер: сообщество IVWEB, регулярно каждую неделю публикуйте качественные статьи.

  • Сборник статей еженедельника:weekly
  • Командные проекты с открытым исходным кодом:Feflow