Android Keystore: что это, для чего нужен, как создать ключ

JSONParser.pro

Не забываем подключить в профайле проекта модуль network , чтобы была возможность работать с классом QNetworkAccessManager.

#————————————————- # # Project created by QtCreator 2016-01-02T13:12:55 # #————————————————- QT += core gui network greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = JSONParser TEMPLATE = app SOURCES += main.cpp widget.cpp HEADERS += widget.h FORMS += widget.ui

Редактирование хранилища ключей

Данный раздел охватывает редактирование записей Java Keystore (например, удаление и изменение псевдонимов).

Изменение пароля хранилища

При помощи этой команды можно изменить пароль хранилища (keystore.jks):

keytool -storepasswd -keystore keystore.jks

Укажите текущий пароль хранилища ключей, а затем новый пароль. Задать новый пароль можно и при помощи самой команды, внеся в нее опцию -new newpass, где newpass – новый пароль.

Удаление псевдонима

Данная команда удалит псевдоним domain из хранилища keystore.jks:

keytool -delete -alias domain -keystore keystore.jks

Укажите пароль хранилища.

Изменение псевдонима

При помощи данной команды можно изменить псевдоним (например, domain на newdomain):

keytool -changealias -alias domain -destalias newdomain -keystore keystore.jks

widget.h

Подключаем класс QNetworkAccessManager , также в заголовочном файле объявлен СЛОТ onResult(QNetworkReply *reply) , в котором будет разбираться JSON файл при получении ответа от сайта с содержимым файла.

#ifndef WIDGET_H #define WIDGET_H #include #include namespace Ui { class Widget, } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0), ~Widget(), private slots: // Обработчик данных полученных от объекта QNetworkAccessManager void onResult(QNetworkReply *reply), private: Ui::Widget *ui, QNetworkAccessManager *networkManager, }, #endif // WIDGET_H

Создание и импортирование записей

Данный раздел посвящен командам Java Keytool, которые создают пары ключей и сертификатов, а также импортируют сертификаты.

Создание ключей

Используйте этот метод для поддержки HTTPS (HTTP по TLS). В данном разделе показано, как создать новую пару ключей в новом или уже существующем хранилище ключей Java, которые могут быть использованы для создания запроса на подпись сертификата (CSR) или получения SSL-сертификата в центре сертификации.

Данная команда сгенерирует пару 2048-битных RSA-ключей под указанным псевдонимом (в данном случае это domain) в указанном файле хранилища (keystore.jks).

keytool -genkeypair -alias domain -keyalg RSA -keystore keystore.jks

Если же заданного хранилища ключей не существует, оно будет создано после получения запрашиваемой информации (а именно пароля хранилища ключей, строки Distinguished Name (для закрытого ключа) и пароля закрытого ключа).

Создание CSR для существующего закрытого ключа

Чтобы сгенерировать запрос на подпись сертификата, который можно отправить в ЦС для получения надежного SSL-сертификата, следуйте данному разделу руководства. Для этого понадобятся уже существующее хранилище ключей и псевдоним.

Данная команда создаст CSR (domain.csr), подписанный закрытым ключом с псевдонимом domain в хранилище keystore.jks:

keytool -certreq -alias domain -file domain.csr -keystore keystore.jks

Введите пароль хранилища ключей, после чего запрос будет создан.

Импортирование подписанного/Root/промежуточного сертификата

В данном разделе показано, как импортировать сертификаты (например, подписанный ЦС сертификат) в хранилище ключей. Он должен соответствовать закрытому ключу с определенным псевдонимом. Также данную команду можно использовать для импортирования root

или промежуточного сертификата, который может потребовать ЦС для завершения доверительной цепочки. Просто укажите уникальный псевдоним, (например, root вместо domain) и сертификат, который необходимо импортировать.

Следующая команда импортирует сертификат (domain.crt) в хранилище ключей (keystore.jks) под указанным псевдонимом (domain). Подписанный сертификат при импортировании должен соответствовать закрытому ключу с указанным псевдонимом:

keytool -importcert -trustcacerts -file domain.crt -alias domain -keystore keystore.jks

На данном этапе будет предложено ввести пароль хранилища ключей, а затем подтвердить импортирование.

Примечание: можно также использовать эту команду, чтобы импортировать сертификаты ЦС в Java truststore (хранилище доверенных сертификатов), которое, как правило, находится в $JAVA_HOME/jre/lib/security/cacerts, (предполагается, что JRE или JDK установлены в $JAVA_HOME).

Создание самоподписанного сертификата в новом/существующем хранилище

В данном разделе показано, как создать самоподписанный сертификат для приложения Java. На самом деле, для этого используется та же команда, что и для создания новой пары ключей, но с параметром days, задающим срок действия сертификата.

Итак, данная команда создаст пару 2048-битных RSA-ключей, действительных на протяжении 365 дней, с указанным псевдонимом (domain) в заданном файле ключей (keystore.jks):

keytool -genkey -alias domain -keyalg RSA -validity 365 -keystore keystore.jks

