GRPC на Android с использованием TLS

RedDeveloper
05.01.2023 04:48
GRPC на Android с использованием TLS

GRPC - это относительно новая концепция взаимодействия между клиентом и сервером, но не более.

gRPC client-server

Что такое удаленный вызов процедур (RPC)?

Удаленный вызов процедуры - это протокол связи программного обеспечения. Один процесс может вызвать процедуру (также известную как функция или подпрограмма) на удаленной системе (например, локальной) без предварительного знания сети удаленной системы.

RPC использует традиционную модель "клиент-сервер". Сервер определяет процедуры, а клиент запрашивает удаленные серверы для применения бизнес-логики и возврата результата.

Rest vs gRPC:

Передача репрезентативного состояния (REST) - это коммуникационный протокол взаимодействия между клиентом и сервером, построенный на основе HTTP 1.1/HTTPS 1.1 с такими глаголами, как (PUT, POST, GET и т.д.).

GRPC - это удаленный вызов протокола от Google, кроссплатформенный коммуникационный протокол с открытым исходным кодом, основанный на контрактах и упрощающий межсервисное взаимодействие.

GRPC использует двунаправленную функцию HTTP/2.0 и TLS. gRPC также обеспечивает более эффективную коммуникацию через сериализованные двоичные полезные нагрузки. В качестве механизма управления и сериализации полезной нагрузки он использует буфер протокола, подобно JSON в Rest.

В отличие от JSON буфер протокола также состоит из трех основных частей:

  1. Язык определения контракта, т.е. proto3 (последняя спецификация языка буфера протокола).
  2. Сгенерированный функциональный код
  3. Библиотеки времени выполнения, специфичные для конкретного языка

В отличие от HTTP/1.1, который последовательно загружает ресурсы, HTTP/2.0 использует TCP-соединение и одно соединение для передачи многих потоков данных, поэтому блокировка ресурсов отсутствует. В HTTP/1.1 мы можем столкнуться с проблемой, если ресурс не сможет загрузиться, последовательность будет заблокирована.

Что такое proto3?

syntax = 'proto3';

package bookStorePackage;

// Book service definition. defines all the rpc methods here
service Book {
    rpc createBook (BookItemReq) returns (BookItem);
    rpc readBook (BookRequest) returns (BookItem);
    rpc readBooks (Empty) returns (BooksList);
}

// inputs / request , e.g. BookItemReq 
// outputs / response BookItem must be defined
// they are defined with a keyword of struct

message BookItemReq {
    string name = 1;
    string description = 2;
    string author = 3;
}

message BookItem {
    int32 id = 1;
    string name = 2;
    string description = 3;
    string author = 4;
}

message BookRequest {
    int32 id = 1;
}

message BooksList {
    repeated BookItem books = 1;
}

message Empty {}

Файл `.proto` содержит структуру нашего gRPC и определяет процедуры и запросы/ответы для каждого вызова. Файлы .proto транслируются в файлы буферов proto с помощью плагина protoc.

protoc --proto_path=src --java_out=build/gen PROTO_PATH

Давайте теперь подробнее рассмотрим код. Вы можете найти много ресурсов для реализации gRPC без TLS. Мы рассмотрим создание клиента gRPC на android с TLS.

Некоторые требования перед началом работы: безопасный gRPC-сервер, написанный на любом языке.

Как это сделать для Android Studio:

Во-первых, нам нужно создать новый проект в android. В этом проекте мы будем использовать пустую активность. Затем установите зависимости и добавьте следующее в build.gradle.

plugins {
    id 'com.google.protobuf' version '0.8.18'
}

// this is used to generate proto buf file when you build the project
protobuf {
    protoc {
        artifact = "com.google.protobuf:protoc:3.21.7"
    }
    plugins {
        grpc {
            artifact = 'io.grpc:protoc-gen-grpc-java:1.51.0'
        }
    }
    generateProtoTasks {
        all().each { task ->
            task.builtins {
                java { option 'lite' }
            }
            task.plugins {
                grpc { option 'lite' }
            }
        }
    }
}

dependencies {
    // for TLS based connection we need okhttp
    implementation 'io.grpc:grpc-okhttp:1.51.1'
    implementation 'io.grpc:grpc-protobuf-lite:1.51.1'
    implementation 'io.grpc:grpc-stub:1.51.1'
    // these are used to set up a secure client
    implementation 'com.squareup.okhttp3:okhttp-tls:4.10.0'
    implementation 'com.squareup.okhttp3:okhttp:4.10.0'
}

Теперь нам нужно добавить файл proto в наш проект.

Теперь нам нужно добавить файл proto в наш проектFile Structure Section in Android Studio

Нам нужно изменить структуру с android на проект. Теперь мы можем добавить наш файл proto в app/src/main/proto. Нам нужно создать каталог с именем proto и поместить туда наш файл .proto.

Нам нужно изменить структуру с android на проект Теперь мы можем добавить наш файл protoProto file destination app/src/main/proto

Теперь нам нужно собрать наш проект с помощью панели инструментов > build > rebuild project.

Теперь нам нужно собрать наш проект с помощью панели инструментов > build > rebuildrebuild project to get generated code.

Вот сгенерированный файл, который вы получите.

Вот сгенерированный файл который вы получитеauto-generated protocol buffer files.Вот сгенерированный файл который вы получитеBookGrpc auto-generated class

Один важный момент, как мы знаем, в java мы имеем определенное имя пакета в нашем проекте. Как мы можем указать его в нашем proto файле?

Очень просто. Нам нужно добавить опцию для java, чтобы направлять компилятор (protoc) при генерации буферного файла proto.

Очень просто Нам нужно добавить опцию для java чтобы направлять компилятор (protoc) приproto file with java options

Добавив эту опцию в наш файл proto, наш компилятор поймет, что ему нужно указать имя пакета, которое мы навязали. По умолчанию он будет использовать ключевое слово package в качестве имени нашего пакета.

Теперь давайте разберемся, как настроить нашего клиента на взаимодействие с сервером gRPC через защищенное соединение.

Мы должны поместить наш сертификат подписи в категорию raw в папке res нашего приложения.

Мы должны поместить наш сертификат подписи в категорию raw в папке res нашего приложенияlocation to add the signing certificate

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

        try{
            Resources res = getResources();
            InputStream instream = res.openRawResource(R.raw.ca_cert);
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            Certificate ca = cf.generateCertificate(instream);
            KeyStore kStore = KeyStore.getInstance(KeyStore.getDefaultType());
            kStore.load(null, null);
            kStore.setCertificateEntry("ca", ca);
            TrustManagerFactory tmf = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(kStore);
            TrustManager[]  trustManagers = tmf.getTrustManagers();
            if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
                throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
            }
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, tmf.getTrustManagers(), null);
            SSLSocketFactory sslSocketFactory = context.getSocketFactory();
            
            final ManagedChannel channel = OkHttpChannelBuilder
                    .forAddress("IP Address",PORT)
                    .useTransportSecurity()
                    .overrideAuthority("add same DNS / IP:PORT entry here")
                    .sslSocketFactory(sslSocketFactory)
                    .build();
            // BookGrpc is an auto generated class from the proto we defined.
            BookGrpc.BookBlockingStub stub = BookGrpc.newBlockingStub(channel);
            // create a request object
            BookItemReq requestData = BookItemReq
                    .newBuilder()
                    .setName("AnyName")
                    .setAuthor("AnyAuthor")
                    .setDescription("Any Description")
                    .build();
            BookItem response = stub.createBook(requestData);
            // handle the response
            System.out.println(response);
            channel.shutdown();
        } catch (Exception e){
            e.printStackTrace();
        }

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

Что делает этот код?

Как мы знаем, чтобы установить безопасное соединение, у нас есть набор сертификатов, которые гарантируют, что наша связь зашифрована. Нам нужно добавить сертификат подписи в наше android-приложение.

Далее мы считываем сертификат с помощью следующих строк.

Resources res = getResources();
InputStream instream = res.openRawResource(R.raw.ca_cert);

Сначала мы получаем экземпляр ресурса, затем используем функцию openRawResource для чтения нашего сертификата. Затем мы генерируем сертификат из нашего файла и добавляем его в качестве доверенного сертификата. Используя доверенный сертификат, мы инициализируем экземпляр контекста SSL для инициализации фабрики сокетов SSL. Фабрика сокетов SSL действует как фактор защищенных сокетов.

