漫谈Web安全

当今互联网Web安全问题层出不穷,我们需要了解常见的安全问题和防范的手段,在开发的时候要注意相关的安全问题。

跨站脚本攻击(XSS)

跨站脚本攻击(Cross Site Scripting),简称XSS(因与CSS层叠样式表重名,改为XSS)。web漏洞中危害比较大排行靠前的漏洞。

原理

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

特点及危害

  • 挂马
  • 盗取用户Cookie
  • 钓鱼攻击、恶意篡改数据、嫁祸
  • js前端挖矿
  • ...

类别

反射型 XSS

  • 定义:XSS代码出现在URL中,提交给服务器后响应内容出现这段XSS代码,最后由浏览器解析执行。
  • 例子:
场景:从url中参数获取用户的来源,然后展现在网站头部的标题“欢迎来自xx的朋友”
预期:http://xx.com/?from=google, 从参数获取用户
服务端:ctx.render('index', {posts, comments, from:ctx.query.from || ''});
前端PUG模板:
    a.page-title(href="/")
        span 测试网站
        if from
            span - 欢迎来自!{from}的朋友
攻击者:
 http://xx.com/?from=<scripit>alert("执行恶意代码")</script>google   
复制代码

短链接能提升隐秘性

存储型 XSS

  • 定义:提交的XSS代码会存储在服务端,下次请求目标页面时不用再提交XSS代码,其攻击是最隐秘的
  • 例子:例如文章评论,攻击者提交一条包含XSS代码的评论存储到数据库,如果网站不做什么处理,直接显示,则访问这篇文章的用户都会受到XSS攻击。

DOM XSS

  • 与反射性XSS、存储型XSS的差别在于DOM XSS的代码并不需要服务器解析响应的直接参与,通过浏览器的DOM解析就可以进行触发。
  • 例子:
前端代码:
var hash = location.hash;
if(hash){
    var url = hash.substring(1);
    location.href = url;
}

攻击者:
 http://xx.com/#javascript:alert(1) // 使用Javascript伪协议进行攻击
复制代码
//常见的输入点
document.URL
document.location
document.cookie
window.location
window.name
...

// 常见的输出点
document.write()
document.writeln()
document.body.innerHTML
document.create
window.location.href
...
复制代码

常见的注入点

  • HTML节点内容

    • 节点内容是动态生成的,并且里面的内容包含用户的输入,可能输入脚本进行攻击
前端代码:
var hash = location.hash;
if(hash){
    document.getElementById('value').innerHTML = hash;
}
攻击者:
http://localhost/#<img src="1" onerror="alert(document.cookie)"
复制代码

HTML属性

  • 某个HTML的节点的某个属性是由用户输入决定的,用户的输入可能包含脚本或者跃出这个属性的范围而导致XSS攻击
前端代码:
<img src="/image/!{avatarId}"/>
攻击者:
http://localhost/?avatarId=1" onerror="alert(1)
复制代码

JavaScript代码

  • JS代码中存在由后台注入的变量,里面包含用户输入的信息,可能改变JS的逻辑,从而导致XSS攻击
前端代码:
let data="#{data}"
let data="hello";alert(1);"" //转义双引号
        script.
            var from="!{from}"
攻击者:
http://localhost/?from=google"alert(1);"
复制代码

富文本

  • 富文本带有很多的HTML代码

防治方法

  • 浏览器自带防御: 防御参数出现在HTML内容或属性上的反射型XSS,但不同浏览器的支持不一样,是一种有限的手段。Chrome等浏览器默认开启,可设置X-XSS-Protection强制开启,防止用户关闭检查。
ctx.set('X-XSS-Protection',1); // 可以通过设置header进行关闭,0为关闭,1为开启
复制代码

转义和过滤

  • 输入检查 用户输入的内容,过滤其中的特殊字符,如",',<,>,&
  • 输出检查 输出用户输入的内容时,对其中不含的特殊字段进行转义,如<转为&lt;,> 转为 &gt;
  • 谨慎使用eval,innerHTML等js方法或属性
  • 设立白名单 对于富文本,按白名单保留部分标签和属性
  • CSP

跨站请求伪造(CSRF)

跨站请求伪造(Cross-site request forgery),简称CSRF,关键点是跨站点的请求与伪造请求,挟持用户在当前已登录的Web应用程序上执行非本意的操作。其与XSS的概念很容易发生混淆,其与XSS的区别,可以通过知乎的一个例子了解:

===防盗系统启动===
妈妈: 给我看着衣服呀
小孩: 好的
===小偷来了===

===正常工作===
小孩: 你是谁?
小偷: 我是张三
小孩:妈妈,有人偷衣服
妈妈: 谁?
小孩: 张三
小偷被抓

