UDRIVE 悠駕特斯拉租賃實踐 Tesla Fleet API:經驗分享與技術指南|USPACE


Tesla 在 2023 年 Q4 官方終於釋出 API,我們 UDRIVE 悠駕特斯拉租賃在整合Tesla Fleet API 過程中,踩了一些小雷。本文旨在分享我們的經驗,特別是那些在官方文件中未提及的寶貴經驗,以助於未來有意整合此 API 的公司或開發者。

官方文件:Tesla Fleet API 官方文件

Tesla Developer 後台管理列表

概覽

FleetAPI 是一個 RESTful 資料(代表性狀態資料)和指令組成的服務,提供 Tesla 車輛和能源裝置的存取權限。

合作夥伴可以和他們擁有的裝置或者客戶授權給他們的裝置進行互動。

一、開發者帳號申請與設定

(1) 設定一個第三方帳號 https://developer.tesla.com 注意建立第三方帳號可能被自動拒絕:
– 無效的網域
– 應用程式名稱已存在
– [可能已經被更新] 當時我們發票設定三聯單時無法通過,錯誤訊息未標示清楚。*備註:申請 Redirect URI 時,請記得必須包含 /:path 例如:uspace.city/call_back,當時我們有寫信給官方,目前已經看到官方後台有清楚提示(Tesla 看起來也是密集地在改版 XD)

(2) 完成註冊流程:
a. 產生公私鑰,用於簽署指令並部署在網站的 /.well-known 
b. 產生夥伴驗證 token
c. POST /api/1/partner_accounts

(3) 由客戶發送並驗證授權權限,產生第三方 token

二、Client Side 實作經驗

其實特斯拉 Fleet API 在實作這段授權就類似 Meta, Google 等其他 OAuth 機制,流程上就是提供一個特殊網址給車主去登入取得相關資料授權 > 夾帶參數返回設定的 Redirect URI > 在指定網址做額外自身服務 API 處理

*授權時,可以利用 redirect_uri 這參數去夾帶自定義參數,並且在返回到 App 指定之 Redirect URI 後繼續在自己的服務端去做資料的媒合

三、Server Side 實作經驗

# 完成註冊流程:

⚠️ 注意,如果您取得的 Token 包含 %, $ 等特殊字元,請記得使用單引號或謹慎處理,否則將會無法驗證。

使用 macOS 我們是按照以下實踐:

# 1. 安裝 OpenSSL
$ brew install openssl

# 2. 建立私鑰
$ openssl ecparam -name prime256v1 -genkey -noout -out private.pem

# 3. 建立公鑰
$ openssl ec -in private.pem -pubout -out public.pem

# 4-1. 將公私鑰放到 /Users/<YOUR_USERNAME> 目錄
$ cp public.pem ~/
$ cp private.pem ~/
# 4-2. 將公鑰改名為 com.tesla.3p.public-key.pem
$ mv public.pem com.tesla.3p.public-key.pem
# 4-3. 將公鑰放到網站目錄 /.well-know/ 底下,請自行變更為自己的資料
$ scp <LOCAL_FILE_PATH> <USERNAME>@<SERVER_IP>:<REMOTE_PATH>
#### 範例使用 scp 上傳主機
$ scp ~/com.tesla.3p.public-key.pem [email protected]:/home/username/

# 5. 使用 CURL 或其他工具取得 Partner authentication token
$ CLIENT_ID=<command to obtain your client_id>
CLIENT_SECRET=<secure command to obtain your client_secret>
AUDIENCE="https://fleet-api.prd.na.vn.cloud.tesla.com"
curl --request POST \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=client_credentials' \
  --data-urlencode "client_id=$CLIENT_ID" \
  --data-urlencode "client_secret=$CLIENT_SECRET" \
  --data-urlencode 'scope=openid vehicle_device_data vehicle_cmds vehicle_charging_cmds' \
  --data-urlencode "audience=$AUDIENCE" \
  'https://auth.tesla.com/oauth2/v3/token'

# Tesla Fleet API 與 SSL/TLS 握手: 一個 curl 使用案例

結論:目前 Tesla Fleet API 支援的 TSL 版本是 1.3,對於某些技術環境所使用的套件,例如 openssl 可能在未指定版本的狀態下會是低於 1.3 的做法,導致 403 報錯

  • 解法:使用特定參數,如 --tlsv1.3 等指定版本做法
