XSS攻击

279 阅读6分钟

XSS攻击的定义

XSS(Cross Site Scripting),跨站脚本攻击,是一种允许攻击者在另外一个用户的浏览器中执行恶意代码脚本注入式攻击。本来缩小应该是CSS,但为了和层叠样式(CasCADing Style Sheet,CSS)有所区分,故称XSS

XSS攻击又称为跨站脚本,XSS的重点不在于跨站点,而是在于脚本的执行。XSS是一种经常出现在Web应用程序中的计算机安全漏洞,是由于Web应用程序对用户的输入过滤不足而产生的,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。

对于攻击者来说,能够让受害者浏览器执行恶意代码的唯一方式,就是把代码注入到受害者从网站下载的网页中。

XSS攻击的种类

持续型XSS攻击

  • 经过后端,经过数据库
  • 恶意脚本来源于网站的数据库

攻击者事先将恶意代码上传或者储存到漏洞服务器中,只要受害者浏览包含此恶意代码的页面就会执行恶意代码。这意味着只要访问了这个页面的访客,都有可能会执行这段恶意脚本,因此存储型XSS攻击的危害会更大。此类攻击一般出现在网站留言、评论、博客日志等交互处,恶意脚本存储到客户端或者服务端的数据库中。

场景举例

  • 攻击者通过评论表单提交将<script>alert(‘aaa’)</script>提交到网站
  • 网站后端对提交的评论数据不做任何操作,直接存储到数据库中
  • 其他用户访问正常访问网站,并且需要请求网站的评论数据
  • 网站后端会从数据库中取出数据,直接返回给用户
  • 用户得到页面后,直接运行攻击者提交的代码<script>alert(‘aaa’)</script>,所有用户都会在网页中弹出aaa的弹窗

这种攻击方式恶意代码会被存储在数据库中,其他用户在正常访问的情况下,也有会被攻击,影响的范围比较大。

反射型XSS攻击

  • 经过后端,不经过数据库
  • 恶意脚本来源于受害者的请求

反射型XSS攻击一般是攻击者通过特定手法,诱使用户去访问一个包含恶意代码的URL,当受害者点击这些专门设计的链接的时候,恶意代码会直接在受害者主机上的浏览器执行。此类XSS攻击通常出现在网站的搜索栏、用户登录口等地方,常用来窃取客户端Cookies或进行钓鱼欺骗

场景举例1

  • 用户误点开了带攻击的url :http://xxx?keyword=
  • 网站给受害者的返回中包含了来自URL的的恶意文本
  • 用户的浏览器收到文本后执行页面,会在网页中弹窗aaa

反射型的攻击需要用户主动的去访问带攻击的链接,攻击者可以通过邮件或者短信的形式,诱导受害者点开链接。如果攻击者配合短链接URL,攻击成功的概率会更高

场景举例2

image.png

image.png

上述就是一个简单的反射XSS攻击的例子。
当我们访问一个网站时,此时如果攻击者在该网站上设置了一个恶意连接,此时当我们点击该链接时,就会向攻击者服务器发起请求,返回对应的脚本,此时当浏览器加载该脚本文件时,就会出现token或者cookie等信息的泄漏。

DOM-based型XSS攻击

  • 不经过后端,DOM—based XSS漏洞是基于文档对象模型(Document Objeet Model,DOM)的一种漏洞,dom - xss是通过url传入参数去控制触发的。
  • 基于DOM的XSS攻击是反射型攻击的变种。服务器返回的页面是正常的,只是我们在页面执行js的过程中,会把攻击代码植入到页面中。

客户端的脚本程序可以动态地检查和修改页面内容,而不依赖于服务器端的数据。例如客户端如从URL中提取数据并在本地执行,如果用户在客户端输入的数据包含了恶意的JavaScript脚本,而这些脚本没有经过适当的过滤或者消毒,那么应用程序就可能受到DOM-based型XSS攻击。

需要特别注意以下的用户输入源document.URL、location.hash、location.search、document.referrer等。

DOM型XSS攻击步骤如下。

  • 攻击者构造出特殊的url,其中包含恶意代码。
  • 用户打开带有恶意代码的url。
  • 用户浏览器接收到响应后解析执行,前端取出恶意代码并执行。
  • 恶意代码窃取用户数据并且发送到攻击者的网站,冒充用户的行为。