===漏洞===
小孩: 你是谁?
小偷: 我叫逗你玩
小孩: 妈妈有人偷衣服呀
妈妈: 谁?
小孩: 逗你玩
妈妈: ...
========================================

csrf是让用户在不知情的情况下,冒用其身份发起了一个请求
小偷: 你妈妈喊你去买洗衣粉
复制代码

原理

特点及危害

  • 传播CSRF蠕虫
  • 篡改目标网站上的用户数据
  • 盗取用户隐私数据
  • 冒充用户发帖背锅
  • ...

类别

document.write(`
    <form name="commentForm" target="csrf" method="post"          action="http://localhost/post/addComment">
        <input name="postId" type="hidden" value="23">
        <textarea name="content">来自CSRF!</textarea>
    </form>`
);

var iframe = document.createElement('iframe');
iframe.name = 'csrf';
iframe.style.display = 'none';
document.body.appendChild(iframe);
setTimeout(function(){
    document.querySelector('[name=commentForm]').submit();

},1000);
复制代码

防治方法

  • Token

    • 生成一个随机字符串,存到前端表单,或者header请求头
  • 验证码

    • 提交需要填写验证码,但此操作对用户不太友好
  • 验证Referer

  • Cookie same-site

    • strict:任何跨域请求中都不会携带 cookie,能够完美的阻止 CSRF 攻击
    • lax:用 安全的 HTTP 方法(GET、HEAD、OPTIONS 和 TRACE)改变了当前页面或者打开了新页面,可以允许携带cookie

点击劫持(Clickjacking)

点击劫持,是指利用透明的按钮或链接做成陷阱,覆盖在 Web 页面之上。然后诱使用户在不知情的情况下,点击那个按钮或链接访问内容的一种攻击手段。

原理

  • 黑客创建一个网页利用 iframe 包含目标网站
  • 隐藏目标网站,使用户无法无法察觉到目标网站存在
  • 构造网页,诱使用户点击特定按钮
  • 用户在不知情的情况下点击按钮,触发执行恶意网页的命令

特点及危害

  • 获取用户敏感信息
  • 盗取用户
  • ...

防治方法

  • Javascript禁止内嵌

    • 可以利用top和self进行区分是否内嵌,但这种手段没法彻底防范CSRF攻击,攻击者可以使用IFrame的sanbox="allow-forms" 禁止js运行导致不起作用。
if(top !== self){             
    top.location.href = location.href;         
}
复制代码

X-FRAME-OPTIONS

ctx.set('X-Frame-Options','DENY')
复制代码

DENY:表示页面不允许在 frame 中展示,即便是在相同域名的页面中嵌套也不允许

  • SAMEORIGIN:表示该页面可以在相同域名页面的 frame 中展示
  • ALLOW-FROM url:表示该页面可以在指定来源的 frame 中展示

跨域资源共享(CORS)漏洞

CORS(Cross-Origin Resource Sharing),HTML5的一个新特性,用于解决浏览器跨域资源访问。在此之前,我们先说明一下SOP。

原理

同源策略

SOP(Same Origin Policy,同源策略),web最重要的安全策略,以同源为限制条件。同源策略,隔离了不同源网站的cookie,拦截不同源的请求,只允许同源网站的脚本运行,保证了web网站的安全。

  • 同源:相同的协议、端口和域名

CORS

W3C设计CORS协议标准,为了更安全规范地支持跨域网络资源共享,其在各大浏览器已经得到了很好地支持。

类别

CORS请求可以分为两类:简单请求(simple request)和非简单请求(not-so-simple request)

满足以下两大条件为简单请求

  • 请求方法是以下三种方法之一

    • HEAD
    • GET
    • POST
  • HTTP的头信息在以下字段之中

    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:限于三种值:Application/x-www-form-urlencoded multipart/form-datatext/plain

不同时满足两大条件为非简单请求

连接过程
  • 网站直接发起CORS请求,浏览器自动在每个跨域请求的头信息添加Origin字段,用来说明本次请求来源

  • 简单请求

    • 如果Origin值不在允许范围内,服务器会返回一个正常的HTTP Response,浏览器如果发现返回信息没有包含Access-Control-Access-Origin,会抛出错误
    • 如果在允许范围之内,添加几个字段
Access-Control-Allow-Origin
Access-Control-Allow-Credentials
Access-Control-Expose-Headers
复制代码

非简单请求

  • 先发出一个OPTIONS请求,判断所在的域名是否在服务器的允许范围,以及可以使用哪些HTTP方式和头信息字段。
Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Allow-Headers
复制代码

通过之后,其请求过程都跟简单请求一样

错误配置引起的攻击

场景:想要与多个域共享数据

方法:需要配置Access-Control-Allow-Origin,但Access-Control-Allow-Origin值的范围只能为*、null、<origin> ,以下配置是错误:

Access-Control-Allow-Origin: http://a.com, http://b.com  错误配置
Access-Control-Allow-Origin: http://*.a.com  错误配置
复制代码