Если заданного хранилища ключей не существует, команда создаст его, получив необходимые данные (это пароль хранилища, Distinguished Name (дл закрытого ключа) и пароль закрытого ключа).

widget.cpp

Процесс заключается в том, чтобы создать объект QJsonDocument и записать в него содержимое ответа QNetworkReply. После чего забираем из документа корневой объект root , который будет содержать все три свойства. После этого забираем по названиям свойств их значения. Из второго свойства «employes» забираем массив с именами и фамилиями сотрудников отдела. Все данные помещаем в поле ui-&gt,textEdit.

#include «widget.h» #include «ui_widget.h» #include #include #include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui-&gt,setupUi(this), networkManager = new QNetworkAccessManager(), // Подключаем networkManager к обработчику ответа connect(networkManager, &QNetworkAccessManager::finished, this, &Widget::onResult), // Получаем данные, а именно JSON файл с сайта по определённому url networkManager-&gt,get(QNetworkRequest(QUrl(«https://www.evileg.ru/it_example.json»))), } Widget::~Widget() { delete ui, } void Widget::onResult(QNetworkReply *reply) { // Если ошибки отсутсвуют if(!reply-&gt,error()){ // То создаём объект Json Document, считав в него все данные из ответа QJsonDocument document = QJsonDocument::fromJson(reply-&gt,readAll()), // Забираем из документа корневой объект QJsonObject root = document.object(), /* Находим объект «departament», который располагается самым первым в корневом объекте. * С помощью метода keys() получаем список всех объектов и по первому индексу * забираем название объекта, по которому получим его значение * */ ui-&gt,textEdit-&gt,append(root.keys().at(0) + «: » + root.value(root.keys().at(0)).toString()), // Второе значение пропишем строкой QJsonValue jv = root.value(«employees»), // Если значение является массивом, … if(jv.isArray()){ // … то забираем массив из данного свойства QJsonArray ja = jv.toArray(), // Перебирая все элементы массива … for(int i = 0, i &lt, ja.count(), i++){ QJsonObject subtree = ja.at(i).toObject(), // Забираем значения свойств имени и фамилии добавляя их в textEdit ui-&gt,textEdit-&gt,append(subtree.value(«firstName»).toString() + » » + subtree.value(«lastName»).toString()), } } // В конце забираем свойство количества сотрудников отдела и также выводим в textEdit ui-&gt,textEdit-&gt,append(QString::number(root.value(«number»).toInt())), } reply-&gt,deleteLater(), }

Структура JWT

JWT состоит из трех частей: заголовок header, полезные данные payload и подпись signature. Давайте пройдемся по каждой из них.

Шаг 1. Создаем HEADER

Хедер JWT содержит информацию о том, как должна вычисляться JWT подпись. Хедер — это тоже JSON объект, который выглядит следующим образом:

header = { «alg»: «HS256», «typ»: «JWT»}

Поле typ не говорит нам ничего нового, только то, что это JSON Web Token. Интереснее здесь будет поле alg, которое определяет алгоритм хеширования. Он будет использоваться при создании подписи. HS256 — не что иное, как HMAC-SHA256, для его вычисления нужен лишь один секретный ключ (более подробно об этом в шаге 3). Еще может использоваться другой алгоритм RS256 — в отличие от предыдущего, он является ассиметричным и создает два ключа: публичный и приватный. С помощью приватного ключа создается подпись, а с помощью публичного только лишь проверяется подлинность подписи, поэтому нам не нужно беспокоиться о его безопасности.

Шаг 2. Создаем PAYLOAD

Payload — это полезные данные, которые хранятся внутри JWT. Эти данные также называют JWT-claims (заявки). В примере, который рассматриваем мы, сервер аутентификации создает JWT с информацией об id пользователя — userId.

payload = { «userId»: «b08f86af-35da-48f2-8fab-cef3904660bd» }

Мы положили только одну заявку (claim) в payload. Вы можете положить столько заявок, сколько захотите. Существует список стандартных заявок для JWT payload — вот некоторые из них:

  • iss (issuer) — определяет приложение, из которого отправляется токен.
  • sub (subject) — определяет тему токена.
  • exp (expiration time) — время жизни токена.

Эти поля могут быть полезными при создании JWT, но они не являются обязательными. Если хотите знать весь список доступных полей для JWT, можете заглянуть в Wiki. Но стоит помнить, что чем больше передается информации, тем больший получится в итоге сам JWT. Обычно с этим не бывает проблем, но все-таки это может негативно сказаться на производительности и вызвать задержки во взаимодействии с сервером.

Шаг 3. Создаем SIGNATURE

Подпись вычисляется с использование следующего псевдо-кода:

const SECRET_KEY = ‘cAtwa1kkEy’ const unsignedToken = base64urlEncode(header) + ‘.’ + base64urlEncode(payload) const signature = HMAC-SHA256(unsignedToken, SECRET_KEY)

Алгоритм base64url кодирует хедер и payload, созданные на 1 и 2 шаге. Алгоритм соединяет закодированные строки через точку. Затем полученная строка хешируется алгоритмом, заданным в хедере на основе нашего секретного ключа.

