egg.js学习记录——代码安全

原文链接https://eggjs.org/zh-cn/intro/quickstart.html

XSS攻击

XSS攻击全称跨站脚本攻击,是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS,XSS是一种在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。

egg.js学习记录——代码安全_第1张图片
image.png

恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。

Web 安全概念

Web 应用中存在很多安全风险,这些风险会被黑客利用,轻则篡改网页内容,重则窃取网站内部数据,更为严重的则是在网页中植入恶意代码,使得用户受到侵害。常见的安全漏洞如下:

  • XSS 攻击:对 Web 页面注入脚本,使用 JavaScript 窃取用户信息,诱导用户操作。
  • CSRF 攻击:伪造用户请求向网站发起恶意请求。
  • 钓鱼攻击:利用网站的跳转链接或者图片制造钓鱼陷阱。
  • HTTP参数污染:利用对参数格式验证的不完善,对服务器进行参数注入攻击。
  • 远程代码执行:用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,导致在没有指定绝对路径的情况下就执行命令。

而框架本身针对 Web 端常见的安全风险内置了丰富的解决方案:

  • 利用 extend 机制扩展了 Helper API, 提供了各种模板过滤函数,防止钓鱼或 XSS 攻击。
  • 常见 Web 安全头的支持。
  • CSRF 的防御方案。
  • 灵活的安全配置,可以匹配不同的请求 url 。
  • 可定制的白名单,用于安全跳转和 url 过滤。
  • 各种模板相关的工具函数做预处理。

在框架中内置了安全插件 egg-security, 提供了默认的安全实践。

开启与关闭配置

注意:除非清楚的确认后果,否则不建议擅自关闭安全插件提供的功能。

框架的安全插件是默认开启的,如果我们想关闭其中一些安全防范,直接设置该项的 enable 属性为 false 即可。例如关闭 xframe 防范:


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

match 和 ignore

match 和 ignore 使用方法和格式与中间件通用配置一致。

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


exports.security = {
 csp: {
 match: '/example',
 policy: {
 //...
 },
 },
};

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


exports.security = {
 csp: {
 ignore: '/example',
 xframe: {
 //...
 },
 },
};

如果要针对内部 ip 关闭部分安全防范:


exports.security = {
 csrf: {
 // 判断是否需要 ignore 的方法,请求上下文 context 作为第一个参数
 ignore: ctx => isInnerIp(ctx.ip),
 },
}

下面我们会针对具体的场景,来讲解如何使用框架提供的安全方案进行 Web 安全防范。

安全威胁XSS的防范

XSS(cross-site scripting跨域脚本攻击)攻击是最常见的 Web 攻击,其重点是『跨域』和『客户端执行』。

XSS 攻击一般分为两类:

  • Reflected XSS(反射型的 XSS 攻击)
  • Stored XSS(存储型的 XSS 攻击)

Reflected XSS

反射型的 XSS 攻击,主要是由于服务端接收到客户端的不安全输入,在客户端触发执行从而发起 Web 攻击。比如:

在某购物网站搜索物品,搜索结果会显示搜索的关键词。搜索关键词填入, 点击搜索。页面没有对关键词进行过滤,这段代码就会直接在页面上执行,弹出 alert。

防范方式

框架提供了 helper.escape() 方法对字符串进行 XSS 过滤。


const str = '><';
console.log(ctx.helper.escape(str));
// => ><script>alert("abc") </script><

当网站需要直接输出用户输入的结果时,请务必使用 helper.escape() 包裹起来,如在 egg-view-nunjucks 里面就覆盖掉了内置的 escape

另外一种情况,网站输出的内容会提供给 JavaScript 来使用。这个时候需要使用 helper.sjs() 来进行过滤。

helper.sjs() 用于在 JavaScript(包括 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";

还有一种情况,有时候我们需要在 JavaScript 中输出 json ,若未做转义,易被利用为 XSS 漏洞。框架提供了 helper.sjson()宏做 json encode,会遍历 json 中的 key ,将 value 的值中,所有非白名单字符转义为 \x 形式,防止 XSS 攻击。同时保持 json 结构不变。 若存在模板中输出一个 JSON 字符串给 JavaScript 使用的场景,请使用 helper.sjson(变量名) 进行转义。

处理过程较复杂,性能损耗较大,请仅在必要时使用。

实例:



Stored XSS

基于存储的 XSS 攻击,是通过提交带有恶意脚本的内容存储在服务器上,当其他人看到这些内容时发起 Web 攻击。一般提交的内容都是通过一些富文本编辑器编辑的,很容易插入危险代码。

防范方式

框架提供了 helper.shtml() 方法对字符串进行 XSS 过滤。

注意,将富文本(包含 HTML 代码的文本)当成变量直接在模版里面输出时,需要用到 shtml 来处理。 使用 shtml 可以输出 HTML 的 tag,同时执行 XSS 的过滤动作,过滤掉非法的脚本。

由于是一个非常复杂的安全处理过程,对服务器处理性能一定影响,如果不是输出 HTML,请勿使用。

简单示例:

// js
const value = `google`;

// 模板


 {{ helper.shtml(value) }}


// => google<script>evilcode…</script>

shtml 在 xss 模块基础上增加了针对域名的过滤。

  • 默认规则
  • 自定义过滤项: http://jsxss.com/zh/options.html

例如只支持 a 标签,且除了 title 其他属性都过滤掉: whiteList: {a: ['title']}

options:

  • config.helper.shtml.domainWhiteList: [] 可拓展 href 和 src 中允许的域名白名单。

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

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


const html = '';

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

// 输出空

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

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

JSONP XSS

JSONP 的 callback 参数非常危险,他有两种风险可能导致 XSS

1、callback 参数意外截断js代码,特殊字符单引号双引号,换行符均存在风险。

2、callback 参数恶意添加标签(如

你可能感兴趣的:(egg.js学习记录——代码安全)