@eggjs/security

中文文档
5.1.0发布于 2026/10/07MITTypeScriptES Module构建来源已验证近 30 天下载 5399

彩蛋框架中的安全插件

中文使用文档
文档目录30 节
  1. 使用方式
  2. 关闭安全防范
  3. match 和 ignore
  4. API
  5. ctx.isSafeDomain(domain)
  6. 接口限制
  7. csrf
  8. ctoken
  9. safe redirect
  10. jsonp
  11. helper
  12. .escape()
  13. .surl()
  14. .sjs()
  15. .shtml()
  16. .spath()
  17. .sjson()
  18. .cliFilter()
  19. .escapeShellArg()
  20. .escapeShellCmd()
  21. Web 安全头
  22. hsts Strict-Transport-Security
  23. csp
  24. X-Download-Options:noopen
  25. X-Content-Type-Options:nosniff
  26. X-Frame-Options
  27. X-XSS-Protection
  28. 其他
  29. License
  30. Contributors

@eggjs/security

NPM version Known Vulnerabilities npm download Node.js Version PRs Welcome CodeRabbit Pull Request Reviews

egg 内置的安全插件

使用方式

egg 默认开启此插件,所以无需配置。

修改 config/config.js 文件修改配置

exports.security = {
  xframe: {
    value: 'SAMEORIGIN',
  },
};

关闭安全防范

如果你想关闭其中一些安全防范,直接设置该项的 enable 属性为 false 即可,如关闭 xfame 防范:

exports.security = {
  xframe: {
    enable: false,
  },
};

match 和 ignore

如果只想开启针对某一路径,则配置 match 选项,例如只针对 /example 开启 csp

exports.security = {
  csp: {
    match: '/example',
    // match: /^\/api/, // support regexp
    // match: ctx => ctx.path.startsWith('/api'), // support function
    // match: [ ctx => ctx.path.startsWith('/api'), /^\/foo$/, '/bar'], // support Array
    policy: {
      //...
    },
  },
};

如果需要针对某一路径忽略某安全选项,则配置 ignore 选项,例如针对 /example 关闭 xframe,以便合作商户能够嵌入我们的页面:

exports.security = {
  xframe: {
    ignore: '/example',
    // ignore: /^\/api/, // support regexp
    // ignore: ctx => ctx.path.startsWith('/api'), // support function
    // ignore: [ ctx => ctx.path.startsWith('/api'), /^\/foo$/, '/bar'], // support Array
    // ...
  },
};

注意:如果存在 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 代码:

<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,存什么字段等,都可以通过以上两个接口拓展。

配置项