// header eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 // payload eyJ1c2VySWQiOiJiMDhmODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYzOTA0NjYwYmQifQ // signature -xN_h82PHVTCMA9vdoHrcZxH-x5mb11y1537t3rGzcM

Шаг 4. Теперь объединим все три JWT компонента вместе

Теперь, когда у нас есть все три составляющих, мы можем создать наш JWT. Это довольно просто, мы соединяем все полученные элементы в строку через точку.

const token = encodeBase64Url(header) + ‘.’ + encodeBase64Url(payload) + ‘.’ + encodeBase64Url(signature) // JWT Token // eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJiMDhmODZhZi0zNWRhLTQ4ZjItOGZhYi1jZWYzOTA0NjYwYmQifQ.-xN_h82PHVTCMA9vdoHrcZxH-x5mb11y1537t3rGzcM

Вы можете попробовать создать свой собственный JWT на сайте jwt.io. Вернемся к нашему примеру. Теперь сервер аутентификации может слать пользователю JWT.

Как JWT защищает наши данные?

Очень важно понимать, что использование JWT НЕ скрывает и не маскирует данные автоматически. Причина, почему JWT используются — это проверка, что отправленные данные были действительно отправлены авторизованным источником. Как было продемонстрировано выше, данные внутри JWT закодированы и подписаны, обратите внимание, это не одно и тоже, что зашифрованы. Цель кодирования данных — преобразование структуры. Подписанные данные позволяют получателю данных проверить аутентификацию источника данных. Таким образом закодирование и подпись данных не защищает их. С другой стороны, главная цель шифрования — это защита данных от неавторизованного доступа. Для более детального объяснения различия между кодированием и шифрованием, а также о том, как работает хеширование, смотрите эту статью. Поскольку JWT только лишь закодирована и подписана, и поскольку JWT не зашифрована, JWT не гарантирует никакой безопасности для чувствительных (sensitive) данных.

Шаг 5. Проверка JWT

В нашем простом примере из 3 участников мы используем JWT, который подписан с помощью HS256 алгоритма и только сервер аутентификации и сервер приложения знают секретный ключ. Сервер приложения получает секретный ключ от сервера аутентификации во время установки аутентификационных процессов. Поскольку приложение знает секретный ключ, когда пользователь делает API-запрос с приложенным к нему токеном, приложение может выполнить тот же алгоритм подписывания к JWT, что в шаге 3. Приложение может потом проверить эту подпись, сравнивая ее со своей собственной, вычисленной хешированием. Если подписи совпадают, значит JWT валидный, т.е. пришел от проверенного источника. Если подписи не совпадают, значит что-то пошло не так — возможно, это является признаком потенциальной атаки. Таким образом, проверяя JWT, приложение добавляет доверительный слой (a layer of trust) между собой и пользователем.

Итоги

Данное руководство описывает большинство операций, которые выполняются при управлении Java Keystores. Конечно, охватить все функции в одной статье невозможно. Но зная базовые команды, можно самостоятельно поэкспериментировать с управлением хранилищами.

Данное руководство основано на версии хранилища ключей, которое поставляется с Java 1.7.0. чтобы установить Java, читайте данную статью.
Tags: Cloud Server, CSR, HTTPS, Java, Java Keystore, Java Keytool, JKS, RSA, SSL, TLS, VPS

Fake Rest API (jsonplaceholder)

JSONPlaceholder — Live running version. Можно сделать свой Fake Server, проект доступен на github

Ресурсы

Маршрут
/posts 100 items
/comments 500 items
/albums 100 items
/photos 5000 items
/todos 200 items
/users 10 items

Маршруты

HTTP метод Маршрут
GET /posts
GET /posts/1
GET /posts/1/comments
GET /comments?postId=1
GET /posts?userId=1
POST /posts
PUT /posts/1
PATCH /posts/1
DELETE /posts/1

Например https://jsonplaceholder.typicode.com/posts вернёт

[ { «userId»: 1, «id»: 1, «title»: «sunt aut facere repellat provident occaecati excepturi optio reprehenderit», «body»: «quia et suscipitnsuscipit recusandae consequuntur expedita et cumnreprehenderit molestiae ut ut quas totamnnostrum rerum est autem sunt rem eveniet architecto» }, { «userId»: 1, «id»: 2, «title»: «qui est esse», «body»: «est rerum tempore vitaensequi sint nihil reprehenderit dolor beatae ea dolores nequenfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendisnqui aperiam non debitis possimus qui neque nisi NULLa» }, { «userId»: 1, «id»: 3, «title»: «ea molestias quasi exercitationem repellat qui ipsa sit aut», «body»: «et iusto sed quo iurenvoluptatem occaecati omnis eligendi aut adnvoluptatem doloribus vel accusantium quis pariaturnmolestiae porro eius odio et labore et velit aut» }, …

Видео от Traversy Media по работе Fake Server

Понравилась статья? Поделиться с друзьями:
Добавить комментарий