<origin>只能配置单个域名,如果允许多个源的话,需要编写代码来动态生成访问控制策略,而在这个过程中很可能由于配置出现问题,导致网站遭受攻击。

  • 反射Origin头:发射请求的Origin值,导致信任所有来源的请求
  • Origin校验错误:慎用正则
前缀匹配:
    预期:a.com
    攻击者:a.com.danger.com

后缀匹配:
    预期:a.com
    攻击者:dangera.com
    
没有转义‘.’

    预期:www.a.com
    攻击者:wwwba.com
复制代码

信任null

  • 开发者在网站上配置信任null,用于与本地file页面共享数据,但是除了本地file页面的跨域请求Origin头为null外,攻击者可以从任意域通过iframe sanbox构造Origin为null的跨域请求。
<iframe 
    sandbox="allow-scripts allow-top-navigation allow-forms" 
    src="data:text/html,<script>XMLHttpRequest here</script>"
>
</iframe>
复制代码

HTTPS信任HTTP域

  • 中间人攻击
  • 信任自身全部子域

    • 所有鸡蛋放在一个篮子里。某个子域的XSS漏洞会危害其他所有子域
  • Origin:* 与 Credentials:true 共用

  • 缺少Vary:Origin头

    • 服务器需要在响应头中配置Vary:Origin头来指导缓存,为每个不同的Origin头缓存一份不同的内容,避免由于缓存导致CORS失效

特点及危害

  • 用户隐私泄露
  • 信息窃取
  • ...

防治方法

  • 不要盲目反射 Origin头
  • 严格校验 Origin 头,避免出现权限泄露
  • 不要配置 Access-Control-Allow-Origin: null
  • HTTPS 网站不要信任HTTP 域
  • 不要信任全部自身子域,减少攻击面
  • 不要配置 Origin:*和 Credentials: true
  • 增加 Vary: Origin 头

SQL注入(SQL Injection)

SQL注入攻击是通过将恶意的 SQL查询或添加语句插入到应用的输入参数中,再在数据库服务器上解析执行进行的攻击。

原理

===基本例子===
select * from table where id=${id}
传入数据:1 or 1=1
select * from table where id=1 or 1=1

===实际场景的注入===
select * from user where username='${data.username}' and password='${data.password}'
// 注入的攻击
输入http://localhost/post/23,获取id取得对应的文章
对应的sql语句:select * from post where id = "${id}"
攻击者:http://localhost/post/23" and 1=0 and ""="
结果构造的SQL语句:select * from post where id = "23" and 1=1 and ""="



=== SQL语句 ===
select * from table where id='1' and 1=0 //错误回显
select * from table where id='1' or 1=1
select * from table where id='1' and mid(version(),1,1)=5  //探测服务端信息
select 1,2,3 from table
select id,1,2,3 from table
select * from table union select 1,2,3 from table2 // 猜table2的列数
select * from table where mid(username,1,1)='t' // 猜测数据库内容
复制代码

常见的注入点:

  • SELECT columns
  • FROM table
  • WHERE expression
  • ORDER BY expression

特点及危害

  • 脱库
  • 读取或修改数据库中的内容
  • 通过存储过程执行系统命令和操作注册表
  • ...

防治方法

  • 关闭错误输出

  • 检查数据类型

  • 对数据进行转义

    • 对可能变为程序的字符进行转义
  • 参数化查询

    • 不管输入任何值,都将整个值作为参数的值,而不是原始 SQL 文本的一部分

安全防御

内容安全策略(CSP)

  • 定义

内容安全策略(Content Security Policy),用于指定哪些内容可执行,能够将各种子资源的加载限制到开发人员允许的一组源。

  • 实现方式:

    • 服务器添加 Content-Security-Policy 响应头来指定规则
    • HTML 中添加 标签来指定 Content-Security-Policy 规则
  • 预设值

Content-Security-Policy: default-src ‘self’;
复制代码

none 不匹配任何东西

  • self 匹配当前域,但不包括子域。比如 example.com 可以,api.example.com 则会匹配失败
  • unsafe-inline 允许内嵌的脚本及样式。对于页面中内嵌的内容也是有相应限制规则的
  • unsafe-eval 允许通过字符串动态创建的脚本执行,比如 eval,setTimeout 等

几条安全原则

  • 黑名单、白名单原则

    • 黑名单能够防止已知可能带来的威胁,但很难防范未知的危险
    • 白名单只有在规则内才可以使用,可以防范很多未知的危险,但是要基于白名单是完全可信任的前提
  • 最小权限原则

    • 只授予主体必要的权限,而不要过度授权,能有效减少出错的机会
  • 数据与代码分离原则

    • 将用户数据当作代码执行,可能导致安全问题
分类:
前端
标签: