React Nativeの使用中にSSL証明書のピン留めを実装するにはどうすればよいですか?

Amr Draz:

反応ネイティブアプリケーションにSSL証明書ピン留めを実装する必要があります。

ピン留めはもちろん、SSL / TLSについてもほとんど知りません。私はネイティブのモバイル開発者でもありませんが、Javaを知っており、このプロジェクトでObjective-Cを十分に習得しました。

このタスクの実行方法を探し始めました。

React Nativeはすでにこれを実装していませんか?

いいえ、最初の検索で、2016年8月2日以降何も活動していないこの提案にたどり着きました。

それから、react-nativeがPinningをサポートするOkHttpを使用していることを学びましたが、JavaScriptからそれを引き出すことができません。これは、実際には要件ではなくプラスです。

JavaScriptで実装してください。

reactはnodejsランタイムを使用しているように見えますが、nodeではなくブラウザのようなものです。つまり、すべてのネイティブモジュール、特にこの記事に従って証明書の固定を実装したhttpsモジュールをサポートしているわけではありませんしたがって、ネイティブに反応させることはできませんでした。

rn-nodeifyを使用してみましたが、モジュールが機能しませんでした。これは、私が現在取り組んでいるRN 0.33からRN 0.35まで当てはまります。

phonegapプラグインを使用して実装する

私はphongape-pluginを使用することを考えましたが、反応0.32+を必要とするライブラリに依存しているため、react-native-cordova-pluginを使用できません

ネイティブでやるだけ

私はネイティブアプリの開発者ではありませんが、いつでも問題を解くことができます。

Androidには証明書の固定があります

AndroidがSSLピン接続をサポートしていることを知りましたが、Android 7より前ではこのアプローチは機能せず、Androidでのみ機能するようで、失敗しました。

肝心なこと

私はいくつかの方向を尽くしてきましたが、よりネイティブな実装を追求し続けます。おそらくOkHttpとRNNetworkingを構成する方法を理解し、それからリアクションネイティブにブリッジするかもしれません。

しかし、IOSとandroidの実装またはガイドはすでにありますか?

Amr Draz:

Javascriptから利用可能なオプションの現在のスペクトルを使い果たした後、私は証明書の固定をネイティブに実装することを決定しました。

ソリューションに到達するプロセスを読みたくない場合はAndroid SolutionおよびIOS Solutionというタイトルのヘッダーにスキップしてください。

アンドロイド

工藤の勧めに従って、okhttp3を使用してピン留めを実装することを考えました。

client = new OkHttpClient.Builder()
        .certificatePinner(new CertificatePinner.Builder()
            .add("publicobject.com", "sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=")
            .add("publicobject.com", "sha1/SXxoaOSEzPC6BgGmxAt/EAcsajw=")
            .add("publicobject.com", "sha1/blhOM3W9V/bVQhsWAcLYwPU6n24=")
            .add("publicobject.com", "sha1/T5x9IXmcrQ7YuQxXnxoCmeeQ84c=")
            .build())
        .build();

最初に、反応するネイティブでトーストモジュールを作成するネイティブAndroidブリッジを作成する方法を学びました。次に、簡単なリクエストを送信するメソッドを使用して拡張しました

@ReactMethod
public void showURL(String url, int duration) {
    try {
        Request request = new Request.Builder()
        .url(url)
        .build();
        Response response = client.newCall(request).execute();
        Toast.makeText(getReactApplicationContext(), response.body().string(), duration).show();
    } catch (IOException e) {
        Toast.makeText(getReactApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
    }
}

リクエストの送信に成功した後、リクエストの送信を固定しました。

これらのパッケージをファイルで使用しました

import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.CertificatePinner;
import java.io.IOException;

import java.util.Map;
import java.util.HashMap;

工藤のアプローチは、私がどこで公開鍵を取得するのか、またはどのようにしてそれらを生成するのかについて明確ではありませんでした。幸運なことにokhttp3のドキュメントに加えて、CertificatePinnerの使用方法の明確なデモンストレーションを提供し、公開キーを取得するには、間違ったピンを使用してリクエストを送信するだけでエラーメッセージに正しいピンが表示されると述べています。

Kudoの提案(おそらく古いバージョン)の誤解を招く例とは異なり、OkHttpClent.Builder()をチェーンでき、CertificatePinnerをビルドの前に含めることができることを少し理解した後、このメソッドを思いつきました。

@ReactMethod
public void getKeyChainForHost(String hostname, Callback errorCallbackContainingCorrectKeys,
  Callback successCallback) {
    try {
        CertificatePinner certificatePinner = new CertificatePinner.Builder()
             .add(hostname, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAA=")
             .build();
        OkHttpClient client = (new OkHttpClient.Builder()).certificatePinner(certificatePinner).build();

        Request request = new Request.Builder()
             .url("https://" + hostname)
             .build();
        Response response =client.newCall(request).execute();
        successCallback.invoke(response.body().string());
    } catch (Exception e) {
        errorCallbackContainingCorrectKeys.invoke(e.getMessage());
    }
}

次に、エラーで取得した公開キーチェーンを置き換えると、ページの本文が返され、リクエストが成功したことを示し、キーの1文字を変更して機能していることを確認し、順調に進んでいることを確認しました。

最後に、このメソッドをToastModule.javaファイルに入れました

@ReactMethod
public void getKeyChainForHost(String hostname, Callback errorCallbackContainingCorrectKeys,
  Callback successCallback) {
    try {
        CertificatePinner certificatePinner = new CertificatePinner.Builder()
             .add(hostname, "sha256/+Jg+cke8HLJNzDJB4qc1Aus14rNb6o+N3IrsZgZKXNQ=")
             .add(hostname, "sha256/aR6DUqN8qK4HQGhBpcDLVnkRAvOHH1behpQUU1Xl7fE=")
             .add(hostname, "sha256/HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=")
             .build();
        OkHttpClient client = (new OkHttpClient.Builder()).certificatePinner(certificatePinner).build();

        Request request = new Request.Builder()
             .url("https://" + hostname)
             .build();
        Response response =client.newCall(request).execute();
        successCallback.invoke(response.body().string());
    } catch (Exception e) {
        errorCallbackContainingCorrectKeys.invoke(e.getMessage());
    }
}

React NativeのOkHttpClientを拡張するAndroidソリューション

固定されたhttpリクエストを送信する方法がわかったので、作成した方法を使用できるようになりましたが、理想的には、既存のクライアントを拡張して実装の利点をすぐに得ることが最善だと思いました。

このソリューションは現在有効でRN0.35あり、将来どのように公正になるかわかりません。

RN用のOkHttpClientを拡張する方法を検討しているときに、SSLSocketFactoryを置き換えることによってTLS 1.2サポートを追加する方法を説明するこの記事に出くわしました。

それを読んで、reactはOkHttpClientProviderを使用してXMLHttpRequestオブジェクトが使用するOkHttpClientインスタンスを作成しているため、そのインスタンスを置き換えると、すべてのアプリに固定が適用されます。

私はと呼ばれるファイルを追加OkHttpCertPin.java私にandroid/app/src/main/java/com/dreidevフォルダを

package com.dreidev;

import android.util.Log;

import com.facebook.react.modules.network.OkHttpClientProvider;
import com.facebook.react.modules.network.ReactCookieJarContainer;


import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.CertificatePinner;

public class OkHttpCertPin {
    private static String hostname = "*.efghermes.com";
    private static final String TAG = "OkHttpCertPin";

    public static OkHttpClient extend(OkHttpClient currentClient){
      try {
        CertificatePinner certificatePinner = new CertificatePinner.Builder()
             .add(hostname, "sha256/+Jg+cke8HLJNzDJB4qc1Aus14rNb6o+N3IrsZgZKXNQ=")
             .add(hostname, "sha256/aR6DUqN8qK4HQGhBpcDLVnkRAvOHH1behpQUU1Xl7fE=")
             .add(hostname, "sha256/HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=")
             .build();
        Log.d(TAG, "extending client");
        return currentClient.newBuilder().certificatePinner(certificatePinner).build();
      } catch (Exception e) {
        Log.e(TAG, e.getMessage());
      }
     return currentClient;
   }
}

このパッケージには、既存のOkHttpClientを取得し、certificatePinnerを追加して再構築するメソッド拡張があり、新しく構築されたインスタンスを返します。

次に、この回答のアドバイスに従ってMainActivity.javaファイルを変更し、次のメソッドを追加しました

.
.
.
import com.facebook.react.ReactActivity;
import android.os.Bundle;

import com.dreidev.OkHttpCertPin;
import com.facebook.react.modules.network.OkHttpClientProvider;
import okhttp3.OkHttpClient;

public class MainActivity extends ReactActivity {

  @Override
  public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     rebuildOkHtttp();
  }

  private void rebuildOkHtttp() {
      OkHttpClient currentClient = OkHttpClientProvider.getOkHttpClient();
      OkHttpClient replacementClient = OkHttpCertPin.extend(currentClient);
      OkHttpClientProvider.replaceOkHttpClient(replacementClient);
  }
.
.
.

このソリューションは、OkHttpClientProvider createClientメソッドを完全に再実装することを優先して実行されました。プロバイダーを検査したところ、マスターバージョンにはTLS 1.2サポートが実装されているが、まだ使用できるオプションがないことがわかったため、再構築がクライアントを拡張する最良の方法。このアプローチがアップグレード時にどのように公平になるか疑問に思っていますが、今のところそれはうまく機能しています。

アップデート 0.43以降、このトリックは機能しなくなったようです。時間的な制約があるため、リビルドが機能しなくなった理由が明らかになるまで、今のところプロジェクトを0.42に凍結します。

ソリューションIOS

IOSの場合、私は同様の方法に従う必要があると思っていましたが、やはり工藤の提案を筆頭に始めました。

RCTNetworkモジュールを調べると、NSURLConnectionが使用されていることがわかりました。そのため、提案で提案されているように、AFNetworkingで完全に新しいモジュールを作成しようとする代わりに、TrustKitを見つけました。

私が追加したその入門ガイドに従って

pod 'TrustKit'

私のポッドファイルに、実行しました pod install

GettingStartedGuideは、pList.fileからこのポッドを構成する方法を説明しましたが、構成ファイルよりもコードを使用したいので、AppDelegate.mファイルに次の行を追加しました

.
.
.
#import <TrustKit/TrustKit.h>
.
.
.
@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{


  // Initialize TrustKit
  NSDictionary *trustKitConfig =
    @{
    // Auto-swizzle NSURLSession delegates to add pinning validation
    kTSKSwizzleNetworkDelegates: @YES,

    kTSKPinnedDomains: @{

       // Pin invalid SPKI hashes to *.yahoo.com to demonstrate pinning failures
       @"efghermes.com" : @{
           kTSKEnforcePinning:@YES,
           kTSKIncludeSubdomains:@YES,
           kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048],

           // Wrong SPKI hashes to demonstrate pinning failure
           kTSKPublicKeyHashes : @[
              @"+Jg+cke8HLJNzDJB4qc1Aus14rNb6o+N3IrsZgZKXNQ=",
              @"aR6DUqN8qK4HQGhBpcDLVnkRAvOHH1behpQUU1Xl7fE=",
              @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY="
              ],

          // Send reports for pinning failures
          // Email [email protected] if you need a free dashboard to see your App's reports
          kTSKReportUris: @[@"https://overmind.datatheorem.com/trustkit/report"]
          },

     }
  };

  [TrustKit initializeWithConfiguration:trustKitConfig];
.
.
.

私はAndroid実装から公開鍵ハッシュを取得し、それはうまくいきました(私のポッドで受け取ったTrustKitのバージョンは1.3.2です)

IOSが呼吸であることが判明してうれしかった

補足として、NSURLSessionとConnectionが既にスウィズルされている場合、自動スウィズルは機能しないことをTrustKitは警告しました。それは今のところうまく機能しているようだと言った。

結論

この回答は、AndroidとIOSの両方のソリューションを示しています。これをネイティブコードで実装できたとすれば、

考えられる改善の1つは、公開キーの設定とAndroidとIOSの両方のネットワークプロバイダーの設定をJavaScriptで管理できる共通プラットフォームモジュールを実装することです。

ただし、公開鍵をjsバンドルに追加するだけであると述べた工藤の提案には、バンドルファイルが何らかの方法で置き換えられる可能性があるという脆弱性が存在する可能性があります。

その攻撃ベクトルがどのように機能するかはわかりませんが、提案されているbundle.jsに署名するという追加の手順によって、jsバンドルが保護される可能性があります。

別のアプローチとしては、jsバンドルを64ビット文字列に単純にエンコードし、この問題の会話で述べたように、ネイティブコードに直接含める方法がありますこのアプローチには、jsバンドルを難読化し、アプリにハードワイヤリングするという利点があり、攻撃者がアクセスできないようになっていると思います。

ここまで読んだら、バグを修正するための探求について啓蒙し、晴れた日を楽しんでほしいと思います。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

React Nativeの使用中にSSL証明書のピン留めを実装するにはどうすればよいですか?

分類Dev

React Nativeの使用中にSSL証明書のピン留めを実装するにはどうすればよいですか?

分類Dev

create-react-appでSSL証明書を提供するにはどうすればよいですか?

分類Dev

ReactアプリとSpringブートサーバーにSSL証明書を適用するにはどうすればよいですか?

分類Dev

画像値を取得して、reactで別のdivに実装するにはどうすればよいですか?

分類Dev

React Native の最新バージョンで Navigator を使用するにはどうすればよいですか?

分類Dev

React Hooksを使用して、ラジオボタンの[すべてチェック]ボタンを実装するにはどうすればよいですか?

分類Dev

react-reduxを使用してログイン認証を実装するにはどうすればよいですか?

分類Dev

React NativeでFirebaseを使用してMicrosoftログインを実装するにはどうすればよいですか?

分類Dev

React Native with Jestでrealm.ioの実装を適切にテストするにはどうすればよいですか?

分類Dev

React Nativeで以下の設計を実現するにはどうすればよいですか?

分類Dev

React NativeでMapViewの右下隅にボタンを配置するにはどうすればよいですか?

分類Dev

React Native-ログイン後に認証トークンを保存して他の画面に移動するにはどうすればよいですか?

分類Dev

React NativeのsetNativePropsにuseRefフックを使用するにはどうすればよいですか?

分類Dev

リボンを作成するためにreact-nativeでビューのスタイルを設定するにはどうすればよいですか?

分類Dev

React NativeのTextInput内にアイコンを配置するにはどうすればよいですか?

分類Dev

React NativeのTextInput内にアイコンを配置するにはどうすればよいですか?

分類Dev

React NativeのNavigatorIOSに右ボタンを追加するにはどうすればよいですか?

分類Dev

フック付きのReactでこのカウントダウンタイマーを実装するにはどうすればよいですか?

分類Dev

Reactの入力変更時にデバウンスされた自動保存を実装するにはどうすればよいですか?

分類Dev

React Native 0.57のデコレータでMobXを使用するにはどうすればよいですか?

分類Dev

react-nativeのモーダルでタブを使用するにはどうすればよいですか?

分類Dev

React Nativeで「FrameLayout」コンポーネントを実現するにはどうすればよいですか?

分類Dev

このReactトランジションを最適に実装するにはどうすればよいですか?

分類Dev

setState()を使用してReact Nativeの多次元配列を変更するにはどうすればよいですか?

分類Dev

React-Nativeを使用してこのJsonを消費するにはどうすればよいですか?

分類Dev

React NativeでFirestoreのドキュメントを削除するにはどうすればよいですか?

分類Dev

このsvgをreactコンポーネントに含めるにはどうすればよいですか?

分類Dev

[React-Native-Firebase] onMessageの存在イベントを削除するにはどうすればよいですか?

Related 関連記事

  1. 1

    React Nativeの使用中にSSL証明書のピン留めを実装するにはどうすればよいですか?

  2. 2

    React Nativeの使用中にSSL証明書のピン留めを実装するにはどうすればよいですか?

  3. 3

    create-react-appでSSL証明書を提供するにはどうすればよいですか?

  4. 4

    ReactアプリとSpringブートサーバーにSSL証明書を適用するにはどうすればよいですか?

  5. 5

    画像値を取得して、reactで別のdivに実装するにはどうすればよいですか?

  6. 6

    React Native の最新バージョンで Navigator を使用するにはどうすればよいですか?

  7. 7

    React Hooksを使用して、ラジオボタンの[すべてチェック]ボタンを実装するにはどうすればよいですか?

  8. 8

    react-reduxを使用してログイン認証を実装するにはどうすればよいですか?

  9. 9

    React NativeでFirebaseを使用してMicrosoftログインを実装するにはどうすればよいですか?

  10. 10

    React Native with Jestでrealm.ioの実装を適切にテストするにはどうすればよいですか?

  11. 11

    React Nativeで以下の設計を実現するにはどうすればよいですか?

  12. 12

    React NativeでMapViewの右下隅にボタンを配置するにはどうすればよいですか?

  13. 13

    React Native-ログイン後に認証トークンを保存して他の画面に移動するにはどうすればよいですか?

  14. 14

    React NativeのsetNativePropsにuseRefフックを使用するにはどうすればよいですか?

  15. 15

    リボンを作成するためにreact-nativeでビューのスタイルを設定するにはどうすればよいですか?

  16. 16

    React NativeのTextInput内にアイコンを配置するにはどうすればよいですか?

  17. 17

    React NativeのTextInput内にアイコンを配置するにはどうすればよいですか?

  18. 18

    React NativeのNavigatorIOSに右ボタンを追加するにはどうすればよいですか?

  19. 19

    フック付きのReactでこのカウントダウンタイマーを実装するにはどうすればよいですか?

  20. 20

    Reactの入力変更時にデバウンスされた自動保存を実装するにはどうすればよいですか?

  21. 21

    React Native 0.57のデコレータでMobXを使用するにはどうすればよいですか?

  22. 22

    react-nativeのモーダルでタブを使用するにはどうすればよいですか?

  23. 23

    React Nativeで「FrameLayout」コンポーネントを実現するにはどうすればよいですか?

  24. 24

    このReactトランジションを最適に実装するにはどうすればよいですか?

  25. 25

    setState()を使用してReact Nativeの多次元配列を変更するにはどうすればよいですか?

  26. 26

    React-Nativeを使用してこのJsonを消費するにはどうすればよいですか?

  27. 27

    React NativeでFirestoreのドキュメントを削除するにはどうすればよいですか?

  28. 28

    このsvgをreactコンポーネントに含めるにはどうすればよいですか?

  29. 29

    [React-Native-Firebase] onMessageの存在イベントを削除するにはどうすればよいですか?

ホットタグ

アーカイブ