exports.security = {
  csrf: {
    type: 'ctoken', // 可以是 ctoken / referer / all, 默认为 ctoken
    useSession: false, // 如果设为 true,secret 将存储在 session 中
    ignoreJSON: false, // 如果设为 true ,将忽略 json 请求
    cookieName: 'csrfToken', // csrf 的 token 在 cookie 中存储的 key 名称
    sessionName: 'csrfToken', // csrf 的 token 在 session 中存储的 key 名称
    headerName: 'x-csrf-token', // csrf token 在 header 中的名称
    bodyName: '_csrf', // csrf token 在 body 中的名称
    queryName: '_csrf', // csrf token 在 query 中的名称
    rotateWhenInvalid: false, // csrf invalid 时刷新 token,用于同域名下多个业务 token 可能互相影响的情况
    refererWhiteList: [], // referer 白名单
    supportedRequests: [
      // 支持的 url path pattern 和方法,根据配置名单由上至下匹配 url path 正则,建议在自定义时配置 {path: /^\//, methods:['POST','PATCH','DELETE','PUT','CONNECT']} 为兜底规则
      { path: /^\//, methods: ['POST', 'PATCH', 'DELETE', 'PUT', 'CONNECT'] },
    ],
  },
};

注意,methods 可以为空, 如果将 supportedRequests 设置为supportedRequests: [{path: /^\//, methods:[]}], 那么等效于关闭 csrf 防御。

safe redirect

  • ctx.redirect(url) 如果不在配置的白名单内,则禁止
  • ctx.unsafeRedirect(url) 不建议使用

安全方案覆盖了默认的ctx.redirect方法,所有的跳转均会经过安全域名的判断。

用户如果使用ctx.redirect方法,需要在应用的配置文件中做如下配置:

exports.security = {
  domainWhiteList: ['.domain.com'], // 安全白名单,以.开头
};

若用户没有配置 domainWhiteList 或者 domainWhiteList 数组内为空,则默认会对所有跳转请求放行,即等同于ctx.unsafeRedirect(url)。同时域名和 url 检查时不区分大小写。

jsonp

使用 jsonp-body,在 egg context 中实现,并不再 egg-security 中。

防御内容:

  • callback函数名词最长50个字符限制
  • callback函数名只允许"[","]","a-zA-Z0123456789_", "$" ".",防止一般的 xss,utf-7 xss等攻击

可定义配置:

  • callback 默认 _callback,可以改名
  • limit - 函数名 length 限制,默认 50

helper

.escape()

对字符串进行 xss 过滤,安全性最高的过滤方式。

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

<a href="$value" />

output:

<a href="http://www.domain.com<script>" />

使用 surl

<a href="helper.surl($value)" />

output:

<a href="http://www.domain.com&lt;script&gt;" />

.sjs()

用于在 js(包括 onload 等 event)中输出变量,会对变量中字符进行 JAVASCRIPT ENCODE, 将所有非白名单字符转义为 \x 形式,防止xss攻击,也确保在 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
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 模块基础上增加了针对域名的过滤。

例如只支持 a 标签,且除了 title 其他属性都过滤掉:

whiteList: {
  a: ['title'];
}

options:

config.helper.shtml.domainWhiteList 已过时,请使用 config.security.domainWhiteList 代替。

注意,shtml 使用了严格的白名单机制,除了过滤掉 xss 风险的字符串外, 在 默认规则 外的 tag 和 attr 都会被过滤掉。

例如 html 标签就不在白名单中,

const html = '<html></html>';

// html
${helper.shtml($html)}

// 输出空

常见的 data-xx 属性由于不在白名单中,所以都会被过滤。

所以,一定要注意 shtml 的适用场景,一般是针对来自用户的富文本输入,切忌滥用,功能既受到限制,又会影响服务端性能。 此类场景一般是论坛、评论系统等,即便是论坛等如果不支持 html 内容输入,也不要使用此 helper,直接使用 escape 即可。

.spath()

如果把输入字符串用作 path 路径,需要使用 spath 进行安全检验。若路径不合法,返回 null。

不合法的路径包括:

  • 使用 .. 的相对路径
  • 使用 / 开头的绝对路径
  • 以及以上试图通过 url encode 试图绕过校验的结果字符串
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(变量名)}进行转义。

处理过程较复杂,性能损耗较大,尽量避免使用

实例:

<script>window.locals = ${this.helper.sjson(locals)};</script>

.cliFilter()

远程命令执行漏洞,用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,导致可以执行命令,通常可导致入侵服务器。

如果用户可控变量为命令中的参数。则直接使用安全包函数过滤。

修复前:

cp.exec('bash /home/admin/ali-knowledge-graph-backend/initrun.sh ' + port);

修复后:

cp.exec('bash /home/admin/ali-knowledge-graph-backend/initrun.sh ' + this.helper.cliFilter(port));

如果因为业务需要,需要在参数中添加白名单之外的字符。可以将用户输入按照该字符分割,并使用过滤函数过滤每一段数据。

如果用户可控变量为命令中的命令,则和开发协商修改功能或功能下线。

.escapeShellArg()

POSIX shell 命令行参数转义。给字符串增加一对单引号并且能引用或者转码任何已经存在的单引号, 这样以确保能够直接将一个字符串传入 shell 函数,并且还是确保安全的。

如果可以,优先使用 child_process.execFile() 或 child_process.spawn() 的参数数组。这个 helper 只用于 POSIX shell 命令字符串里的单个参数,不适用于 Windows cmd.exe 或 PowerShell 转义。

const ip = '127.0.0.1 && cat /etc/passwd';
const cmd = 'ping -c 1 ' + this.helper.escapeShellArg(ip);

console.log(cmd);
//ping -c 1 '127.0.0.1 && cat /etc/passwd'

.escapeShellCmd()

命令行转义,从输入的命令行中删除下列字符: #&;`|*?~<>^()[]{}$;'", 0x0A 和 0xFF

const ip = '127.0.0.1 && cat /etc/passwd';
const cmd = 'ping -c 1 ' + this.helper.escapeShellCmd(ip);

console.log(cmd);
//ping -c 1 127.0.0.1  cat /etc/passwd

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

Contributors

Contributors

Made with contributors-img.

版本与发布记录

@eggjs/security 共发布 55 个版本,首次发布于 2025/01/18;过去 12 个月发布了 34 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
5.1.0latest2026/10/071 个月前
5.0.22026/10/061 个月前
5.0.2-rc.1rc2026/10/061 个月前
5.0.2-rc.02026/09/231 个月前
5.0.2-beta.27beta2026/09/201 个月前
5.0.2-beta.262026/08/073 个月前

关于 @eggjs/security 的常见问题

@eggjs/security 是什么?

彩蛋框架中的安全插件

如何安装 @eggjs/security?

在项目目录运行 npm install @eggjs/security,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:egg(4.2.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@eggjs/security 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@eggjs/security 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@eggjs/security 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >= 22.18.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@eggjs/security 可以商用吗?

@eggjs/security 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@eggjs/security 的下载量有多少?

根据 npm 官方下载统计,@eggjs/security 在 2026/10/13 – 2026/11/11 这 30 天内被下载 5,399 次,日均约 180 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@eggjs/security 还在维护吗?

最新版本 5.1.0 发布于 2026/10/07(1 个月前);至今共发布 55 个版本,其中过去 12 个月发布了 34 个;首次发布于 2025/01/18。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。