XSS 攻击与防范

跨站脚本攻击

跨站脚本攻击,Cross-site scripting, 缩写 XSS, ( 以前的文档也有写作 CSS 的,但跟层叠样式表的缩写一样,为了区分,现在一般称作 XSS ),是一种非常常见的网络攻击方式,类似于 SQL 注入,也是一种注入攻击。

XSS 通过在网页中插入危险脚本,可以绕过同源策略之类的安全机制,获得执行危险操作的权限,达到攻击的目的。这些攻击可能涵盖访问敏感信息、篡改 HTML 内容、跳转到恶意网站、监控用户输入等等等,具有相当大的威胁。

攻击的逻辑

  • 对于服务器来说,攻击代码是是一种普通数据(如一段 HTML 字符串),对服务器本身是没有特殊意义的,不会对服务器的行为有影响
  • 对于客户端来说,攻击代码(如 HTML )是一种有特定意义的指令,会影响客户端的行为
  • XSS 攻击通常会在客户端传递经过精心设计的恶意内容给服务器,这些数据会影响服务器正常组装 HTML、JavaScript、CSS 等指令代码的过程,让最终组装出来的指令代码包含恶意内容。

比如,通过传递经过巧妙设计的 URL 查询参数,让服务器使用该参数组装 HTML 标签时,意外提前闭合 HTML 标签,然后接续上一段攻击代码,这些包含攻击代码的 HTML 在浏览器上就反映为攻击。

XSS 的类型

XSS 根据特点,可以分为几种类型。

READ MORE...

HTTP 请求报文

HTTP 报文结构

起始行

报文第一行内容即为起始行,请求报文和响应报文中有所区别

请求报文的起始行包含:

  1. HTTP 动作(GET, POST, PUT, DELETE, PATCH, …)
  2. 操作的资源
  3. HTTP 版本

例:

GET /example/example.jpg HTTP/1.1

响应报文的起始行包含:

  1. HTTP 版本
  2. HTTP 状态码
  3. HTTP 状态描述

例:

HTTP/1.1 200 OK

首部(headers)

首部内容紧接着起始行之后,每行代表一个首部字段。 一个 HTTP 报文可以拥有多个或者零个首部字段。

每个首部字段的结构是一个名值对,字段名后面跟着一个冒号,冒号之后是字段值。如:

Content-Type: text/html

最后,首部以一个空行结束(即使后面没有 body 部分也不可省略)。

READ MORE...

CSRF 攻击与防范

跨站请求伪造

跨站请求伪造 ( Cross Site Request Forgery, 缩写 CSRF ),是一种网络攻击方式。

原理上,它欺骗服务器,让服务器误认为攻击请求是用户自己发出的合法请求,以达到攻击的目的。

攻击的原理

  1. 用户登录 站点A。
  2. 没有注销 站点A 的情况下,访问包含攻击代码的 站点B。
  3. 站点B 向 站点A 发送包含敏感操作的请求,这时候浏览器会带上 站点A 的 cookie。
  4. 站点A 的服务器收到请求,通过 cookie 识别出了用户,开始执行请求的敏感操作。

我们可以发现,这里面的核心思想是,服务器没有或不能分辨包含敏感操作的请求是否是用户自己发出的

防御攻击

既然明白了攻击的原理,那么就可以针对性的作出防御。核心在于,服务器需要甄别请求是否是用户自身发出的。

实践上有下面几种常见的防御手段。

READ MORE...

Immutable.js

网络上找到的一张原理图:

  1. 对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。
  2. 如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。
  3. Immutable 实现的原理是 Persistent Data Structure(持久性数据结构)
  4. Immutable 使用了 Structural Sharing 来节省内存、提升效率(深拷贝效率低,内存占用大

全文完

READ MORE...

阻塞、非阻塞IO,同步、异步IO

今天闲暇看 Node.js,看到这些概念,有些困惑的地方,Google 一番,做些笔记。 因为术业方向问题,可能理解有误,但记录下来便于日后复习的时候比对。

阻塞 IO (Blocking IO), 非阻塞 IO (Non-Blocking IO)

核心区别在于,发起调用的进程(或线程)是否会挂起等待 IO 完成。

下面举例说明用户进程发起一个 read 数据的阻塞 IO 操作的过程。 进程在发起系统调用后,就会一直干等。

  1. 首先等待 kernel 准备数据(如等待完整的网络数据包),这个阶段是 Blocking 的。
  2. 数据准备完毕后,kernel 将数据从缓冲区拷贝到用户空间,这个阶段也是 Blocking 的。
  3. 调用返回,用户进程也就解除了阻塞状态。

由上述过程可见,阻塞 IO 操作的流程很简单易懂,但也可以遇见,如果 IO 操作非常费时,那么用户进程在这个过程将会无法响应其他操作,这对某些应用来说,是无法接受的。

那么,一个非阻塞的 IO 又是怎么样的呢?

  1. 一个read的非阻塞IO,不会挂起用户进程,在 kernel 准备数据中的时候,收到系统调用后,会立即返回一个错误状态,用户进程不会被挂起,是Non-Blocking的。
  2. 发起调用的进程因为马上就能获得数据的准备的状态,因此可以周期性继续发起调用,直至 kernel 准备好数据。
  3. 当 kernel 准备好数据后,再接收到读取的调用的话,就会将数据拷贝到用户空间,这个阶段是Blocking的。
  4. 调用返回,圆满结束。

由上述过程可见,非阻塞 IO 操作的流程相比复杂一些,但因为用户进程不会被挂起,因此有机会在 IO 过程做其他事情,灵活很多。

同步 IO

通常情况下, 不论阻塞 IO 还是非阻塞 IO, 均是同步 IO。

异步 IO

着重说明下异步 IO, 因为这是我们 JavaScript 开发者接触最多的一个概念。

一个异步的 IO,发起调用后会立即返回,可以不必等待 IO 结果去做其他事情,当有结果之后,会收到一个信号通知,从而可以回头进入数据处理环节。

具体的流程如下:

  1. 发起异步 IO,立即返回,可以做其他事情
  2. kernel 会默默地准备数据、拷贝数据到内存用户空间,向用户进程发一个 signal 通知其IO已完成
  3. 调用发起者处理 IO 结果

由此可见,一个异步的 IO 全程不阻塞,也不必关心 IO 的过程状态,省心省事。

READ MORE...