image.png

区别

DOM-based xss和之前两种xss攻击的区别,DOM-based xss是前端的漏洞,但是前面两个是服务器的漏洞。

XSS预防

关于前面我们知道了XSS攻击形成的存在两个原因:

  • 攻击者提交恶意代码
  • 浏览器执行恶意代码

防御措施

  • 输入过滤:避免 XSS 的方法之一主要是将用户输入的内容进行过滤。对所有用户提交内容进行可靠的输入验证,包括对 URL、查询关键字、POST数据等,仅接受指定长度范围内、采用适当格式、采用所预期的字符的内容提交,对其他的一律过滤。(客户端和服务器都要)
  • 输出转义:例如: 往 HTML 标签之间插入不可信数据的时候,首先要做的就是对不可信数据进行 HTML Entity 编码 HTML 字符实体
function htmlEncodeByRegExp  (str){  
         var s = "";
         if(str.length == 0) return "";
         s = str.replace(/&/g,"&amp;");
         s = s.replace(/</g,"&lt;");
         s = s.replace(/>/g,"&gt;");
         s = s.replace(/ /g,"&nbsp;");
         s = s.replace(/\'/g,"&#39;");
         s = s.replace(/\"/g,"&quot;");
         return s;  
 }
var tmpStr="<p>123</p>";   
var html=htmlEncodeByRegExp (tmpStr)
console.log(html) //&lt;p&gt;123&lt;/p&gt;
document.querySelector(".content").innerHTML=html; //<p>123</p>
  • 使用 HttpOnly Cookie:将重要的cookie标记为httponly,这样的话当浏览器向Web服务器发起请求的时就会带上cookie字段,但是在js脚本中却不能访问这个cookie,这样就避免了XSS攻击利用JavaScriptdocument.cookie获取cookie

现代web开发框架如vue.js、react.js等,在设计的时候就考虑了XSS攻击对html插值进行了更进一步的抽象、过滤和转义,我们只要熟练正确地使用他们,就可以在大部分情况下避免XSS攻击。

方法

1.字符串进行转义,防止xss攻击

/**
 *. 转义html(防XSS攻击)
 *. @param str 字符串
 */
function escapeHTML (str) {
    return     str.replace(
        /[&<>'"]/g,
        tag =>
            ({
                '&': '&amp;',
                '<': '&lt;',
                '>': '&gt;',
                "'": '&#39;',
                '"': '&quot;'
            }[tag] || tag)
    );
}

2.反之,转义字符替换,防止页面显示异常

function (string) {
  if (!string) return ''
  return string
    .replace(/&#34;/g, '"')
    .replace(/&#39;/g, "'")
    .replace(/&#40;/g, '(')
    .replace(/&#41;/g, ')')
    .replace(/&#42;/g, '*')
    .replace(/&#43;/g, '+')
    .replace(/&#44;/g, ',')
    .replace(/&#45;/g, '-')
    .replace(/&#46;/g, '.')
    .replace(/&#47;/g, '/')
    .replace(/&#58;/g, ':')
    .replace(/&#59;/g, ';')
    .replace(/&#60;/g, '<')
    .replace(/&#61;/g, '>')
    .replace(/&#95;/g, '_')
    .replace(/&#145;/g, '‘')
    .replace(/&#146;/g, '’')
    .replace(/&#147;/g, '“')
    .replace(/&#148;/g, '”')
    .replace(/ /g, '&nbsp;')
    .replace(/&gt;/g, '>')
    .replace(/&lt;/g, '<')
    .replace(/&quot;/g, '"')
     .replace(/&lsquo;/g, '‘')
    .replace(/&rsquo;/g, '’')
    .replace(/&ldquo;/g, '“')
    .replace(/&rdquo;/g, '”')
}

更多日常使用的公共类的操作方法,可以关注下小滑轮网站

转义字符

< &lt; &#60; 小于号

> &gt; &#62; 大于号

≤ &le; &#8804; 小于等于号

≥ &ge; &#8805; 大于等于号

" &quot; &#34; 引号

“ &ldquo; &#147; 左双引号

” &rdquo; &#148; 右双引号

‘ &lsquo; &#145; 做单引号

’ &rsquo; &#146; 右单引号