Зашифрованный канал обрабатывает запросы и ответы от сервера. Мы использовали OkHttpChannelBuilder, который поддерживает использование SSLSocketFactor для обеспечения безопасной среды связи между клиентом и сервером.

Как получить сертификаты самостоятельно?

Для генерации сертификатов вы можете использовать следующий скрипт:

rm *.pem
rm *.srl
rm *.cnf

# 1. Generate CA's private key and self-signed certificate
openssl req -x509 -newkey rsa:4096 -days 365 -nodes -keyout ca-key.pem -out ca-cert.pem -subj "/C=FR/ST=Occitanie/L=Toulouse/O=Test Org/OU=Test/CN=*.test/emailAddress=test@gmail.com"

echo "CA's self-signed certificate"
openssl x509 -in ca-cert.pem -noout -text

# 2. Generate web server's private key and certificate signing request (CSR)
openssl req -newkey rsa:4096 -nodes -keyout server-key.pem -out server-req.pem -subj "/C=FR/ST=Ile de France/L=Paris/O=Server TLS/OU=Server/CN=*.tls/emailAddress=tls@gmail.com"

# Remember that when we develop on localhost, It’s important to add the IP:0.0.0.0 as an Subject Alternative Name (SAN) extension to the certificate.
echo "subjectAltName=DNS:*.tls,DNS:example.com,IP:0.0.0.0" > server-ext.cnf
# Or you can use localhost DNS and grpc.ssl_target_name_override variable
# echo "subjectAltName=DNS:localhost" > server-ext.cnf

# 3. Use CA's private key to sign web server's CSR and get back the signed certificate
openssl x509 -req -in server-req.pem -days 60 -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile server-ext.cnf

echo "Server's signed certificate"
openssl x509 -in server-cert.pem -noout -text

# 4. Generate client's private key and certificate signing request (CSR)
openssl req -newkey rsa:4096 -nodes -keyout client-key.pem -out client-req.pem -subj "/C=FR/ST=Alsace/L=Strasbourg/O=PC Client/OU=Computer/CN=*.client.com/emailAddress=client@gmail.com"

# Remember that when we develop on localhost, It’s important to add the IP:0.0.0.0 as an Subject Alternative Name (SAN) extension to the certificate.
echo "subjectAltName=DNS:eaple.com,IP:0.0.0.0" > client-ext.cnf

# 5. Use CA's private key to sign client's CSR and get back the signed certificate
openssl x509 -req -in client-req.pem -days 60 -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -extfile client-ext.cnf

echo "Client's signed certificate"
openssl x509 -in client-cert.pem -noout -text

Примечание: Полный код вы можете найти на сайте https://github.com/AbdullahJanKhan/android-grpc-tls

Руководство для начинающих по веб-разработке на React.js
Руководство для начинающих по веб-разработке на React.js

21.03.2023 12:23

Веб-разработка - это захватывающая и постоянно меняющаяся область, которая постоянно развивается благодаря новым технологиям и тенденциям. Одним из самых популярных фреймворков для веб-разработки сегодня является React.js. Если вы начинающий веб-разработчик и хотите узнать больше о React.js, это...

Разница между Angular и React
Разница между Angular и React

21.03.2023 07:56

React и AngularJS - это два самых популярных фреймворка для веб-разработки. Оба фреймворка имеют свои уникальные особенности и преимущества, которые делают их подходящими для различных проектов веб-разработки.

Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit

20.03.2023 14:01

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

Калькулятор CGPA 12 для семестра
Калькулятор CGPA 12 для семестра

20.03.2023 12:24

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

ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023

20.03.2023 11:15

О тренинге HTML JavaScript :HTML (язык гипертекстовой разметки) и CSS (каскадные таблицы стилей) - две основные технологии для создания веб-страниц. HTML обеспечивает структуру страницы CSS (визуальное и звуковое) оформление для различных устройств. Наряду с графикой и сценариями HTML и CSS являются...

Как собрать/развернуть часть вашего приложения Angular
Как собрать/развернуть часть вашего приложения Angular

20.03.2023 08:46

Вам когда-нибудь требовалось собрать/развернуть только часть вашего приложения Angular или, возможно, скрыть некоторые маршруты в определенных средах?