Akka-CQRS(13)- SSL/TLS for gRPC and HTTPS:自簽名證書產生和使用

来源:https://www.cnblogs.com/tiger-xc/archive/2019/06/24/11075240.html
-Advertisement-
Play Games

到現在,我們已經完成了POS平臺和前端的網路集成。不過,還是那句話:平臺系統的網路安全是至關重要的。前一篇博客里我們嘗試實現了gRPC ssl/tls網路連接,但測試時用的證書如何產生始終沒有搞清楚。現在akka-http開發的ws同樣面臨HTTPS的設置和使用問題。所以,特別抽出這篇博文討論一下數 ...


  到現在,我們已經完成了POS平臺和前端的網路集成。不過,還是那句話:平臺系統的網路安全是至關重要的。前一篇博客里我們嘗試實現了gRPC ssl/tls網路連接,但測試時用的證書如何產生始終沒有搞清楚。現在akka-http開發的ws同樣面臨HTTPS的設置和使用問題。所以,特別抽出這篇博文討論一下數字證書的問題。

在正式的生產環境里數字證書應該是由第三方公證機構CA簽發的,我們需要向CA提出申請。數字證書的申請、簽發和驗證流程如下:

1) 服務⽅ S 向第三⽅方機構CA提交公鑰、組織信息、個⼈信息(功能變數名稱)等資料提出認證申請 (不需要提供私鑰)

2) CA 通過各種手段驗證申請者所提供信息的真實性,如組織是否存在、 企業是否合法,是否擁有功能變數名稱的所有權等

3) 如信息審核通過,CA 會向申請者簽發認證文件-證書。 證書包含以下信息:申請者公鑰、申請者的組織信息和個⼈信息、簽發機構 CA 信息、有效時間、證書序列號等信息的明⽂,同時包含一個簽名的產⽣生演算法:首先,使用散列函數計算出證書中公開明文信息的信息摘要,然後, 採用 CA 的私鑰對信息摘要進⾏加密,這個密⽂就是簽名了

4) 客戶端 C 向伺服器 S 發出請求時,S 返回證書文件

5) 客戶端 C 讀取證書中的相關的明⽂信息,採⽤相同的散列函數計算得到信息摘要, 然後,利用對應 CA 的公鑰解密簽名數據,對比證書的信息摘要,如果一致,則可以確認證書的合法性,即公鑰合法

6) 客戶端 C 然後檢驗證書相關的功能變數名稱信息、有效時間等信息

7) 客戶端 C 應內置信任 CA 的證書信息(包含公鑰),如果 CA 不被信任,則找不到對應 CA 的證書,證書也會被判定非法

8) 內置 CA 對應的證書稱為根證書,頒發者和使⽤者相同,用 CA ⾃⼰的私鑰簽名,即⾃簽名證書(此證書中的公鑰即為 CA 的公鑰,可以使用這個公鑰對證書的簽名進行校驗,⽆需另外⼀份證書)

伺服器端在通信中建立SSL加密渠道過程如下:

1)客戶端 C 發送請求到伺服器端 S

2) 伺服器端 S 返回證書和公開密鑰到 C,公開密鑰作為證書的一部分傳送

3)客戶端 C 檢驗證書和公開密鑰的有效性,如果有效,則⽣成共用密鑰並使⽤公開密鑰加密發送到伺服器端 S

4) 伺服器端 S 使⽤私有密鑰解密數據,並用收到的共用密鑰加密數據,發送到客戶端 C 

5) 客戶端 C 使⽤用共用密鑰解密數據

6) SSL 加密通信渠道建立 ...

應該說,需要在客戶端進行認證的應用場景不多。這種情況需要在客戶端存放數字證書。像支付寶和一些銀行客戶端一般都需要安裝證書。

好了,還是回到如何產生自簽名證書示範吧。下麵是一個標準的用openssl命令產生自簽名證書流程:

在產生證書和密鑰的過程中所有系統提問回答要一致。我們先假設密碼統一為:123456

1、生成根證書私鑰: rootCA.key:  openssl genrsa -des3 -out rootCA.key 2048 

2、根證書申請 rootCA.csr:openssl req -new -key rootCA.key -out rootCA.csr

3、用申請rootCA.csr生成根證書 rootCA.crt:openssl x509 -req -days 365 -sha256 -extensions v3_ca -signkey rootCA.key -in rootCA.csr -out rootCA.crt

4、pem根證書 rootCA.pem:openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem

5、創建⼀個v3.ext⽂件,目的是產生X509 v3證書,主要目的是指定subjectAltName選項:

  authorityKeyIdentifier=keyid,issuer
  basicConstraints=CA:FALSE
  keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
  subjectAltName = @alt_names
  [alt_names]
  DNS.1 = localhost
  IP.1 = "192.168.11.189"  
  IP.5 = "192.168.0.189"
  IP.2 = "132.232.229.60"
  IP.3 = "118.24.165.225"
  IP.4 = "129.28.108.238"

註意subjectAltName,這些都是可以信任的功能變數名稱或地址。

6、構建證書密鑰 server.key:openssl req -new -sha256 -nodes -out server.csr -newkey rsa:2048 -keyout server.key

7、用根證書rootCA產生自簽證書 server.crt:openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 500 -sha256 -extfile v3.ext

上面這個過程需要不斷重覆回答同樣的問題,很煩。可以用配置文件來一次性產生:

先構建一個ssl.cnf文件:

  [req]
  prompt = no
  default_bits = 4096
  default_md = sha256
  distinguished_name = dn
  x509_extensions = v3_req
  [dn]
  C=CN
  ST=GuangDong
  L=ShenZhen
  O=Bayakala
  OU=POS
  CN=www.bayakala.com
  emailAddress=admin@localhost
  [v3_req]
  keyUsage=keyEncipherment, dataEncipherment
  extendedKeyUsage=serverAuth
  subjectAltName=@alt_names
  [alt_names]
  DNS.1 = localhost
  IP.1 = "192.168.11.189"  
  IP.5 = "192.168.0.189"
  IP.2 = "132.232.229.60"
  IP.3 = "118.24.165.225"
  IP.4 = "129.28.108.238"

然後:openssl req -new -newkey rsa:2048 -sha1 -days 3650 -nodes -x509 -keyout server.key -out server.crt -config ssl.cnf

一個指令同時產生需要的server.crt,server.key。

除aubjectAltName外還要關註CN這個欄位,它就是我們經常會遇到系統提問:你確定信任“功能變數名稱”嗎?中這個功能變數名稱,也就是對外界開放的一個使用了數字證書的功能變數名稱。

把crt,key抄寫到main/resources目錄下,然後在gRPC伺服器配置證書:

trait gRPCServer {
  
  val serverCrtFile = new File(getClass.getClassLoader.getResource("server.crt").getPath)
  val serverKeyFile = new File(getClass.getClassLoader.getResource("server.key").getPath)

  def runServer(service: ServerServiceDefinition): Unit = {
    val server = NettyServerBuilder
      .forPort(50051)
      .addService(service)
      .useTransportSecurity(serverCrtFile,serverKeyFile)
      .build
      .start
    // make sure our server is stopped when jvm is shut down
    Runtime.getRuntime.addShutdownHook(new Thread() {
      override def run(): Unit = {
        server.shutdown()
        server.awaitTermination()
      }
    })
  }

}

啟動gRPC服務,運作正常。在看看客戶端代碼:

    val clientCrtFile = new File(getClass.getClassLoader.getResource("server.crt").getPath)
 //或者   val clientCrtFile = new File(getClass.getClassLoader.getResource("rootCA.pem").getPath)

//這樣也行 val clientCrtFile: InputStream = getClass.getClassLoader.getResourceAsStream("rootCA.pem")

    val sslContextBuilder = GrpcSslContexts.forClient().trustManager(clientCrtFile)

    //build connection channel
    val channel = NettyChannelBuilder
      .forAddress("192.168.11.189",50051)
      .negotiationType(NegotiationType.TLS)
      .sslContext(sslContextBuilder.build())
//      .overrideAuthority("192.168.1.3")
      .build()

測試連接,gRPC SSL/TLS成功!

現在開始瞭解一下https證書的配置使用方法吧。看了一下akka-http關於server端HTTPS設置的例子,證書是嵌在HttpsConnectionContext類型裡面的。還有就是akka-http使用的https證書格式只支持pkcs12,所以需要把上面用openssl產生的自簽名證書server.crt轉成server.p12。這個轉換又需要先產生證書鏈certificate-chain chain.pem:

1)產生certificate-chain:  cat server.crt rootCA.crt > chain.pem

2) server.crt轉換成server.p12: openssl pkcs12 -export -name servercrt -in chain.pem -inkey server.key -out server.p12

https server 測試代碼:

//#imports
import java.io.InputStream
import java.security.{ SecureRandom, KeyStore }
import javax.net.ssl.{ SSLContext, TrustManagerFactory, KeyManagerFactory }

import akka.actor.ActorSystem
import akka.http.scaladsl.server.{ Route, Directives }
import akka.http.scaladsl.{ ConnectionContext, HttpsConnectionContext, Http }
import akka.stream.ActorMaterializer
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives._

