secure-network.md 9.6 KB
Newer Older
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
1 2 3
**云端一体安全网络**

> HBuilderX 3.6.2+ 支持
d-u-a's avatar
d-u-a 已提交
4

W
wanganxp 已提交
5
## 简介
d-u-a's avatar
d-u-a 已提交
6

W
wanganxp 已提交
7
网络安全的问题很多:
d-u-a's avatar
d-u-a 已提交
8

W
wanganxp 已提交
9 10
1. 客户端受信。因为过去采用无状态网络通过接口交换数据,客户端的真实性很难保证。
2. 网络抓包,即便是https的请求也会被抓包。
d-u-a's avatar
d-u-a 已提交
11

W
wanganxp 已提交
12
当攻击者了解了你的服务器接收什么样的数据时,就可以冒名客户端,提交假数据来攻击你的服务器。
d-u-a's avatar
d-u-a 已提交
13

W
wanganxp 已提交
14
尤其当你的业务中涉及促销、返佣、激励视频等场景,非常容易被刷。褥羊毛已经是一个非常成熟的灰产。
d-u-a's avatar
d-u-a 已提交
15

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
16
DCloud面向开发者同时提供了端引擎`uni-app` 和 云引擎`uniCloud`,其实可以提供云端一体的安全网络的能力。
d-u-a's avatar
d-u-a 已提交
17

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
18
`uni-app` 连接 `uniCloud` 时,可以选择是否启动安全网络。它通过高安全的保护机制,防止客户端伪造和通信内容抓包。
d-u-a's avatar
d-u-a 已提交
19

W
wanganxp 已提交
20
注意:安全网络不支持web平台,只支持微信小程序和App。并且App的安全级别更高。
d-u-a's avatar
d-u-a 已提交
21

W
wanganxp 已提交
22
**平台差异说明**
d-u-a's avatar
d-u-a 已提交
23

W
wanganxp 已提交
24 25
|App|微信小程序|
|:-:|:-:|
雪洛's avatar
雪洛 已提交
26
|3.6.6+|3.6.6+|
d-u-a's avatar
d-u-a 已提交
27

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
28 29
## 准备工作

雪洛's avatar
雪洛 已提交
30
### 微信小程序@mp-weixin
d-u-a's avatar
d-u-a 已提交
31

雪洛's avatar
雪洛 已提交
32
安全网络在微信小程序上的实现,依赖了微信提供的一些用户级的凭据。所以需要下载`uni-id-pages``uni-open-bridge`,并在app.vue里初始化。
d-u-a's avatar
d-u-a 已提交
33

雪洛's avatar
雪洛 已提交
34 35 36 37 38 39 40 41 42
1.[开发者中心](https://dev.dcloud.net.cn/)`应用详情 --> 【名称待定】`内填写微信小程序的appId。一个应用只能有一个发行配置,但是可以有多个开发配置

  【图片待补充】
  
2. 在uniCloud控制台关联允许发送安全网络请求的应用

  【图片待补充】

3. 工程中导入uni-id-pages
d-u-a's avatar
d-u-a 已提交
43

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
44 45
- `uni-id` [文档](uni-id-summary.md#save-user-token)
- `uni-id-co` [插件下载地址](https://ext.dcloud.net.cn/plugin?id=8577)
d-u-a's avatar
d-u-a 已提交
46

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
47
`uni-id-pages`这个插件是云端一体的登录插件,其实安全网络只需要其中的`uni-id-co`云对象。插件中前端登录页面是否使用由开发者自己根据业务决定。
d-u-a's avatar
d-u-a 已提交
48

雪洛's avatar
雪洛 已提交
49
4. 工程中导入uni-open-bridge插件
d-u-a's avatar
d-u-a 已提交
50

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
51
安全网络在微信小程序上依赖了微信的 `access_token``session_key``encrypt_key`等凭据。这些凭据需要`uni-open-bridge`统一接管。
d-u-a's avatar
d-u-a 已提交
52

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
53 54
- `uni-open-bridge` [文档](https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge.html)
- `uni-open-bridge` [插件下载地址](https://ext.dcloud.net.cn/plugin?id=9002)
d-u-a's avatar
d-u-a 已提交
55

雪洛's avatar
雪洛 已提交
56
5. 配置uni-id和uni-open-bridge
d-u-a's avatar
d-u-a 已提交
57

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
登陆微信公众平台[https://mp.weixin.qq.com/](https://mp.weixin.qq.com/),获取微信小程序的固定凭据 `appid``secret`,配置到 uni-id-config

```json
// uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json
{
  "dcloudAppid": "__UNI__xxxxxx", // 在项目的 manifest.json 
  "mp-weixin": {
    "tokenExpiresIn": 259200,
    "oauth": {
      "weixin": {
        "appid": "", // 微信公众平台申请的小程序 appid
        "appsecret": "" // 微信公众平台申请的小程序 secret
      }
    }
  }
}
```

配置 `uni-open-bridge` 定时任务,定时从微信服务器获取 [access_token](/uniCloud/uni-open-bridge.html#access_token) 并保存到Redis或数据库

```json
// uniCloud/cloudfunctions/common/uni-config-center/uni-open-bridge/config.json
{
  "schedule": {
    "__UNI__xxxxxx": { // dcloudAppid, 需要和 `uni-config-center` uni-id中的配置一致
      "enable": true, // 任务全局开关,优先级最高
      "weixin-mp": { // 平台,目前仅支持 微信小程序、微信 H5,详情参见 https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge#platform
        "enable": true, // 当前平台任务开关
        "tasks": ["accessToken"] // 要执行的任务,微信小程序支持 accessToken
      }
    }
  },
  "ipWhiteList": ["0.0.0.0"] // 用于 URL化后 http 调用的服务器IP白名单,即指定ip的服务器才可以访问URL化后的`uni-open-bridge云对象
}
```

W
测试  
wanganxp 已提交
94
注意:拷贝此文件内容时需要移除 `注释`。标准json不支持注释。在HBuilderX中可用多选`//`来批量移除注释。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
95

雪洛's avatar
雪洛 已提交
96
如果项目之前已经使用过uni-id-pages和uni-open-bridge,则上述步骤可省略。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
97

雪洛's avatar
雪洛 已提交
98
6. 在应用的生命周期 `onLaunch` 中检查微信登陆状态,如果过期需要登陆
d-u-a's avatar
d-u-a 已提交
99

100
注意: [uni.checkSession](https://uniapp.dcloud.net.cn/api/plugins/login.html#uni-checksession) 有调用次数限制警告,一个 `pv` 可调用 `2`
d-u-a's avatar
d-u-a 已提交
101

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
102
App.vue页面需要补充如下代码:
d-u-a's avatar
d-u-a 已提交
103 104 105
```js
<script>
  function checkUserSession() {
d-u-a's avatar
d-u-a 已提交
106
    uni.checkSession({
d-u-a's avatar
d-u-a 已提交
107
      fail: (err) => {
d-u-a's avatar
d-u-a 已提交
108
        uni.login({
d-u-a's avatar
d-u-a 已提交
109 110 111 112 113 114 115 116 117 118 119 120
          success: async ({ code }) => {
            const uniIdCo = uniCloud.importObject('uni-id-co') // uniCloud云对象 uni-id-co
            await uniIdCo.loginByWeixin({ code })
          }
        })
      }
    })
  }

  export default {
    onLaunch: function() {
      console.log('App Launch')
d-u-a's avatar
d-u-a 已提交
121
      // #ifdef MP-WEIXIN
d-u-a's avatar
d-u-a 已提交
122
      checkUserSession();
d-u-a's avatar
d-u-a 已提交
123
      // #endif
d-u-a's avatar
d-u-a 已提交
124 125 126 127
    }
  }
</script>
```
雪洛's avatar
雪洛 已提交
128 129 130 131 132 133 134 135 136 137
  
7. 在项目根目录manifest.json文件内为微信小程序平台开启安全网络模块
  
  【图片待补充】

### App@app

App平台安全网络需使用[自定义基座](../tutorial/run/run-app.md#customplayground),App端安全网络不依赖于登录逻辑。

1.[开发者中心](https://dev.dcloud.net.cn/)`应用详情 --> 证书管理`内填写安卓应用的包名、签名和iOS应用的bundleId。一个应用只能有一个发行证书配置,但是可以有多个开发证书配置
d-u-a's avatar
d-u-a 已提交
138

雪洛's avatar
雪洛 已提交
139
  【图片待补充】
d-u-a's avatar
d-u-a 已提交
140

雪洛's avatar
雪洛 已提交
141 142 143 144 145 146 147
2. 在uniCloud控制台关联允许发送安全网络请求的应用

  【图片待补充】
  
3. 在项目根目录manifest.json文件内为app平台开启安全网络模块

  【图片待补充】
雪洛's avatar
雪洛 已提交
148 149 150 151 152 153 154

4. 创建集合`opendb-app-client-key`用于保存发放给客户端的密钥对

  - 切勿删除或修改此集合内容,否则会导致部分客户端不能发送安全网络请求(重新安装客户端或清除客户端数据后才能正常使用)
  - 如果服务空间开通了redis会在redis内存储一份客户端密钥对以加速安全网络请求的处理,所使用的键为`unicloud:encryption:app-client-key:{appId}:{deviceId}:string`

5. 通过上传schema触发一次clientDB云函数的更新
雪洛's avatar
雪洛 已提交
155
  
W
wanganxp 已提交
156
## 调用方式
d-u-a's avatar
d-u-a 已提交
157

雪洛's avatar
雪洛 已提交
158
准备工作完成后,在uni-app客户端调用uniCloud服务器时,可以通过参数来声明这次请求走安全网络,对传输数据加密。
d-u-a's avatar
d-u-a 已提交
159

雪洛's avatar
雪洛 已提交
160
### 云函数
d-u-a's avatar
d-u-a 已提交
161

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
162
客户端通过callFunction调用云函数时,加入secretType参数。
W
wanganxp 已提交
163 164 165 166 167 168
```js
uniCloud.callFunction({
  name: 'collection',
  data: {
    name: 'user'
  },
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
169
  secretType: 'both' //both指上下行数据都加密,具体见下
W
wanganxp 已提交
170 171
})
```
d-u-a's avatar
d-u-a 已提交
172

雪洛's avatar
雪洛 已提交
173
### 云对象
W
wanganxp 已提交
174

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
175
客户端通过importObject调用云对象时,通过secretMethods参数来配置每个方法调用时是否加密。
W
wanganxp 已提交
176 177 178

```js
uniCloud.importObject('object-name', {
179
  secretMethods: {'login':'both'} // 支持配置所有方法设置加密参见下面的 secretMethods 说明
W
wanganxp 已提交
180 181 182
})
```

雪洛's avatar
雪洛 已提交
183
### clientDB
184 185

暂不支持
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
186 187 188 189 190 191 192 193 194 195 196 197

**secretType 属性说明**

|值			|描述												|
|:-:		|:-:												|
|none		|不加密,默认值										|
|request	|只加密客户端请求时的上行数据,服务器下发数据不加密	|
|response	|客户端请求时不加密数据,只加密服务器下发的数据		|
|both		|客户端和服务器上行下行数据都加密数据				|

**secretMethods 属性说明**

198 199 200 201 202 203
`secretMethods` 是云对象中指定需要加密的方法名。

- 对所有方法设置加密,例如 `secretMethods: {'*':'both'}`
- 对每个方法配置加密,例如 `secretMethods: {'login':'both'}`,指定 `login` 方法的 `secretType` 为 both

方法级配置优先级最高,例如 `secretMethods: {'*':'response', 'login':'both'}`,login 的 both 覆盖了 `'*':'response'`
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
204

雪洛's avatar
雪洛 已提交
205 206 207 208
**注意**

- 微信小程序安全网络依赖于登录逻辑,因此在客户端检测到发送安全网络请求时用户未登录时会自动调用uni-id-co的loginByWeixin接口

209 210
## 服务器端

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
211
虽然uni-app客户端和uniCloud云端通信是加密的,但对于开发者而言过程是透明的。
212

雪洛's avatar
雪洛 已提交
213
**不管是客户端接收云端数据、还是云端接受客户端数据,开发者的代码拿到的数据都是解密后的数据。**
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
214 215 216

但云端有一个注意事项:为了避免客户端伪造`secretType`获取服务器敏感数据,应以服务器端为准,如果客户端携带的 `secretType` 不符合要求应拒绝响应数据。示例代码如下

雪洛's avatar
雪洛 已提交
217
### 云函数中验证secretType
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
218 219

在云函数的context中有secretType。
220 221 222 223 224 225 226 227 228 229 230 231

```js
exports.main = async (event, context) => {
  const secretType = context.secretType
  // secretType 是客户端调用 uniCloud.callFunction 传递的参数 secretType

  if (secretType !== 'both' || secretType !== 'response') {
    return null
  }
}
```

雪洛's avatar
雪洛 已提交
232
### 云对象中验证secretType
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
233 234

在云对象的this中有secretType。
235 236 237 238 239 240 241

```js
module.exports = {
  async _before() {
    const methodName = this.getMethodName()
    const clientInfo = this.getClientInfo()
    const secretType = clientInfo.secretType
d-u-a's avatar
d-u-a 已提交
242
    // methodName 是客户端调用的方法名
243 244
    // secretType 是客户端调用 uniCloud.importObject 传递的参数 secretMethods

雪洛's avatar
雪洛 已提交
245
    if (methodName === 'reward' && (secretType !== 'both' || secretType !== 'response')) {
246 247 248 249 250 251
      throw new Error('secretType invalid')
    }
  }
}
```

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
252
## 错误码
W
wanganxp 已提交
253

雪洛's avatar
雪洛 已提交
254 255 256 257 258 259 260
|错误码									|说明											|平台				|
|---										|---											|---				|
|ACCOUNT_NOT_EXISTS			|用户账号不存在						|微信小程序	|
|OPENID_NOT_FOUND				|用户表记录内openid未找到	|微信小程序	|
|GET_ENCRYPT_KEY_FAILED	|获取加密key失败					|微信小程序	|

微信小程序加解密时还会使用uni-id-common的checkToken方法,相关错误码参考:[uni-id错误码](uni-id-summary.md#errcode)
261

W
wanganxp 已提交
262 263 264
## 小贴士

1. 安全是相对的,没有绝对的安全。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
265
2. 安全是有代价的,加密的数据越庞大,加密和解密的耗时越长。