當時經驗與問題發現

我們在嘗試使用存取 Tesla API 時,發現在不同的環境下,對 Tesla API 的存取行為不一致。例如,在本地環境存取正常,但在伺服器上則返回 403 錯誤。這提示了環境與版本差異可能對 SSL/TLS 握手過程有重要影響。

在伺服器環境下執行下面指令遭遇 403 拒絕

CLIENT_ID="client-id"
CLIENT_SECRET="client-secret"
AUDIENCE="https://fleet-api.prd.na.vn.cloud.tesla.com"
curl --request POST \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode 'grant_type=client_credentials' \
    --data-urlencode "client_id=$CLIENT_ID" \
    --data-urlencode "client_secret=$CLIENT_SECRET" \
    --data-urlencode 'scope=openid vehicle_device_data vehicle_cmds vehicle_charging_cmds' \
    --data-urlencode "audience=$AUDIENCE" \
    'https://auth.tesla.com/oauth2/v3/token'

額外補充:嘗試理解 SSL/TLS 握手流程分析問題點|以 OpenSSL 為例

🎯 預設 TLS 握手

(1) Client Hello:用戶端向伺服器發送訊息,包含支援的 TLS 版本,密碼套件列表和 client random。

$ curl --version 
$ openssl ciphers -v
$ curl -v --tlsv1.3 https://example.com
$ openssl s_client -connect example.com:443 -tls1_3

(2) Server Hello:伺服器回覆用戶端,發送 SSL 憑證,選擇的密碼套件和 server random。

$ openssl s_client -connect auth.tesla.com:443
# 尋找 "Cipher is" 表示伺服器選擇的套件

(3) 身份驗證:用戶端利用伺服器的 SSL 憑證進行驗證。
(4) 預主密鑰:用戶端發送一串隨機位元組,即 Premaster Secret。
(5) 建立工作階段金鑰:使用 client random、server random 和預主密鑰建立。
(6) 完成握手:雙方發送「已完成」消息,開始加密通訊。

🎯 Diffie-Hellman 握手

(1) Client Hello:同上述。
(2) Server Hello:
– 伺服器選擇 DH 或 ECDHE 密碼套件。
– 發送 SSL 憑證、數位簽章、server random,Diffie-Hellman 參數。
# 連接到伺服器並取得 SSL/TLS 證書資訊 openssl s_client -connect [伺服器地址]:443 -showcerts
(3) 用戶端和伺服器計算預主密鑰:使用交換的 DH 參數。
(4) 建立工作階段金鑰:同上述。

🎯 TLS 1.3 握手

(1) Client Hello:發送通訊協定版本,client random,密碼套件列表。
(2) Server Hello 和完成:
– 發送 SSL 憑證,數位簽章,server random。
– 選擇密碼套件。
(3) 用戶端完成:驗證簽章和憑證,產生金鑰,發送完成訊息
(4) 伺服器就緒:伺服器確認握手成功,開始加密通訊。

🎯 關鍵學習點

(1) TLS 版本與密碼套件:不同的 TLS 版本和密碼套件可能導致不同的握手結果。特定環境下(如 Tesla API),這可能導致存取權限被拒絕。
(2) 除錯策略:使用 curl -v 可以查看詳細的連線日誌,有助於確定問題所在。
(3) 解決方案的多樣性:更改 TLS 版本或密碼套件可以解決某些特定問題,例如使用 --tlsv1.3 或 --ciphers 'DEFAULT:!DH'
(4) SSL/TLS 握手的複雜性:理解 TLS 握手過程中的每個步驟對於解決問題至關重要。特別是在處理特定於應用程序的連接問題時,如本例中的 Tesla API。
(5) 數位簽章與身份驗證:SSL/TLS 握手過程中,數位簽章的驗證是保證伺服器身份真實性的重要步驟。
(6) Diffie-Hellman 握手:這種類型的握手提供了前向保密性,但與標準 RSA 握手相比,其過程更為複雜。
(7) TLS 1.3 的變化:TLS 1.3 減少了握手過程的往返次數,並刪除了許多不安全的密碼套件,導致與舊版本的行為有所不同。


發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *