前端话安全

做为前端工程师,平时少不了要与客户端安全问题打交道,这里记录了一些自己平时工作中对于客户端安全的理解,以及一些应对方式。


同源策略

首先是同源策略,同源策略作为客户端安全的基础约定,客户端的安全功能都是基于它进行构建的。
大部分从客户端发起的攻击,第一步需要做的就是想办法让自己的攻击手段符合同源策略约定,或欺骗,或绕过。

同源策略,约定了:协议,域名,端口 必需统一。

同源策略

它的影响范围对前端来说常见于:

  1. XMLHttpRequest请求
  2. DOM操作(常见于嵌套了iframe的页面)
  3. cookie操作
  4. Web storage

我们通过src加载的跨域静态资源不在受限范围内。

WEB应用发展到今天功能越来越强大,应用场景也越来越复杂,难以避免我们有时需要进行跨域通信,而同源策略也同时限制了我们这类业务需求,针对这种场景,我们目前主流的解决方案是:设置响应头与JSONP。

  1. 设置响应头:Access-Control-Allow-Origin: * , 注意,其实这里*号是非常不安全的设置方式,这样允许了任何域名进行访问,从安全角度考虑建议设置为固定的域名。 而 * 更多用于静态资源CDN这样的非业务服务器。
  2. JSONP其实利用的就是src加载静态资源不受同源策略限制这个特点,通过生成一个JS文件的方式,进行前后端的通信。

利用这些方案满足我们业务的同时,我们也不能忘了潜在的安全风险,添加referer check过滤非法请求是一个很好的方式。


ClickJacking(点击劫持)

点击劫持是一种视觉上的欺骗手段。攻击者使用一个透明的、不可见的iframe,覆盖在一个网页上,然后诱使用户在该网页上进行操作,此时用户将在不知情的情况下点击透明的iframe页面。通过调整iframe页面的位置,可以诱使用户恰好点击在iframe页面的一些功能性按钮上。

ClickJacking

ClickJacking被广泛用于钓鱼网站以及广告作弊,应对它业界也已经有了比较成熟的解决方案:

  1. frame busting: —— 脚本判断是否iframe嵌套

    1
    2
    3
    4
    5
    if top != self
    if top.location != self.location
    if top.location != location
    if window != top
    ……
  2. X-Frame-Options: ——设置响应头

    1
    2
    3
    DENY  —— 不允许通过Iframe加载
    SAMEORIGIN —— 只允许同源网站通过iframe加载
    ALLOW-FROM origin —— 允许设置的origin使用iframe加载

第一种方案,实现代码多样,存在被绕过的风险,所以通常我们选择第二种方案设置响应头来应对点击劫持。


CSRF(跨站请求伪造)

CSRF 是一种挟制用户在当前已登录的Web应用上执行非本意的操作的攻击方法。利用的是网站对用户网页浏览器的信任机制。

上面的描述有点抽象,我们还可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,甚至于购买商品,虚拟货币转账…可以造成用户个人隐私泄露以及财产安全。

CSRF(跨站请求伪造)

以上图为例,

  1. 同一浏览器下。
  2. 用户登陆jd.com。
  3. 在未关闭jd.com的前提下,新开窗口访问了另一个包含CSRF攻击的网站。这里用csrf.com代称
  4. csrf.com直接发起一个jd.com的操作请求,由于用户已登陆jd.com,这个请求带上了合法的jd.com域cookie。
  5. jd.com接受请求,验证请求为合法操作,执行相关操作。

这就是一个典型的CSRF攻击流程。
当然jd.com肯定对CSRF进行了防御,通常是referer check,所以我在demo演示时,使用了chrome插件强行将csrf.com下发出请求的referer值修改为了jd.com。

对于CSRF的防御。我们通常采用以下方案:

  1. Referer Check — HTTP头中的Referer字段,进行域名校验。
  2. 交互验证 — 比如验证码,短信验证等等。
  3. Token 校验 — CSRF攻击的本质,其实是用户操作的参数可以被猜测到,如果我们使用攻击者无法猜测的数据做为校验,侧CSRF攻击无法进行。

XSS(跨站脚本攻击)

因为现有电商网站对XSS防御非常好,这块会结合后面的代理劫持一起做示例演示。

什么是XSS攻击?

