333
schangxiang@126.com
2025-09-19 18966e02fb573c7e2bb0c6426ed792b38b910940
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
# egg-security
 
egg 内置的安全插件
 
[![NPM version][npm-image]][npm-url]
[![build status][travis-image]][travis-url]
[![Test coverage][codecov-image]][codecov-url]
[![David deps][david-image]][david-url]
[![Known Vulnerabilities][snyk-image]][snyk-url]
[![npm download][download-image]][download-url]
 
[npm-image]: https://img.shields.io/npm/v/egg-security.svg?style=flat-square
[npm-url]: https://npmjs.org/package/egg-security
[travis-image]: https://img.shields.io/travis/eggjs/egg-security.svg?style=flat-square
[travis-url]: https://travis-ci.org/eggjs/egg-security
[codecov-image]: https://codecov.io/gh/eggjs/egg-security/branch/master/graph/badge.svg
[codecov-url]: https://codecov.io/gh/eggjs/egg-security
[david-image]: https://img.shields.io/david/eggjs/egg-security.svg?style=flat-square
[david-url]: https://david-dm.org/eggjs/egg-security
[snyk-image]: https://snyk.io/test/npm/egg-security/badge.svg?style=flat-square
[snyk-url]: https://snyk.io/test/npm/egg-security
[download-image]: https://img.shields.io/npm/dm/egg-security.svg?style=flat-square
[download-url]: https://npmjs.org/package/egg-security
 
## 使用方式
 
egg 默认开启此插件,所以无需配置。
 
修改 `config/config.js` 文件修改配置
 
```js
exports.security = {
  xframe: {
    value: 'SAMEORIGIN',
  },
};
```
 
### 关闭安全防范
 
如果你想关闭其中一些安全防范,直接设置该项的 `enable` 属性为 false 即可,如关闭 xfame 防范:
 
```js
exports.security = {
  xframe: {
    enable: false,
  },
};
```
 
### match 和 ignore
 
如果只想开启针对某一路径,则配置 match 选项,例如只针对 `/example` 开启 csp
 
```js
exports.security = {
  csp: {
    match: '/example',
    policy: {
      //...
    },
  },
};
 
```
 
如果需要针对某一路径忽略某安全选项,则配置 ignore 选项,例如针对 `/example` 关闭 xframe,以便合作商户能够嵌入我们的页面:
 
```js
exports.security = {
  csp: {
    ignore: '/example',
    xframe: {
      //...
    },
  },
};
 
```
 
__注意:如果存在 match 则忽略 ignore。__
 
## API
 
### ctx.isSafeDomain(domain)
 
是否为安全域名。安全域名在配置中配置,见 `ctx.redirect` 部分
 
## 接口限制
 
### csrf
 
__使用__
 
* `ctx.csrf` 获取 csrf token
 
一般在 POST 表单时使用。
 
页面渲染时,将 `ctx.csrf` 作为 form 隐藏域或 query string 渲染在页面上。(`_csrf` 作为 key)
 
在提交表单时,带上 token 即可。
 
#### 通过formData上传时使用csrf
 
浏览器端 html 代码:
 
```html
<form method="POST" action="/upload?_csrf={{ ctx.csrf | safe }}" enctype="multipart/form-data">
  title: <input name="title" />
  file: <input name="file" type="file" />
  <button type="submit">上传</button>
</form>
```
 
### ctoken
 
ajax 防跨站攻击。
 
__使用__
 
在 ajax 请求时,以 `ctoken` 为 name 带上 ctoken 即可。
 
ctoken 从 cookie 中获取
 
__安全开发者约定__
 
- `ctx.ctoken` 获取 ctoken 的逻辑。使用者不要调用,安全插件内部使用。
- `ctx.setCTOKEN()` 设置 ctoken 的逻辑。使用者不要调用,安全插件内部使用。
- `ctx.assertCTOKEN()` ctoken 校验逻辑。使用者不要调用,安全插件内部使用。
- `ctx.setCTOKEN()`会将cookie设置到主域名下,主要考虑主域名下其他子域名对应的应用之间的互相调用。例如 A.xx.com 域种了 ctoken,会设置cookie到xx.com域上,在 B.xx.com 域的时候可以利用 ctoken 去请求,在 A 域 jsonp 请求 B 域的时候,B 域也可以验证 ctoken。
 
