Ionic 如何正确设置我的离子(Angular )开发机器与自签名证书?

63lcw9qa  于 2022-12-08  发布在  Ionic
关注(0)|答案(1)|浏览(131)

我正在开发一个Ionic-Angular应用程序,由于明文流量的原因,我遇到了很多问题。所以我决定在编码时切换到https,但这并不容易。
我打开这个问题,并提出我发现的答案,以保持一个痕迹,希望保存你一些时间,如果你想这样做。

wqsoz72f

wqsoz72f1#

Edit:
I now have a repo for certificates generation scripts: https://github.com/ch4mpy/self-signed-certificate-generation

Prerequisite

You need a hostname for your dev machine. This name will be declared in certificates and https services will be accessed using this hostname (URLs have to be like https://[hostname]:... for certificate check to pass).
If your network doesn't have a DNS already, you might use something like MaraDNS hosted on your dev-machine (see P.S. for sample configuration).

Generate certificate (and signing key) in various formats

self_signed_template.config:

[req]
default_bits       = 2048
default_md         = sha256
prompt             = no
default_keyfile    = [hostname]_self_signed_key.pem
encrypt_key        = no

distinguished_name = dn

req_extensions     = v3_req
x509_extensions    = v3_req

[dn]
C            = PF
ST           = Tahiti
L            = Papeete
O            = c4-soft
emailAddress = ch4mp@c4-soft.com
CN           = [hostname]

[v3_req]
subjectAltName   = critical, @alt_names
basicConstraints = critical, CA:false
keyUsage         = critical, keyCertSign, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = critical, serverAuth, clientAuth

[alt_names]
DNS.1 = [hostname]
DNS.2 = localhost
DNS.3 = 10.0.2.2

self_signed.sh

#!/bin/bash
if [ -z "$1" ]
then
  echo "Usage:"
  echo ""
  echo "self_signed.sh key_password [java_home] [hostname] [store_password] [certificates_directory_path] [cacerts_password]"
  echo ""
  echo "  - java_home is defaulted to $JAVA_HOME"
  echo "  - hostname is defaulted to $HOSTNAME"
  echo "  - store_password is defaulted to key_password"
  echo "  - certificates_directory_path is defaulted to current diretory"
  echo "  - cacerts_password is defaulted to changeit"
  echo ""
  echo "Sample:"
  echo "./self_signed.sh \"secr3!\" \"C:/Java/jdk1.8.0_281\" \"bravo-ch4mp\""
  echo ""
  exit 1
else

  echo "#------------------------------------------"
  echo "# This is a no-op script"
  echo "# Copy / paste output to:"
  echo "#   - generate certificate files"
  echo "#   - import certificates into cacerts file"
  echo "#------------------------------------------"
  
  KEY_PASSWORD="${1}"
  echo "# key password: $KEY_PASSWORD"
  
  if [ -z "$2" ]
  then
    if [ -z "$JAVA_HOME" ]
    then
      echo "ERROR: could not locate java home"
      exit 1
    else
      JAVA=$JAVA_HOME
    fi
  else
    JAVA=$2
  fi
  JAVA=$(echo $JAVA | sed 's/\\/\//g')
  echo "# java home: $JAVA"
  
  if [ -f "${JAVA}/lib/security/cacerts" ]
  then
    # recent JDKs and JREs style
    CACERTS="${JAVA}/lib/security/cacerts"
  elif [ -f "${JAVA}/jre/lib/security/cacerts" ]
  then
    # legacy JDKs style (1.8 and older)
    CACERTS="${JAVA}/jre/lib/security/cacerts"
  else
    echo "ERROR: could not locate cacerts under ${JAVA}"
    exit 1
  fi
  echo "# cacerts path: $CACERTS"
  
  if [ -z "${3}" ]
  then
    HOST="$HOSTNAME"
  else
    HOST="${3}"
  fi
  echo "# host (certificate CN): $HOST"
  
  if [ -z "${4}" ]
  then
    STORE_PASSWORD="$KEY_PASSWORD"
  else
    STORE_PASSWORD="${4}"
  fi
  echo "# store password : $STORE_PASSWORD"
  
  if [ -z "${5}" ]
  then
    CERTIF_DIR="."
  else
    CERTIF_DIR="${5}"
  fi
  echo "# certificates directory path: $CERTIF_DIR"
  CERTIF_DIR=$(echo $CERTIF_DIR | sed 's/\\/\//g')
  
  if [ -z "${6}" ]
  then
    CACERTS_PASSWORD="changeit"
  else
    CACERTS_PASSWORD="${6}"
  fi
  echo "# cacerts password: $CACERTS_PASSWORD" 
  echo "#------------------------------------------"
fi

echo ""

rm -f ${HOST}_self_signed.config;
sed 's/\[hostname\]/'${HOST}'/g' "${CERTIF_DIR}/self_signed_template.config" > "${CERTIF_DIR}/${HOST}_self_signed.config"

echo openssl req -config \"${CERTIF_DIR}/${HOST}_self_signed.config\" -new -keyout \"${CERTIF_DIR}/${HOST}_self_signed_key.pem\" -out \"${CERTIF_DIR}/${HOST}_self_signed_cert.pem\" -reqexts v3_req
echo ""

echo openssl x509 -req -days 365 -extfile \"${CERTIF_DIR}/${HOST}_self_signed.config\" -in \"${CERTIF_DIR}/${HOST}_self_signed_cert.pem\" -extensions v3_req -signkey \"${CERTIF_DIR}/${HOST}_self_signed_key.pem\" -out \"${CERTIF_DIR}/${HOST}_self_signed.crt\"
echo ""

echo openssl pkcs12 -export -in \"${CERTIF_DIR}/${HOST}_self_signed.crt\" -inkey \"${CERTIF_DIR}/${HOST}_self_signed_key.pem\" -name ${HOST}_self_signed -password pass:${KEY_PASSWORD} -out \"${CERTIF_DIR}/${HOST}_self_signed.pfx\"
echo ""

echo \"${JAVA}/bin/keytool\" -importkeystore -srckeystore \"${CERTIF_DIR}/${HOST}_self_signed.pfx\" -srcstorepass \"${STORE_PASSWORD}\" -srcstoretype pkcs12 -srcalias ${HOST}_self_signed -destkeystore \"${CERTIF_DIR}/${HOST}_self_signed.jks\" -deststoretype PKCS12 -deststorepass ${STORE_PASSWORD} -destalias ${HOST}_self_signed
echo ""

echo \"${JAVA}/bin/keytool\" -importkeystore -srckeystore \"${CERTIF_DIR}/${HOST}_self_signed.pfx\" -srcstorepass \"${STORE_PASSWORD}\" -srcstoretype pkcs12 -srcalias ${HOST}_self_signed -destkeystore \"${CACERTS}\" -deststorepass ${CACERTS_PASSWORD} -destalias ${HOST}_self_signed
echo ""

Then run something like ./self_signed.sh "secr3!" C:/Java/jdk1.8.0_281 .
Execute ./self_signed.sh for each of your JDKs / JREs and then Simply copy / paste / run all output commands at 1st execution and last command only (import certificate in JDK / JRE cacerts file) from 2nd execution on (otherwise you'll loose previous certificates).
Admin privileges could be required to import the certificate in Java's cacerts.
On windows, Git Bash has all of sed , openssl and keytool on the path.

Import this certificate as trusted root authority

If you add this certificate to trusted root authorities, your browser will display no error nor warning when navigating URLs like https://[hostname]:... .
On windows, this can be done with certmgr.msc (right click trusted root authorities and then import). Please comment if you successfully do the same on other OS.

Configure Ionic-Angular to serve over https with this certificate

Edit angular.json to set "sslCert" and "sslKey" under your-project/architect/serve/options/ and point it to respectively [hostname]_self_signed.crt and [hostname]_self_signed_key.pem generated earlier.
This is enough for the right certificate to be picked when running ionic serve --ssl --host=[hostname] or ionic capacitor run android -l --ssl --host=[hostname]

Embed certificate in Android project

Reminder: android resource folder is android/app/src/main/res/ under your project or app/res/ in Android Studio
First, copy [hostname]_self_signed.crt to raw resources, replacing - , if any, with _ in hostname.
Create network_security_config.xml in xml resources (careful with modified hostname)

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
          <certificates src="@raw/[hostname]_self_signed"/>
          <certificates src="system"/>
        </trust-anchors>
    </base-config>
</network-security-config>

important note: if all your trafic is served over https, you should set cleartextTrafficPermitted to false (which is default value since Android 9). Consider doing so for prod build at least.
Finally, edit AndroidManifest.xml and add android:networkSecurityConfig="@xml/network_security_config" to your <application > tag

Embed certificate in iOS project

I have no experience with iOS, please feel free to comment or add an answer if you get it working.

Configure your backends to serve over https with self-signed certificate

Well... it really depends on the stack you use. A few samples:

  • For Kestrel (.Net app debugged in Visual Studio), set ASPNETCORE_Kestrel__Certificates__Default__Password and ASPNETCORE_Kestrel__Certificates__Default__Path , the second pointing to the [hostname]_self_signed.pfx
  • For spring-boot, copy [hostname]_self_signed.jks into src/main/resources/ and set server.ssl properties
  • Keycloak has comprensive doc to setup the server with custom certificate
  • Please comment if you get other backend types working
    P.S. The dwood3rc.txt file I use for MaraDNS:
#upstream_servers = {}
#upstream_servers["."]="8.8.8.8, 8.8.4.4" # Servers we connect to 
root_servers = {}
# ICANN DNS root servers 
root_servers["."]="198.41.0.4, 199.9.14.201, 192.33.4.12, 199.7.91.13,"
root_servers["."]+="192.203.230.10, 192.5.5.241, 192.112.36.4, "
root_servers["."]+="198.97.190.53, 192.36.148.17, 192.58.128.30, "
root_servers["."]+="193.0.14.129, 199.7.83.42, 202.12.27.33"
# local DNS server
root_servers["bravo-ch4mp."]="192.168.1.181"
root_servers["local."]="192.168.1.181"

# The IP this program has 
bind_address="127.0.0.1, 192.168.1.181, 192.168.1.132"

# The IPs allowed to connect and use the cache
recursive_acl = "127.0.0.1/16, 192.168.0.1/16"

chroot_dir = "/etc/maradns"

# This is the file Deadwood uses to read the cache to and from disk
cache_file = "dw_cache_bin"

filter_rfc1918 = 0

ip4 = {}
ip4["bravo-ch4mp."] = "192.168.1.181"

ip6 = {}

Once the DNS server is up ( net start deadwood ) on my dev machine (and also firewall configured...), I configure clients to use it as primary DNS (edit wifi network properties which does not require rooted device) et voilà!

P.S.2 Keycloak standalone configuration allowing test devices to connect to OpenId endpoints over https

Copy [hostname]_self_signed.jks to standalone/configuration/ .
Edit standalone/configuration/standalone.xml to replace ${jboss.bind.address:127.0.0.1} with ${jboss.bind.address:0.0.0.0} . Save and close.
Start Keycloak with bin/standalone[.bat|.sh] , then using bin/jboss-cli[.bat|.sh] :

connect
/subsystem=keycloak-server/spi=hostname/provider=default:write-attribute(name=properties.frontendUrl,value="https://[hostname]:8443/auth")
/core-service=management/security-realm=UndertowRealm:add()
/core-service=management/security-realm=UndertowRealm/server-identity=ssl:add(keystore-path=[hostname]_self_signed.jks, keystore-relative-to=jboss.server.config.dir, keystore-password=[keystore_password])
/subsystem=undertow/server=default-server/https-listener=https:write-attribute(name=security-realm, value=UndertowRealm)
reload

相关问题