XSS是利用WEB开发时的漏洞,通过某些方法,在网页上注入恶意代码。并执行恶意代码,通常来说,都是一些客户端脚本,javascript,vbscript。

XSS攻击的方式是具有针对性的,针对不同的安全策略,采用不同的注入方案,以期望绕过拦截,在浏览器端执行恶意代码。同时XSS攻击随我们技术的发展,在同时进步,对XSS的防御我们应该随时警惕。

XSS攻击的类型?

网上对XSS攻击分了各种类型,这里我根据自己的理解,只归为两大类:

  1. 反射型XSS — 将输入数据简单的“反射”给浏览器, 非持久型XSS —— URL传参等。
  2. 存储型XSS — 将输入数据 “存储” 在服务器上,持久型XSS —— 用户评论,用户发贴,签名等等。

常见的防御方案

  1. Cookie —— 设置HttpOnly ,只允许由浏览器发起的请求中带Cookie , 封堵了前端获取cookie的渠道。
  2. 输入检测 —— 过滤提交内容,encode, js-xss等。
  3. 输出转义 – 前后端模板引擎都可以帮我们完成这个事。

历史案例

  1. 腾讯 —— QQ空间自定义样式 , 初期QQ空间收费时,很多用户通过输入样式代码,免费装扮空间。
  2. 腾讯 —— QQ空间自动转发不良信息。
  3. 腾讯 —— QQ邮箱XSS漏洞可获取用户邮件列表信息及内容。
  4. 百度 —— 百度空间XSS 蠕虫,用户互发垃圾消息。

以上案例有一个共同特征 —— 都是用户产生内容为主体的WEB站点。

这类网站内容通常是带有用户自定义样式的富内容,针对这样的富内容,只依靠模板引擎暴力转义,将丢失用户的自定义样式,甚至可能引起页面报错阻塞。所以我们需要正确识别用户意图,有针对性的进行安全字符转义。

业界对这种富文本场景也有非常成熟的方案:

  1. 前端: JS-XSS
  2. 后端: Anti-samy

Proxy Hijack(代理劫持)

关于代理劫持,网上有这样一组数据:

Proxy Hijack(代理劫持)

我们可以看到,大部分代理服务器都没有使用HTTPS,小部分代理甚至有内容篡改行为。

不安全代理带来的危害:

  1. 网页广告植入
  2. 窃取登陆凭证
  3. 获取用户隐私
  4. ……

如果使用代理服务器,实际上你所访问的所有HTTP内容,都有可能是伪造的。

唯一的防御方式

请使用https


获取登陆cookie演示

现代电商对于安全问题也非常重视,所以我们这里通过代理劫持,模拟出不安全的前端环境,用于演示前端攻击。

DEMO

流程说明:

  1. 攻击者发布免费代理
  2. 普通用户通过网络途径等获取到代理地址
  3. 普通用户在使用代理的情况下登陆了jd
  4. 代理服务器劫持jd.com网页,篡改jd.com网页内容,注入xss攻击代码。
  5. 被篡改的jd.com网站,通过js获取jd.com域下的cookie, 发送到代理服务器。
  6. 同时由于这个系统登陆态cookie放在passport域下,该域cookie使用了httpOnly,所以发起一个被劫持的passport域下请求。passport域下的cookie被代理服务器获取到。
  7. 代理服务器将jd.com及passport域下的cookie发送给攻击者
  8. 攻击者本地代理jd.com域,访问一个任意jd.com域下地址,并通过本地代理服务器,注入刚刚由免费代理服务器发送来的cookie。
  9. 攻击者此时已取得用户合法的登陆凭证。可以进行任意操作。

这个demo利用代理,在没有安全漏洞的情况下,创建了一个前端安全漏洞。正常网络访问下,用户是不需要担心这些问题的。

总结

客户端从客观上都是不可信任,任何的东西在客户端都有被伪造可能。前端工程师在渲染客户端时,需要时刻注意过滤可能存在的安全漏洞。服务器端工程师接收数据时,也应该注意数据安全校验,请求源的校验等等。对于敏感页面,前后端都可以进行协议头的监测,强制转换。

另外产品角度也可以有意识的引导用户使用安全的环境环境,给出一些网络环境监测提醒,比如chrome最新版,已经将所有http页面标注为不安全页面。

安全问题无止境,引用一段《白帽子讲安全》的话做为本文结束:

安全是一门朴素的学问,也是一种平衡的艺术。