了解XSS与防范

华盟原创文章投稿奖励计划

了解XSS与防范

  跨站脚本(XSS, Cross Site Script)攻击指的是,攻击者可以让某网站执行一段非法脚本。这种情况很常见,比如提交一个表单用于修改用户名,我们可以在文本框中输入一些特殊字符,比如 <, >, ', " 等,检查一下用户名是否正确修改了。

  XSS 如何发生

  XSS 一定是由用户的输入引起的,无论是提交表单、还是点击链接(参数)的方式,只要是对用户的输入不做任何转义就写到数据库,或者写到 html,js 中,就很有可能出错。举两个例子。

  假设需要显示一个新闻标题的列表,服务端渲染的话,用 jade 来实现的话也许是这样的

以下是代码片段:

  h1 娱乐速递

  ul

  each val in newslist

  li= val

  newslist 就当是 ['新闻1', '新闻2', ...] 这样格式的数组,如果直接把内容迭代渲染到 html 上的话,一旦某个新闻标题有特殊字符,比如标题中恰好包含一个标签,那么它就不会显示出来。

  另一个例子,用户在写博客,先不考虑实时保存吧,现在就仅仅需要预览一下,那么可能的代码就是

以下是代码片段:
var preview = document.getElementById('#preview'),

  title = document.getElementById('#blog-title'),

  content = document.getElementById('#blog-content');

  preview.innerHTML =

  '

  ' + title.value + '

  ' +

  '

  ' + content.value + '

  ';

  这里同样是把用户的输入直接显示在了 html 上,如果用户的输入中,正好输入了,把标签提前结束,然后再输入 就可以直接执行 js 代码了。

  XSS 的发生至少需要一个条件,就是这些非法的脚本必须得在浏览器中解析。

  从一个请求发出开始,到浏览器显示内容,与 XSS 相关的有三个地方:URL、HTML、javascript。至于后台方面,它分两个功能,一个是将数据写到数据库,这时候也要对数据进行转义,但不是XSS的范畴,它更多是防止数据破坏 SQL 语句的结构;另一个是从数据库读取数据,直接生成 HTML 或者以 JSON 的方式传给前端,这些数据都必须转义后才能显示到浏览器中。

  HTML 特殊字符

  HTML 本身是一个文本文档,但在浏览器中却可以显现得花样百出,是因为很多字符对于浏览器来说是有特殊含义的,比如在<script> 中的内容,浏览器会做一些动画等等。那么对这些特殊字符进行转义,就意味着让浏览器对待它们的时候,就像普通字符一样,比如 &lg;script&gt; 这段文字在浏览器中就会正常显示为 <script>。

  当我们在代码中生成 HTML 时,一定要注意,变量是否转义了。像这种

以下是代码片段:
  el.innerHTML = title.value;

  就是非常危险的。因为输入框的内容来源于用户,而用户的输入是不可靠的。无论是前端还是后台,一定要有一个类似于 escapeHTML 的方法,然后在代码中这样使用

  

以下是代码片段:
el.innerHTML = escapeHTML(title.value);

  这边贴一段简单的用来转义 HTML 的 JavaScript 方法

  

以下是代码片段:
function encodeHTML (a) {

  return String(a)

  .replace(/&/g, "&")

  .replace(/

  .replace(/>/g, ">")

  .replace(/"/g, """)

  .replace(/'/g, "'");

  };

  那么有哪些字符需要转义呢?这里列了一些常见的。

 

以下是代码片段:
 " --> "

  # --> #

  $ --> $

  & --> &

  ' --> '

  ( --> (

  ) --> )

  ; --> ;

  < --> <

  > --> >

  在 escapeHTML 方法中,我使用了别名的方式转义,因为它比较容易记一点。无论是别名还是十六进制,它们表示的含义都是一样的,比如 & 和 & 都表示 & 符号。想要看更具体的列表可以参考这个网站。

  在浏览器收到 HTML 之后,首先会对所有的内容进行解码,它会把所有能识别的编码符号,解码成字面值。比如有

  

以下是代码片段:
<p>my name is&#58;&#32;<a href="http&#58;&#47;&#47;www.jchen.cc">名一</a></p>

  经过浏览器解码就变成

以下是代码片段:
<p>my name is: <a href="http://www.jchen.cc">名一</a></p>

  这里要说的是,浏览器只会对两个地方解码,一个是标签的内容(即 textContent,除了 <script> 和 <style> 标签)

  另一个是标签的属性值。对于属性名是不会解码的。

  URL早些时候,服务端还不支持在 URL 中直接传输 Unicode,比如 http://jchen.cc/find?q=你好 这样的地址,服务端无法识别“你好”这个值,所以必须编码之后进行传输。

  那么对于 URL,我们只需要对参数的值进行编码就可以了。比如上面这个链接,编码之后就是 http://jchen.cc/find?q=%E4%BD%A0%E5%A5%BD。

  如果对整个 URL 编码,那么链接就无效了。

  编码的方式很简单,浏览器提供了全局的 encodeURI 方法,调用之后就可以实现转义了。

  有一点很重要,encodeURI 是不会转义 :, /, ?, &, = 这些在 URL 中有特殊含义的字符的,那么如果有个参数正好包含了这些字符,就不会转义,比如

以下是代码片段:

  encodeURI('http://jchen.cc/login?name=名一&from=http://other.com');

  // -> http://jchen.cc/login?name=%E5%90%8D%E4%B8%80&from=http://other.com

  from 参数的值并没有转义,这时候,就需要用到另一个方法 encodeURIComponent

  var param = encodeURIComponent('http://other.com');

  encodeURI('http://jchen.cc/login?name=名一&from=') + param;

  // -> http://jchen.cc/login?name=%E5%90%8D%E4%B8%80&from=http%3A%2F%2Fother.com

  所以结论就是,如果要对整个 URL 进行转义,使用 encodeURI,如果对参数的值进行转义,使用 encodeURIComponent。

  当动态生成的链接地址需要赋值给 href 或者 src 属性时,需要对这些地址进行 URL 转义。当然,如果服务端支持在 URL 中包含 UTF-8 的字符的话,其实不转义也不会错,这就是为什么我们平时不会太注意对表单和 URL 参数进行转义的原因,因为服务端表现良好。

  JavaScript 特殊字符

  JS 中的转义都是通过反斜杠完成,有三种类型,以 ' 和 " 为例

以下是代码片段:

  直接反斜杠 --> /'/"

  十六进制 --> /x22/x27

  Unicode --> /u0022/u0027

  一般情况下可以直接通过反斜杠转义,但有些字符我们不知道怎么输入,很常见的比如 Web Font,在 CSS 中可以看到类似这样的代码

  .glyphicon-home::before {

  content: "

 

原文地址:https://hack.77169.com/201510/215469.shtm

本文原创,作者:华盟君,其版权均为华盟网所有。如需转载,请注明出处:https://www.77169.net/html/20271.html