為了深入洞察用戶行為,企業通常會從小程序中收集小程序日志,分析用戶的設備信息、瀏覽歷史等關鍵數據,進而改善產品功能并優化用戶體驗。通過啟用阿里云日志服務(SLS)的Web Tracking功能,企業能自動將終端用戶的小程序日志收集到SLS,既提高了數據處理效率,又減輕了業務服務器的負擔。盡管便捷,但由于允許Logstore支持匿名寫入,如小程序中的配置信息泄露可能引致數據污染。為了降低該風險,推薦使用阿里云安全令牌服務(STS),為小程序端提供時間和權限受限的訪問令牌,從而增強數據上傳過程的安全性。本文將以用戶瀏覽行為日志收集為例,介紹如何利用SLS和STS為小程序構建安全、高效的小程序日志直傳服務。
背景信息
企業A開發的這款小程序為用戶提供了一個功能豐富、界面友好的在線平臺,旨在吸引用戶前來瀏覽、購買商品或服務。為了更好地理解用戶的需求、優化用戶體驗,并進一步提升小程序的轉化率,企業A認識到了對用戶行為進行深入分析的重要性。這種分析需要基于用戶在小程序上的實際操作行為,比如點擊、滑動、停留、搜索習慣以及購買行為等。因此,企業A的技術團隊決定采集小程序端日志,并將這些日志上傳到SLS進行更高效的數據分析和處理。
安全風險
為了減輕業務服務器的負擔并提高處理效率,該小程序被設計為允許用戶的日志數據直接上傳到SLS,避免了日志采集與上傳過程中經過業務服務器的中轉。
企業A計劃采取以下方案搭建小程序日志直傳服務:
然而,在以上方案中,允許小程序直接上傳日志到SLS的同時,由于SLS的Logstore開啟了支持匿名寫入的Web Tracking功能,企業將面臨以下風險:
數據污染風險:惡意用戶可能會上傳虛假或蓄意破壞的數據,影響數據質量和分析結果的準確性。
服務濫用風險:未受限的寫入訪問可能會被利用進行拒絕服務(DoS)攻擊,通過大量寫入請求耗盡資源。
解決方案
為了應對上述風險,企業在原有方案的基礎上增加臨時授權。通過這種方式,企業A能夠在確保數據直傳效率的同時,實現以下效果:
增強的身份驗證和授權:通過STS生成的具有時間限制的令牌,即便在短時間內泄露,也極大降低了安全風險。因為這些憑證很快就會失效,降低了被不當利用的可能性。
精細化權限控制:STS允許根據最小權限原則配置權限,僅授權小程序必需的訪問權限。這種精細化的權限控制方法限制了潛在泄露的影響范圍,防止了過度權限的風險。
企業A最終采取以下方案搭建小程序日志直傳服務:
方案部署
下面將以一個簡單的用戶瀏覽行為日志收集場景為例,引導您一步步使用SLS和STS為小程序部署小程序日志直傳服務。本方案部署的示例工程:sls-mini-tracking-sts.zip。
準備工作
在開始部署前,您需要先創建云資源。
創建一個日志服務Project和Logstore,用于存儲和分析從瀏覽器采集的日志。具體操作,請參見創建項目Project和創建Logstore。
參數
示例值
所屬地域
華東2(上海)
Project名稱
sls-webtracking-mini
Logstore名稱
web-tracking-logstore
創建一臺ECS實例作為業務服務器,用于生成臨時身份憑證。具體步驟,請參見創建ECS實例。
說明在實際部署時,您可以將調用STS服務的接口集成到自己的業務服務器的接口中,而無需創建該ECS實例。
參數
示例值
付費類型
按量付費
地域
華東2(上海)
公網 IP
分配公網 IPv4 地址
安全組
開放HTTP (TCP:80)端口
步驟一:創建RAM用戶
步驟二:授權RAM用戶授予調用AssumeRole接口
為RAM用戶添加AliyunSTSAssumeRoleAccess權限,使其可以通過扮演RAM角色來獲取臨時身份憑證。具體操作,請參見為RAM用戶授權。
步驟三:創建RAM角色
創建RAM用戶要扮演的RAM角色,例如命名為:sls-web-tracking
。具體操作,請參見創建可信實體為阿里云賬號的RAM角色。
步驟四:創建自定義權限策略
創建一個自定義權限策略,例如命名為:post-logs-policy
。其中在腳本編輯頁簽,請使用以下腳本替換配置框中的原有內容。具體操作,請參見通過腳本編輯模式創建自定義權限策略。
將以下腳本中的<Project名稱>
和<Logstore名稱>
替換為準備工作中創建的Project名稱和Logstore名稱。
該策略只能向指定的SLS Logstore上傳日志。您可根據實際需求配置更細粒度的授權策略,防止出現權限過大的風險。更多信息,請參見RAM自定義授權示例。
{
"Version":"1",
"Statement":[
{
"Effect":"Allow",
"Action":[
"log:PostLogStoreLogs"
],
"Resource":[
"acs:log:*:*:project/<Project名稱>/logstore/<Logstore名稱>"
]
}
]
}
步驟五:為RAM角色授予權限
為RAM角色sls-web-tracking
授予創建的自定義權限post-logs-policy
,以便被RAM用戶扮演時能獲取所需的權限。具體操作,請參見為RAM角色授權。
步驟六:在業務服務器獲取臨時身份憑證
在小程序中,通過在業務服務器集成STS SDK,實現一個獲取臨時STS身份憑證的接口。當這個接口(/get_sts_token
)通過HTTP GET方法被訪問時,它會生成一個臨時身份憑證,并將其返回給請求者。
在ECS實例上,使用Flask框架快速搭建小程序,實現一個獲取臨時STS身份憑證的接口的操作示例如下:
登錄ECS實例。并在ECS實例中安裝Python3。
配置RAM用戶的
ALIBABA_CLOUD_ACCESS_KEY_ID
和ALIBABA_CLOUD_ACCESS_KEY_SECRET
,操作步驟請參見在Linux、macOS和Windows系統配置環境變量。創建項目目錄,并切換到項目目錄。
mkdir my_web_sample cd my_web_sample
安裝依賴。
pip3 install Flask pip3 install attr pip3 install yarl pip3 install async_timeout pip3 install idna_ssl pip3 install attrs pip3 install aiosignal pip3 install charset_normalizer pip3 install alibabacloud_tea_openapi pip3 install alibabacloud_sts20150401 pip3 install alibabacloud_credentials
編寫后端代碼。
創建一個
main.py
文件。在這個文件中,添加以下Python代碼。
重要將代碼中的
<YOUR_ROLE_ARN>
替換為步驟三中創建的RAM角色sls-web-tracking
的ARN。將代碼中的
<YOUR_ROLE_SESSION_NAME>
設置為自定義的會話名稱,例如role_session_test
。import json from flask import Flask, render_template from alibabacloud_tea_openapi.models import Config from alibabacloud_sts20150401.client import Client as Sts20150401Client from alibabacloud_sts20150401 import models as sts_20150401_models from alibabacloud_credentials.client import Client as CredentialClient app = Flask(__name__) # 將<YOUR_ROLE_ARN>替換為RAM角色的ARN。 role_arn_for_oss_upload = '<YOUR_ROLE_ARN>' # 設置為STS服務的地域,例如cn-shanghai。 region_id = 'cn-shanghai' @app.route('/get_sts_token', methods=['GET']) def get_sts_token(): # 初始化 CredentialClient 時不指定參數,代表使用默認憑據鏈。 # 在本地運行程序時,可以通過環境變量 ALIBABA_CLOUD_ACCESS_KEY_ID、ALIBABA_CLOUD_ACCESS_KEY_SECRET 指定 AK; # 在 ECS\ECI\容器服務上運行時,可以通過環境變量 ALIBABA_CLOUD_ECS_METADATA 來指定綁定的實例節點角色,SDK 會自動換取 STS 臨時憑證。 config = Config(region_id=region_id, credential=CredentialClient()) sts_client = Sts20150401Client(config=config) assume_role_request = sts_20150401_models.AssumeRoleRequest( role_arn=role_arn_for_oss_upload, # 將<YOUR_ROLE_SESSION_NAME>設置為自定義的會話名稱。 role_session_name='<YOUR_ROLE_SESSION_NAME>' ) response = sts_client.assume_role(assume_role_request) token = json.dumps(response.body.credentials.to_map()) return token app.run(host="0.0.0.0", port=80)
啟動應用程序。
python3 main.py
在瀏覽器中訪問
http://<ECS實例公網IP地址>/get_sts_token
。成功返回示例如下:
步驟七:在小程序使用臨時身份憑證上傳日志到日志服務Logstore
小程序的開發流程和代碼構成,請參見支付寶文檔中心。本文檔的小程序客戶端代碼,基于支付寶小程序的Todo示例和日志服務的使用WebTracking JavaScript SDK的STS插件上傳日志,示例代碼的下載地址sls-mini-tracking-sts.zip。
在業務服務器配置了獲取STS臨時身份憑證的接口后,在小程序的app.js
文件中集成SLS的埋點SDK(@aliyun-sls/web-track-mini)和STS插件(@aliyun-sls/web-sts-plugin),實現實時監控用戶行為并上傳相關日志。
當創建埋點跟蹤器(tracker)實例時,它將自動請求之前部署的/get_sts_token
接口,以便獲取必要的臨時STS憑證。這種機制保證了用戶在小程序交互過程中,如登錄、瀏覽商品或提交訂單等活動的數據會被安全地傳輸至SLS。
下載小程序開發者工具。
創建和體驗Todo App 小程序。
安裝npm。
yum install npm
安裝項目依賴。
npm install --save @aliyun-sls/web-track-mini npm install --save @aliyun-sls/web-sts-plugin
修改Todo示例代碼,將用戶數據通過Webtracking上傳到Logstore。修改后的示例代碼sls-mini-tracking-sts.zip,修改的文件如下。
文件
修改代碼的說明
app.js
在
onLaunch
方法中調用了initSlsTracker
方法,當小程序啟動時會初始化SlsTracker。在
initSlsTracker
方法中定義日志服務的Project、Logstore等參數,參數說明參見webtracking參數名稱。stsOpt
配置和refreshSTSToken
函數用于動態獲取和更新阿里云的安全令牌服務(Security Token Service,簡稱 STS)的臨時訪問憑證。STS相關參數說明參見STS參數名稱。
mini.project.json
STS插件(@aliyun-sls/web-sts-plugin)包含ES6特性,在
mini.project.json
文件中設置編譯選項compileOptions.transpile
為true
,讓小程序的開發工具將 ES6 代碼轉換為ES5代碼,確保兼容性。todo.xml
<view class="todo-footer"> <add-button text="Add Todo" onClickMe="handleAddTodo"></add-button> </view>
定義了用戶界面底部的一個按鈕,界面詞為
Add Todo
,add-button
是自定義按鈕。onClickMe="handleAddTodo"
代表按鈕被單擊時調用todo.js
中的方法handleAddTodo
。todo.js
handleAddTodo()
是事件處理函數。當用戶在頁面上添加新的待辦事項時,這個函數被觸發。它依次執行兩個操作:調用
this.addTodo()
方法添加一個新的待辦事項。調用
this.onAddTodoButtonClick()
發送關于用戶點擊添加按鈕的日志消息。
addTodo()
調用小程序的my.navigateTo
函數,實現從當前頁面跳轉到應用內/pages/add-todo/add-todo
路徑對應的頁面。onAddTodoButtonClick()
調用app.js
中定義的SlsTracker
的send
方法發送一條日志事件,這條日志的內容為eventType: 'addtodo_click'
。
add-todo.js
在
add
方法中創建一個新對象
newTodo
,代表一個待辦事項,newTodo
包括兩個屬性:text
:待辦事項的內容,這里從this.data.inputValue
獲取,意味著它可能是來自用戶輸入。completed
:表示這個待辦事項是否已完成,初始化為false
,意味著新建的待辦事項默認狀態是未完成。
調用
app.js
中定義的SlsTracker
的send
方法發送一條日志事件,這條日志的內容為eventType: 'add_todo' todoText: newTodo.text
add-button.js
自定義按鈕組件。
onClickMe
方法首先檢查this.props.onClickMe
是否為一個函數類型。只有當確定this.props.onClickMe
是函數時,才執行調用。配置小程序
app.js
文件的參數。// app.js import SlsTracker from '@aliyun-sls/web-track-mini'; import createStsPlugin from '@aliyun-sls/web-sts-plugin'; App({ todos: [ { text: 'Learning Javascript', completed: true }, { text: 'Learning ES2016', completed: true }, { text: 'Learning 支付寶小程序', completed: false }, ], userInfo: null, tracker: null, onLaunch: function() { // 在應用啟動時進行初始化 this.initSlsTracker(); }, initSlsTracker: function() { const opts = { host: 'cn-shanghai.log.aliyuncs.com', // 替換為你的服務入口 project: '${project}', // 替換為你的 Project 名稱 logstore: '${Logstore}', // 替換為你的 Logstore 名稱 time: 10, count: 10, topic: 'topic', source: 'source', tags: { tags: 'tags', }, }; const stsOpt = { accessKeyId: '', accessKeySecret: '', securityToken: '', refreshSTSToken: () => new Promise((resolve, reject) => { my.request({ url: 'http://${ECS實例的公網IP}}/get_sts_token', // 替換為后端 STS Token 提供服務的真實地址 method: 'GET', success: (res) => { if (res.statusCode === 200) { let credential; // 檢查返回的數據類型確保是字符串,若不是字符串則可能已是對象 if (typeof res.data === "string") { //解析為JSON對象 credential = JSON.parse(res.data); } else { // 直接使用對象 credential = res.data; } stsOpt.accessKeyId = credential.AccessKeyId; stsOpt.accessKeySecret = credential.AccessKeySecret; stsOpt.securityToken = credential.SecurityToken; resolve(credential); } else { reject(new Error('Failed to refresh STS token with status code: ' + res.statusCode)); } }, fail: (err) => { reject(new Error('Failed to refresh STS token', err)); }, }); }), }; const tracker = new SlsTracker(opts); const stsPlugin = createStsPlugin(stsOpt); tracker.useStsPlugin(stsPlugin); // 以單條日志上傳為例,只要啟動小程序,就會發送一條日志。 // tracker.send({ // eventType:'view_product', // productName: 'Tablet', // price: 500 // }); this.tracker = tracker; }, });
關于
opts
和stsOpt
的參數說明,請參見使用WebTracking JavaScript SDK的STS插件上傳日志。將代碼中的
${project}
和${logstore}
替換為準備工作中創建的Project名稱和Logstore名稱。將代碼中的
<ECS實例公網IP地址>
替換為準備工作中創建的ECS實例的公網IP地址。如何查看公網IP地址,請參見查看IP地址。
運行客戶端示例代碼。在開發者工具,單擊頁面右上角的編譯。在右側小程序預覽頁面,單擊小程序的Todo頁面的Add Todo按鈕或輸入Todo項時,小程序會直接向日志服務的Logstore上傳日志,無需經過服務器。
完成及清理
方案驗證
完成以上操作后,您可以通過預覽方式查看數據是否已上傳到SLS。
在消費預覽面板,查看成功上傳的日志。
清理資源
在本方案中,您創建了1臺ECS實例、1個SLS Project和Logstore、1個RAM用戶和1個RAM角色。測試完方案后,您可以參考以下規則處理對應產品的資源,避免繼續產生費用或產生安全風險。
釋放ECS實例。具體操作,請參見釋放實例。
先刪除Logstore,再刪除Project。具體操作,請參見管理Logstore和管理Project。
后續操作
本文在開發者工具中對示例程序進行本地調試,如果需要正式上線小程序,必須完成以下步驟:
創建開發者賬號,創建小程序,將小程序提交審核等,具體參見開發者賬號注冊。
在開發者工具中忽略域名合法性,檢查便于調試,步驟請參見接入準備。
在支付寶控制臺中配置以下的域名白名單。
添加日志服務的服務器域名(request合法域名)。格式為
https://${project}.${host}
,project
是日志服務的Project名稱,host
是Project域名,本文示例為sls-webtracking-mini.cn-shanghai.log.aliyuncs.com
,操作步驟參見服務器域名白名單。添加小程序后端服務器的域名,本文示例只有小程序客戶端代碼,正式上線小程序還需要開發服務端代碼。服務器域名白名單只支持HTTPS協議,配置HTTPS協議需要在服務器部署SSL證書,步驟請參見SSL證書安裝說明。本文示例在開發者工具中忽略域名合法性,小程序正式上線前必須配置域名檢查。
將終端用戶的小程序日志收集到SLS后: