Google Code Prettify

2023年6月11日 星期日

web server (https)

現在的網站不只對外服務時一定會使用 https 通訊協定,公司內部也很少看到會用 http,底下說明怎麼為一個網站加上 TLS 需要的憑證。

  1. 程式
  2. @RestController
    public class HelloController {

    @GetMapping(value="/hello/{name}")
    public String hello(@PathVariable String name) {
    return "Hello " + name + "!";
    }
    }
    很簡單的 hello 程式,執行時只要在命令列中下 curl http://localhost:8080/hello/Steven 就會回覆 Hello Steven!
  3. 產生金鑰
  4. keytool -genkey -alias hello -keyalg RSA -keysize 4096 -validity 3650 -dname "CN=localhost,OU=Study,O=Home,L=Danshui,S=NewTaipei,C=Taiwan" -keypass changeit -keystore keystore.jks -storeType jks -storepass changeit
    
    JDK 中有附一個 keytool 的工具程式可以用來產生及管理金鑰,如上指令,產生了一個 RSA 的公私鑰,命名為 hello,放在命名為 keystore.jks 的 keystore 裡。 特別注意,CN 要與 web server 網址相同,表示這個憑證是要用在這台主機站台,storeType 選擇 jks 的話,這是 Java 特有,標準的方式是 PKCS#12,這個後面會再說明。 在下指令的目錄下可以找到指令產生的 keystore.jks 這個檔案,將它拷具到專案所在的根目錄。
  5. 修改 application.yml
  6. server:
    ssl:
    key-store: keystore.jks
    key-store-password: changeit
    key-alias: hello
    這樣執行時,這個站台會使用 keystore.jks 裡的 hello 金鑰為 https 做相關的加解密。
    啟動站台後,再執行以下指令:
    http://localhost:8080/hello/Steven
    
    因為沒有走 https,會得到以下訊息,表示 web server 現在提供的是 TLS 通訊協定的服務。
    Bad Request
    This combination of host and port requires TLS.
    
    改成如下指令,改走 https:
    https://localhost:8080/hello/Steven
    
    出現如下訊息,表示是自簽憑證,無法驗證其是否合法!
    curl: (60) SSL certificate problem: self signed certificate
    More details here: https://curl.se/docs/sslcerts.html
    
    curl failed to verify the legitimacy of the server and therefore could not
    establish a secure connection to it. To learn more about this situation and
    how to fix it, please visit the web page mentioned above.
    
    指令可以改成如下,先略過憑證的檢驗,就可以得到正確的結果:
    curl -k https://localhost:8080/hello/Steven
    
    這當然不是我們要的結果! 憑證必預被驗證其合法性!
  7. 驗證憑證
  8. 用以下指令將 hello 的公鑰匯出:
    keytool -export -file hello.crt -alias hello -rfc -keystore keystore.jsk -storePass changeit
    
    上面的 -rfc 參數表示匯出公鑰時採用 PEM 格式。接著重新下以下指令:
    curl --cacert hello.crt https://localhost:8080/hello/Steven
    
    在對 web server 進行 request 時,將公鑰帶過去,即可在 TLS 通訊協定下完成安全的交易。
  9. PKCS#12
  10. 以下列指令將 jks 的憑證轉換成 PKCS#12:
    keytool -importkeystore -srckeystore keystore.jks -destkeystore pkcs12.p12
    
    上面改變的是 keystore 裡的key,接下要將公鑰匯出,指令如下:
    openssl pkcs12 -in pkcs12.p12 -out hello.pem -nodes
    
    將 pkcs12.p12 拷具到專案的根目錄,並且修改 application.yml,如下:
    server:
    ssl:
    key-store: pkcs12.p12
    key-store-password: changeit
    key-alias: hello
    測試的指令如下:
    curl --cert hello.pem https://localhost:8080/hello/Steven