可拓展实现。例如 ctoken token 存在什么 cookie,存什么字段等,都可以通过以上两个接口拓展。
 
 
### safe redirect
 
* `ctx.redirect(url)` 如果不在配置的白名单内,则禁止
* `ctx.unsafeRedirect(url)` 不建议使用
 
安全方案覆盖了默认的`ctx.redirect`方法,所有的跳转均会经过安全域名的判断。
 
用户如果使用`ctx.redirect`方法,需要在应用的配置文件中做如下配置:
 
```js
exports.security = {
  domainWhiteList:['.domain.com'],  // 安全白名单,以.开头
};
```
 
若用户没有配置 `domainWhiteList` 或者 `domainWhiteList` 数组内为空,则默认会对所有跳转请求放行,即等同于`ctx.unsafeRedirect(url)`。同时域名和 url 检查时不区分大小写。
 
### jsonp
 
使用 [jsonp-body](https://github.com/node-modules/jsonp-body),在 egg context 中实现,并不再 egg-security 中。
 
防御内容:
 
* callback函数名词最长50个字符限制
* callback函数名只允许"[","]","a-zA-Z0123456789_", "$" ".",防止一般的 xss,utf-7 xss等攻击
 
可定义配置:
 
* callback 默认 `_callback`,可以改名
* limit - 函数名 length 限制,默认 50
 
## helper
 
### .escape()
 
对字符串进行 xss 过滤,安全性最高的过滤方式。
 
```js
const str = '><script>alert("abc") </script><';
console.log(ctx.helper.escape(str));
// => &gt;&lt;script&gt;alert(&quot;abc&quot;) &lt;/script&gt;&lt;
```
 
在 nunjucks 模板中,默认进行 escape,不需要显式调用。
 
### .surl()
 
url 过滤。
 
用于在html标签中中要解析 url 的地方(比如 `<a href=""/><img src=""/>`),其他地方不允许使用。
 
对模板中要输出的变量,加 `helper.surl($value)`。
 
**特别需要注意的是在需要解析url的地方,surl 外面一定要加上双引号,否则就会导致XSS漏洞。**
 
不使用 surl
 
```html
<a href="$value" />
```
 
output:
 
```html
<a href="http://www.domain.com<script>" />
```
 
使用 surl
 
```html
<a href="helper.surl($value)" />
```
 
output:
 
```html
<a href="http://www.domain.com&lt;script&gt;" />
```
 
### .sjs()
 
用于在 js(包括 onload 等 event)中输出变量,会对变量中字符进行 JAVASCRIPT ENCODE,
将所有非白名单字符转义为 `\x` 形式,防止xss攻击,也确保在 js 中输出的正确性。
 
```js
const foo = '"hello"';
 
// 未使用 sjs
console.log(`var foo = "${foo}";`);
// => var foo = ""hello"";
 
// 使用 sjs
console.log(`var foo = "${this.helper.sjs(foo)}";`);
// => var foo = "\\x22hello\\x22";
```
 
### .shtml()
 
将富文本(包含 html 代码的文本)当成变量直接在模版里面输出时,需要用到 shtml 来处理。
使用 shtml 可以输出 html 的 tag,同时执行 xss 的过滤动作,过滤掉非法的脚本。
 
** 由于是一个非常复杂的安全处理过程,对服务器处理性能一定影响,如果不是输出 HTML,请勿使用。**
 
简单示例:
 
```js
// js
const value = `<a href="http://www.domain.com">google</a><script>evilcode…</script>`;
 
// 模板
<html>
<body>
  ${helper.shtml($value)}
</body>
</html>
// => <a href="http://www.domain.com">google</a>&lt;script&gt;evilcode…&lt;/script&gt;
```
 
shtml 在 [xss](https://github.com/leizongmin/js-xss/) 模块基础上增加了针对域名的过滤。
 
- [默认规则](https://github.com/leizongmin/js-xss/blob/master/lib/default.js)
- 自定义过滤项 http://jsxss.com/zh/options.html
 
例如只支持 a 标签,且除了 title 其他属性都过滤掉:
 
```javascript
whiteList: {a: ['title']}
```
 
options:
 
> `config.helper.shtml.domainWhiteList` 已过时,请使用 `config.security.domainWhiteList` 代替。
 
注意,shtml 使用了严格的白名单机制,除了过滤掉 xss 风险的字符串外,
在 [默认规则](https://github.com/leizongmin/js-xss/blob/master/lib/default.js) 外的 tag 和 attr 都会被过滤掉。
 
例如 html 标签就不在白名单中,
 
```js
const html = '<html></html>';
 
// html
${helper.shtml($html)}
 
// 输出空
```
 
常见的 `data-xx` 属性由于不在白名单中,所以都会被过滤。
 
所以,一定要注意 shtml 的适用场景,一般是针对来自用户的富文本输入,切忌滥用,功能既受到限制,又会影响服务端性能。
此类场景一般是论坛、评论系统等,即便是论坛等如果不支持 html 内容输入,也不要使用此 helper,直接使用 escape 即可。
 
### .spath()
 
如果把输入字符串用作 path 路径,需要使用 spath 进行安全检验。若路径不合法,返回 null。
 
不合法的路径包括:
 
- 使用 `..` 的相对路径
- 使用 `/` 开头的绝对路径
- 以及以上试图通过 url encode 试图绕过校验的结果字符串
 
```js
const foo = '/usr/local/bin';
console.log(this.helper.spath(foo2));
// => null
```
 
### .sjson()
 
json转义
 
在js中输出json,若未做转义,易被利用为xss漏洞。提供此宏做json encode,会遍历json中的key,将value的值中,所有非白名单字符转义为\x形式,防止xss攻击。同时保持json结构不变。
若你有模板中输出一个json字符串给js应用的场景,请使用 `${this.helper.sjson(变量名)}`进行转义。
 
**处理过程较复杂,性能损耗较大,尽量避免使用**
 
实例:
 
```js
  <script>
    window.locals = ${this.helper.sjson(locals)};
  </script>
```
 
### .cliFilter()
 
远程命令执行漏洞,用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,导致可以执行命令,通常可导致入侵服务器。
 
如果用户可控变量为命令中的参数。则直接使用安全包函数过滤。
 
修复前:
 
```js
 
  cp.exec("bash /home/admin/ali-knowledge-graph-backend/initrun.sh " + port);
 
```
 
修复后:
 
```js
 
  cp.exec("bash /home/admin/ali-knowledge-graph-backend/initrun.sh " + this.helper.cliFilter(port));
 
```
 
如果因为业务需要,需要在参数中天加白名单之外的字符。可以将用户输入按照该字符分割,并使用过滤函数过滤每一段数据。
 
如果用户可控变量为命令中的命令,则和开发协商修改功能或功能下线。
 
## Web 安全头
 
### hsts Strict-Transport-Security
 
默认开启,如果是 http 站点,需要关闭
 
- maxAge 默认一年 `365 * 24 * 3600`
- includeSubdomains 默认 false
 
### csp
 
默认关闭。需要开启的话,需要和安全工程师确定开启策略。
 
- policy 策略
 
### X-Download-Options:noopen
 
默认开启,禁用IE下下载框Open按钮,防止 ie 下下载文件默认被打开 xss
 
### X-Content-Type-Options:nosniff
 
禁用 IE8 自动嗅探 mime 功能。例如:`text/plain` 却当成 `text/html` 渲染,特别当本站点服务内容未必可信的时候。
 
### X-Frame-Options
 
默认 SAMEORIGIN,只允许同域把本页面当作 iframe 嵌入。
 
- value 默认值 `SAMEORIGIN`
 
### X-XSS-Protection
 
- close 默认值false,即设置为 `1; mode=block`
 
## 其他
 
* crossdomain.xml robots.txt 支持,默认都不加,系统可自行加,需要咨询项目安全工程师
* 禁止 trace track 两种类型请求
 
## License¬
 
[MIT](https://github.com/eggjs/egg-security/blob/master/LICENSE)¬