//#imports


object HttpsDemo extends App {

  implicit val httpSys = ActorSystem("httpSystem")
  implicit val httpMat = ActorMaterializer()
  implicit val httpEC = httpSys.dispatcher
  

    val password: Array[Char] = "123456".toCharArray // do not store passwords in code, read them from somewhere safe!

    val ks: KeyStore = KeyStore.getInstance("PKCS12")
    val keystore: InputStream = getClass.getClassLoader.getResourceAsStream("server.p12")
    ks.load(keystore, password)

    val keyManagerFactory: KeyManagerFactory = KeyManagerFactory.getInstance("SunX509")
    keyManagerFactory.init(ks, password)

    val tmf: TrustManagerFactory = TrustManagerFactory.getInstance("SunX509")
    tmf.init(ks)

    val sslContext: SSLContext = SSLContext.getInstance("TLS")
    sslContext.init(keyManagerFactory.getKeyManagers, tmf.getTrustManagers, new SecureRandom)
    val https: HttpsConnectionContext = ConnectionContext.https(sslContext)


  val route = get { complete("Hello world!") }

  val (port, host) = (50081,"192.168.11.189")

  val bindingFuture = Http().bindAndHandle(route,host,port,connectionContext = https)

  println(s"Https Server running at $host $port. Press any key to exit ...")

  scala.io.StdIn.readLine()


  bindingFuture.flatMap(_.unbind())
    .onComplete(_ => httpSys.terminate())

}

用safari連接https://192.168.11.189:50081/, 彈出視窗一堆廢話後還是成功連接上了。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 先做個自我介紹,我13年考上一所很爛專科民辦的學校,學的是生物專業,具體的學校名稱我就不說出來獻醜了。13年我就輟學了,我在那樣的學校,一年學費要1萬多,但是根本沒有人學習,我實在看不到希望,我就退學了。退學後我也迷茫,大專都沒有畢業,我真的不知道我能幹什麼,我在糾結著我能做什麼。所以輟學後我一段時 ...
  • JavaScript簡介 JavaScript 是互聯網上最流行的腳本語言,這門語言可用於 HTML 和 web,更可廣泛用於伺服器、PC、筆記本電腦、平板電腦和智能手機等設備。 JavaScript 是一種輕量級的編程語言。是可插入 HTML 頁面的編程代碼。JavaScript 插入 HTML ...
  • 什麼是跨域? 跨域是指一個域下的文檔或腳本試圖去請求另一個域下的資源,這裡跨域是廣義的。 其實我們通常所說的跨域是狹義的,是由瀏覽器同源策略限制的一類請求場景。 為什麼會跨域? 吶,說起跨域就不得不提一下同源策略,那什麼是同源策略呢? 同源策略(瀏覽器提供的一種安全的運行環境) 同源策略限制了從同一 ...
  • 首先!!!!這個問題應該是去面試前端會經常問到的問題!!! 如,下麵這個例子: 按照正常思維的話,這個.container容器分成了左右紅色和綠色兩個部分,但是運行之後卻裝不下這兩個子元素.left 和 .right。 效果如下圖所示: 想要解決這種現象有兩個辦法: 效果最終顯示: ...
  • Object構造函數和對象字面量都可以用來創建單個對象,但是在創建多個對象時,會產生大量重覆代碼. 1.工廠模式 工廠模式抽象了創建具體對象的過程.由於ECMAScript無法創建類,我們用函數來封裝 以特定介面創建對象 的細節. 2.構造函數模式 用來創建特定類型的對象,比如Object/Arr ...
  • 舉個慄子 問題描述 可以給人搭配嘻哈服或白領裝的程式。 簡單實現 代碼 測試結果 存在缺陷 如果需要增加“超人”裝扮,會導致需要修改“Person”類,違背了 開放 封閉原則 簡單實現進化版 代碼 測試結果 存在問題 現在如果要加超人裝扮,只要增加子類就可以了,但是這麼做雖然把“服裝”類和“人”類分 ...
  • Collection介面中的常用方法: * 所有的子類子介面都是具有的 * 集合的方法:增刪改查 * * public boolean add(E e);//添加元素 返回值表示是否添加成功 * public boolean remove(Object o);//刪除元素,返回值表示是否刪除成功 * ...
  • 文章首發: "進程知多少?" @[toc] Java 多線程系列文章第 1 篇 要講線程,一般都得講一講進程,進程是何方神聖呢?下麵來簡單介紹一下。 先通過任務管理器看看 Windows 系統下的進程。 從圖片來看,每一個進程都占有 CPU、記憶體、磁碟、網路等資源。 站在操作系統的角度,進程是分配資 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...