再谈前端安全

知己知彼,百战不殆。 ——《孙子·谋攻》

引导

安全之路任重道远,特别随着智能手机的普及和移动互联网的发展,安全的关注点也慢慢转移到了前端。安全的焦点在于数据,除了数据,业务的任何部分都可以被取代。所以前端安全的关键仍然是保障数据的交互和传递安全

自从通过《web安全开发指南》和《web前端黑客技术揭密》等书籍,关于web前端安全的奇怪知识点确实增涨了不少,借此文持续记录核心部分并浅谈当代web前端安全的做法。

1.攻击

1.1 常见前端应用威胁

  • 1)代码注入:一个实体从中间人攻击(main-in-the-middle-attack)的形式将代码添加到服务器和客户端之间的数据流中。
  • 2)跨站脚本:攻击者将js脚本或其他可执行代码注入到应用程序的输出流中。攻击者想尽一切办法将你的脚本内容在目标网站中目标用户的浏览器上解析执行。
  • 3)跨站请求伪造:它的请求有两个关键点:跨站点的请求,请求时伪造的。伪造的定义很模糊,一般情况下我们可以认为:如果请求的发出不是用户的意愿,那么这个请求就是伪造的。
  • 4)界面操作劫持:比如通过在网页的可见输入控件上覆盖一个不可见的框(iframe),使得用户误以为在操作可见控件,而实际上用户的操作行为被其不可见的框所劫持。执行不可见框中的恶意劫持代码,从而完成在用户不知情的情况下窃取敏感信息、篡改数据等攻击。
  • 5)缓冲区溢出:攻击者试图将足够多的数据发送到缓冲区,以便让应用程序或输出缓冲区溢出,从而导致在缓冲区外的内存数据被损坏。

当然处理这五条外还有很多很多很多的应用威胁,在这就不一一例举了。

1.2 XSS(Cross-site scripting)跨站脚本

XSS有三类:

  • 反射型XSS(也叫非持久型XSS):发出请求时,XSS代码出现在URL中,作为输入提交到服务端,服务端解析后响应,在响应内容中出现这段XSS代码,最后浏览器解析执行。这个过程就像一次反射,故称为反射型XSS。反射型的XSS通常由服务端导致,如:

    1
    2
    3
    4
    // url: http://xss.example.com?name=<script>alert('chenie')</script>
    <?php
    echo $_GET["name"];
    ?>
  • 存储型XSS(页脚持久型XSS);与反射型XSS的区别仅在于提交的XSS代码是否会存储在服务端。存储型XSS会将提交的XSS代码存储在服务端(不管是数据库、内存还是文件系统等),是最隐蔽的。如某前端社区网站可以提交并存储代码,我提交了如下一个html代码:

    1
    <img src="/notfind.gif" onerror="alert(1)"/>

那么当他们访问这个html的效果的时候,不过不做处理则会触发弹窗。当然这类更容易出现在markdown中。

  • DOM XSS:它与以上两者的区别在于DOM XSS的XSS代码不需要服务器解析响应的直接参与,触发XSS靠的是浏览器端的DOM解析。如

    1
    2
    3
    4
    5
    6
    <!-- url: http://xss.example.com/#alert(1) -->
    ...
    <script>
    eval(location.hash.substr(1));
    </script>
    ...

早期浏览器有种利用编码的DOM XSS,有兴趣可访问《字符集编码及XSS》

危害

  • 挂马
  • 盗取用户信息,如cookie
  • Dos(拒绝服务)客户端浏览器
  • 钓鱼攻击,高级钓鱼技巧
  • 编写针对性的XSS病毒,删除目标文章、恶意篡改数据、嫁祸、”借刀杀人“
  • 劫持用户Web行为,甚至进一步渗透内网
  • 爆发web2.0蠕虫
  • 蠕虫式的DDoS攻击
  • 蠕虫式挂马攻击、刷广告、刷流量、破坏网上数据。。。

大致来看,危害上存储型XSS > 反射型XSS > DOM XSS。

DOM XSS常见的输入/输出点

输入点:

1
2
3
4
5
6
7
8
9
document.URL
document.URLUnencoded
document.location
document.referrer
window.location
window.name
xhr请求回来的数据
document.cookie
表单项的值

输出点:

直接输出HTML内容,如:

1
2
3
document.write(...)
document.writeln(...)
document.body.innerHtml = ...

直接修改DOM树,包括事件。如:

1
2
3
4
5
6
document.forms[0].action = ...(以及其他集合,如:一些对象的src/href属性等)
document.attachEvent(...)
document.create(...)
document.execCommand(...)
document.body, ...
window.attachEvent(...)

替换document URL。如:

1
2
3
4
5
6
document.location = ...
document.location.hostname = ...
document.location.replace(...)
document.location.assign(...)
document.URL = ...
window.navigate(...)

打开或修改新窗口。如:

1
2
3
document.open(...)
window.open(...)
window.location.href = ...

直接执行脚本。如:

1
2
3
4
eval(...)
window.execScript(...)
window.setInterval(...)
window.setTimeout(...)

CSRF(Cross Site Request Forgery),跨站请求伪造

按照攻击方式,CSRF可以分为

  • HTML CSRF攻击:HTML元素发出的,当然也包括动态标签生成。最普通的CSRF方式。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <!-- html -->
    <link href=""/>
    <img src=""/>
    <img srcset=""/><!-- html5 -->
    <img lowsrc=""/>
    <img dynsrc=""/>
    <meta http-equiv="refresh" content="0; url="/>
    <iframe src=""/>
    <frame src=""/><!-- html5不支持 -->
    <script src=""></script>
    <bgsound src=""/><!-- html5不支持 -->
    <embed src=""/>
    <video src=""></video><!-- html5 -->
    <audio src=""></audio><!-- html5 -->
    <source src=""/><!-- html5 -->
    <a href=""></a>
    <table background=""></table><!-- html5不支持 -->
    1
    2
    3
    4
    /* css */
    @import '';
    background: url('');
    background-image: url('');
  • JSON HiJacking攻击
    接口返回数据通常为json格式,当返回格式通过eval('(' + JSON_DATA + ')')时,就可能

  • Flash CSRF攻击(可忽略)

危害

  • 篡改目标网站上的用户数据
  • 盗取用户隐私数据
  • 作为其他攻击向量的辅助攻击手法
  • 传播CSRF蠕虫

界面操作劫持

p-1.jpg

它是一种基于视觉欺骗的Web绘画劫持攻击,所以有时候也称为UI伪装。

从技术发展阶段上分析,可以分为以下三种:

  • 点击劫持(Clickjacking):劫持用户的鼠标点击操作。主要的劫持目标是有重要会话交互的页面。
  • 拖放劫持(Drag&Drop jacking):拖放操作不受”同源策略“限制,用户可以把一个域的内容拖放到另一个不同的域。因此突破同源限制的拖放劫持可以演化出更广泛的攻击形式,突破很多种防御。
    比如劫持页面A

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <div>
    <p >将下面图片拖拽到矩形框中</p>
    <div class="rectangle">

    </div>
    <div class="img-container">
    <img id="img" src="logo.png" class="drop-img" alt="">
    </div>
    <iframe class="iframe" src="./dropAttack.html"></iframe>
    </div>
    </body>
    <script>
    var img = document.getElementById('img');
    img.ondragstart = e =>{
    e.dataTransfer.setData('info',document.cookie);
    }
    </script>

    攻击页面B

    1
    2
    3
    4
    5
    <script>
    document.getElementById('attackTarget').ondrop = e => {
    alert(e.dataTransfer.getData('info'))
    }
    </script>
  • 触屏劫持(Tapjacking):移动端类似点击接触的攻击模式。

其中点击/触屏劫持原理:透明层+iframe,拖放劫持原理:dataTransfer对象。
如劫持页面A

1
2
3
4
<iframe src="clickAttack.html" class="iframe"></iframe>
<button class="btn" onclick="alert('index')">
点击我
</button>

攻击页面B

1
2
3
<button class="btn" onclick="alert('attack')">
Attack
</button>

请求劫持

一般分为DNS劫持和HTTP劫持。

DNS劫持:

一般而言,用户上网的DNS服务器都是运营商分配的,所以,在这个节点上,运营商可以为所欲为。

例如,访问http://xxx.qq.com/index.html ,正常DNS应该返回腾讯的ip,而DNS劫持后,会返回一个运营商的中间服务器ip。访问该服务器会一致性的返回302,让用户浏览器跳转到预处理好的带广告的网页,在该网页中再通过iframe打开用户原来访问的地址。

HTTP劫持:

在运营商的路由器节点上,设置协议检测,一旦发现是HTTP请求,而且是html类型请求,则拦截处理。后续做法往往分为2种,1种是类似DNS劫持返回302让用户浏览器跳转到另外的地址,还有1种是在服务器返回的HTML数据中插入js或dom节点(广告)。

在用户角度,这些劫持的表现分为:

1、网址被无辜跳转,多了推广尾巴;
2、页面出现额外的广告(iframe模式或者直接同页面插入了dom节点)。

SQL注入

攻击者会修改由应用程序创建的查询,而这个查询是由用户或其他输入引起的,大部分SQL注入的情况是应用程序需要的是用于查询的数据,但它实际接收到的却是一些SQL片段。其他形式的SQL注入攻击与使用了转义字符或其他意想不到的字符或字符串有关。

cookie注入

实施:

  • 某些应用程序的功能在请求参数中使用一个名称和值,并在响应的cookie中设置该名称和值
  • 如果存在HTTP消息头注入漏洞,就可以利用此漏洞注入任意Set-cookie
  • 可以利用相关域中的XSS漏洞在目标域上设置一个cookie
  • 可以利用主动中间人攻击在任意域上设置cookie,即使目标应用程序仅使用HTTPS并将cookie标记为安全
  • 攻击目标用户:
    • 由于cookie通常仅由应用程序本身设置,因此它们会受客户端代码信任
    • 除将反CSRF令牌与用户会话关联外,一些应用程序还在cookie和请求参数中放置该令牌
    • 攻击者可以利用某个记录性XSS漏洞,通过针对登录功能的CSRF攻击使用户登录攻击者的账户
  • 会话固定:如果应用程序在用户首次访问时为每一名用户建立一个匿名会话,然后登录后该会话升级为通过验证的会话

小结:

  • 1.以上攻击通常都是成套使用,比如劫持和CSRF
  • 2.针对Web应用程序的最严重攻击,是那些能够披露敏感数据或获取对运行应用程序的后端系统的无限访问权限的攻击
  • 3.核心安全问题:用户可以提交做任意输入,应用程序必须假设所有输入的信息都是恶意的输入,并必须采取措施确保攻击者无法使用专门设计的输入破坏应用程序,干扰逻辑结构与行为

浏览器“漏洞”

比如比较典型的target="_blank"漏洞:

  • 1.你的网站上(https://example.com)有一个使用`target="_blank"`的链接

    1
    <a href="https://an.evil.site" target="_blank">Enter an "evil" website</a>
  • 2.一旦用户点击该链接并进入新标签页,并且新标签页的网页上有恶意代码,用户将直接被导航到虚假网站。
    网站可以通过HTTP标头的Referer属性确定用户的来源。并且网页中包含类似这样的代码:

    1
    2
    const url = encodeURIComponent('{{header.referrer}}');
    window.opener.location.replace('https://a.fake.site/?' + url);

此时用户继续浏览新选项卡,但原始的选项卡已经导航到https://a.fake.site/?https://example.com

2.原因分析

可靠性和安全性

软件越可靠,其不安全的风险越高。问题在于可靠性和安全性的不同目标之一。一个可靠的应用程序通常是可访问、可使用和可预期的,这会导致更多的安全问题。以下是可靠性与安全性有不同目标的一些例子。

  • 复杂的密码会让软件更加安全,但这意味着,当用户忘记密码时,软件可能变得不可用,从而使得软件不可靠。
  • 确保没人篡改应用数据的检查会导致当发现篡改时软件变得不可用。
  • 对安全性检查的误判会让应用程序的行为不可预测。
  • 管理安全性设置会增加应用程序界面的复杂度并令其可用性降低。
  • 由于安全限制(如某些政策的规定)拒绝对所需资源的访问会降低应用程序的可访问性并使其变得不可预测。

事实上,有很多安全性与可靠性严重对立的情况。你必须平衡两者,以确保应用数据保持合理的安全,且应用程序能可靠地运行。

在某些情况下,设计者可能不想要这种限制的潜在影响,并移除范围检查以使应用程序更可靠。毕竟,如果软件的目标是防止核反应堆出现危机,但软件却阻止输入能让反应堆免于出现危机的值,那软件的安全性就不再重要了,因为没有人会围绕该问题进行辩论。
处理这种情况的折中解决方案也是存在的,但它会增加软件的复杂度,并因此对可靠性造成更大影响。此外,因为折中解决方案需要增加编码,所以应用程序的速度也会受到影响。但是,在日常操作中包含各种类型的安全性检查并允许管理员重载以便在紧急时刻去除检查,用户就可以输入正确的值来挽救反应堆,但软件平时不会允许这样的输入。
关键是你通常找到的是只解决安全性或只解决可靠性难题的方案。只关注其中一个或另一个通常都不是好的做法,因为黑客(或用户)会让你在某些方面付出代价。

技术原因

从技术角度来分析,安全问题的原因通常如下:

  • 不成熟的技术安全体系
  • 独立开发
  • 欺骗性的简化
  • 迅速发展的威胁形势
  • 资源与时间限制,也包括了功能需求不断增加
  • 技术上强其所难

那么从web端的角度来说,我们首先要分析HTML/CSS/JavaScript的关键问题

定义HTML的关键问题

  • 代码注入:HTML5 里有大量黑客可用来注入恶意代码的方法,包括你通常不认为可疑的数据源。
  • 用户跟踪:因为大多数情况下应用程序使用了不同来源的代码,所以你可能会发现库、API 或微服务实际上执行了一些类型的用户跟踪,而黑客能利用其来获取公司信息。你给黑客的每一份信息都会让攻克系统安全变得更容易。
  • 污染输入:除非你提供自己的输入项检查,否则 HTML5会放行所有用户想要提供的输入。你可能只需要一个数字型的值,但用户可能输入一段脚本代码。尝试对输入进行彻底检测以确保真正得到你要求的输入数据,这在客户端近乎是不可能的,所以你还需要确保有强大的服务器端检查机制。

定义CSS的关键问题

  • 设计主导:CSS3 代码导致安全问题的一个主要原因是由设计来主导一切。问题在于CSS 的样式级联部分不允许 CSS3 知道除了其父节点之外的任何信息。因此,黑客能创建出一种声称要做某件事的界面,实际上却做着另外的事情。
  • 上传的 CSS:在某些情况下,应用程序的设计者会允许用户上传一份 CSS 文件来获得某一特定的应用外观或让其在一个特定的平台上运行得更加良好。但是,上传的 CSS 也可能包含一些代码,使得黑客更容易破坏设在各个地方的安全措施,或者在可见范围内隐藏脏东西。例如,黑客会在 CSS 里隐藏 URL,从而将应用重定向到不安全的服务器上。
  • CSS着色器:一种特殊的CSS用法,它允许访问浏览器数据和跨域数据,从而会产生一些极端的问题。重要的是要明白,有时候在屏幕上展现数据的行为会导致你最初未考虑到的潜在安全漏洞。

定义JavaScript的关键问题

  • 跨站脚本(XSS):只要你在沙盒环境之外运行JavaScript,黑客就有可能对你的应用程序做一些讨厌的动作。
  • 跨站请求伪造(CSRF):一段脚本能够利用保存在 cookie里的用户凭据来访问其他站点。在这些网站上,黑客能执行应用程序设计目的之外的各种任务。例如,黑客能以用户的名义,进行账户篡改、窃取数据、欺诈以及许多其他的违法活动。
  • 浏览器及其插件的漏洞:很多黑客会利用已知的浏览器及浏览器插件的漏洞来强迫应用程序执行其不应执行的任务。例如,用户的系统可能突然变成了向其他系统传送病毒代码的傀儡。黑客能够破坏的程度受限于相关的漏洞。一般来说,你要确保自己安装所有的更新,并要了解这些安全漏洞会如何影响应用程序的作业。

首先要考虑考虑端点的防御要素。端点是指网络传输的目的地,比如一个服务或一个浏览器。当数据包到达端点时,其包含的数据会被解包出来并提供给应用程序做进一步的处理。端点安全是至关重要的,因为端点是网络的一个主要入口点。除非端点是安全的,否则网络会接收到恶意的数据。此外,糟糕的端点安全性会对网络里的其他节点造成损害。接下来会讨论端点安全的三个阶段:预防检测修复

3.预防

避免安全陷阱的第一步是一开始就承认陷阱是存在的。你构建的所有应用程序必须足够可靠以实现以下功能:

  • 对抗普通的攻击
  • 在安全措施失效时发出警报
  • 避免对可能会发生漏洞的地方做出假设
  • 要假设即使是受过训练的用户也会犯导致安全事故的错误。

3.1 防御机制

关于角色与平台可分为如下几个方面

处理用户访问

三层相互关联的安全机制

  • 身份验证:确定用户身份;
  • 会话管理:基本取决于其令牌的安全性;
  • 访问控制:应用程序从收到的每一个请求来确认用户身份,并决定授权用户执行其所请求的操作或访问相关数据

处理用户输入

输入处理方法

  • “拒绝已知的不良输入”:黑名单关键字法、效率最低、效果一般,如SELECT绕过Select
  • “接受已知的正常输入”:白名单,确认机制接受任何与白名单匹配的数据
  • 净化:删除恶意字符或对其适当编码或“转义”
  • 安全数据处理:可使用安全的编程方法,如参数化查询(PDO)等
  • 语法检查:

边界确认:

  • 服务器端应用程序的每一个单独的组件或功能单元将其输入当做来自潜在恶意亚涛的输入对待。除客户端和服务器之间的外部边界外,应用程序在上述每一个信任边界上执行数据确认。

处理攻击者

  • 1.处理错误
    • 生产环境下,应用程序不应在其响应中返回任何系统生成的消息或其他调试信息
  • 2.维护审计日志
    • 所有与身份验证有关的事件,如成功或失败的登录、密码修改等
    • 关键交易,如信用卡支付与转账
    • 被访问控制机制阻止的访问企图
    • 任何包含已知攻击字符串,公然表明恶意意图的请求
  • 3.向管理员发出警报
    • 应用反常:如一个IP或用户发出的大量请求
    • 交易反常:如资金数量异常
    • 包含已知攻击字符串的请求
    • 请求中普通用户无法查看的数据被修改
  • 4.应对攻击:高效的输入确认机制、自动反应措施(如终止异常会话等)

管理应用程序

  • 1.身份验证机制中存在的薄弱环节
  • 2.应用程序并不对它的一些被管理功能执行有效的访问控制
  • 3.管理功能通常能够显示普通用户提交的数据
  • 4.管理用户往往没有经过严格的安全测试

3.2 防御XSS攻击

针对第一节可能发生XSS攻击的输入风险点进行监控和预防处理。

1.防止反射型与保存型XSS漏洞

用户可控制的数据未经适当确认与净化就被复制到应用程序的响应中,这是造成反射型与保存型XSS漏洞的根本原因。因此我们需要保障:确认输入;确认输出;消除危险的插入点;

  • 确认输入:数据不是太长;数据仅包含某组合法字符串;数据与一个特殊的正则表达式相匹配;encode(encodeURI/encodeURIComponent)
  • 确认输出:首先最通用普遍的做法是转义输出(也包括输入)的内容,包括"'

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ``` js
    function escape(str) {
    str = str.replace(/&/g, '&amp;');
    str = str.replace(/</g, '&lt;');
    str = str.replace(/>/g, '&gt;');
    str = str.replace(/"/g, '&quto;');
    str = str.replace(/'/g, '&#39;');
    str = str.replace(/`/g, '&#96;');
    str = str.replace(/\//g, '&#x2F;');
    }

  • 消除危险的插入点:应尽量避免直接在现在的JS中插入用户可控制的数据;如果标签属性接受URL作为它的值,应用程序应避免嵌入用户输入;如果攻击者通过插入一个相关指令,或者因为应用程序使用一个请求参数指定首选的字符集,因而能够控制应用程序响应的编码类型,这些情况也应该加以避免。

    • 允许有限的HTML:仅允许有限的HTML子集,避免提供任何引入脚本代码的方法。采用白名单。

输入与输出确认机制应特别小心,尽量避免任何可能导致攻击者避开确认的漏洞,应在实施相关规范化后再对数据进行过滤与编码,而且之后不得对数据实施进一步的规范化,还必须保证其中存在的空字节不会地它的确认造成干扰。

其实XSS很难防,像输入确认里我们很难做类似如下这种校验:

1
[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()

它其实结果也是alert(1)

因此我们需要根据业务场景做大量测试和校验。

启用严格模式

严格模式对 JavaScript 的操作方式做了许多明显的和微小的改变。重要的是使 JavaScript 应用的调试变得更简单,因为你的 JavaScript 应用程序如今会在遇到问题时报错,而不是悄悄地失败并表现出怪异的行为。这意味着过去常常无故死掉的奇怪的库调用现在会告诉你相关问题的信息。以下是严格模式可帮你解决的主要问题。

  • 消除对 with 的使用
  • 防止错误变量
  • 不允许强制多态使用 this
  • 阻止重名
  • 对不可变值的改变会发出通知
CSP(Content Security Policy)内容安全策略

内容安全策略 (CSP) 是一个额外的安全层,用于检测并削弱某些特定类型的攻击,包括跨站脚本 (XSS) 和数据注入攻击等。无论是数据盗取、网站内容污染还是散发恶意软件,这些攻击都是主要的手段。

CSP 的主要目标是减少和报告 XSS 攻击 ,XSS 攻击利用了浏览器对于从服务器所获取的内容的信任。CSP通过指定有效域——即浏览器认可的可执行脚本的有效来源——使服务器管理者有能力减少或消除XSS攻击所依赖的载体。一个CSP兼容的浏览器将会仅执行从白名单域获取到的脚本文件,忽略所有的其他脚本 (包括内联脚本和HTML的事件处理属性)。

作为一种终极防护形式,始终不允许执行脚本的站点可以选择全面禁止脚本执行。

CSP 被设计成完全向后兼容,不支持CSP的浏览器也能与实现了CSP的服务器正常合作,反之亦然:不支持 CSP 的浏览器只会忽略它,如常运行,默认为网页内容使用标准的同源策略。如果网站不提供 CSP 头部,浏览器也使用标准的同源策略

csp兼容情况如下图:
csp-compatibility.jpg

使用

为使CSP可用, 你需要配置你的网络服务器返回 Content-Security-Policy HTTP头部。

头部包含三个基本要素:策略名数据类型数据源

比如:

只允许加载本站资源:

1
Content-Security-Policy: default-src ‘self’

只允许加载 HTTPS 协议图片:

1
Content-Security-Policy: img-src https://*

允许加载任何来源框架:

1
Content-Security-Policy: child-src 'none'

除此之外, <meta/> 元素也可以被用来配置该策略, 例如

1
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">

3.3 防御CSRF

针对第一节可能发生CSRF攻击的风险点进行监控和处理。防范 CSRF 可以遵循以下几种规则:

  1. Get 请求不对数据进行修改
  2. 不让第三方网站访问到用户 Cookie
  3. 阻止第三方网站请求接口
  4. 请求时附带验证信息,比如验证码或者 token

SameSite

可以对 Cookie 设置 SameSite 属性。该属性设置 Cookie 不随着跨域请求发送,该属性可以很大程度减少 CSRF 的攻击,但是该属性目前并不是所有浏览器都兼容。

验证 Referer

对于需要防范 CSRF 的请求,我们可以通过验证 Referer 来判断该请求是否为第三方网站发起的。

Token

服务器下发一个随机 Token(算法不能复杂),每次发起请求时将 Token 携带上,服务器验证 Token 是否有效。

3.4 防御信息泄露

防御请求劫持

  • 1.https比http安全
  • 2.敏感信息用post

防御信息丢失

  • 1.url中不要带有敏感信息。比如通过A页面跳到钓鱼的B页面,目的页面B将通过 referrer 获取到A页面的url,如果A页面url中带有重要信息的话就尴尬了。当然为了防止 referrer 值泄露,我们可以将请求头 Referer-Policy 标志为no-referrer,如
    1
    Referer-Policy no-referrer

防御劫持攻击

禁用iframe,或 X-Frame-Options,或frame-ancestors。

3.4 防御SQL注入

SQL 注入攻击有多种形式。例如,你会处理应用程序中的表单数据来确定该表单是否能够发送命令到后端服务器。但是,最好是首先有一个检查潜在 SQL 注入攻击的通用方法。

假设你有一个像 http://www.mysite.com/index.php?itemid=10 这样的 URL。你会在很多网站上看到类似结构的 URL。检查漏洞的一个方法是简单地在 URL 后面加上一个单引号,使其成为 http://www.mysite.com/index.php?itemid=10'。当你按下回车,网站会发送回一段SQL 错误消息。这个消息会根据系统有所不同,关键是后端服务器会接收你的 URL 作为SQL 请求,它会被拼成类似这样的格式:SELECT * WHERE itemid=’10’’。多出来的单引号会使查询不合法,从而产生错误。

你现在可以开始操作 URL 来看看会发生什么。例如,你想看看查询会产生多少列数据以及这些列都是什么。可以使用 ORDER BY 这样的 SQL 语句来执行这一任务。改变一下 URL使其包含 ORDER BY 语句,就像这样:http://www.mysite.com/index.php?itemid=10‘ ORDER BY 1。这与输入 SELECT * WHERE itemid=’10’ ORDER BY 1 这样的命令是一样的效果。通过在每次请求中给 ORDER BY 的值加 1,你最终会看到一个错误。假如当你尝试到 ORDER BY 10 时看到了错误,那么可以确定在这个例子中请求会产生 9 列数据。黑客会继续在 URL 中加入 SQL 命令来了解更多数据库的查询结果。例如,使用 SELECT 语句可以帮你确定哪些数据会出现在屏幕上。你也可以请求特殊的信息作为 SELECT 语句的一部分,比如使用 @@version 来获得 SQL 服务器的版本号(会给你一些关于该 SQL 服务器可能存在缺陷的信息)。这里的关键是原始的 URL 可以直接访问 SQL 服务器,使得别人完全不需要做太多工作就可以控制 SQL 服务器。
你可以在网页 http://www.w3schools.com/sql/sql_injection.asp 上看到另一种 SQL 注入攻击。这些攻击根本的原因是开发人员直接使用来自页面或请求中的数据,而没有首先检查其是否有问题并将错误信息移除。

部分有效的防御措施

  • 将用户输入中的任何单引号配对并对它们转义
  • 使用存储过程

参数化查询

  • 应用程序指定查询结构,为用户输入的每个数据预留占位符
  • 应用程序指定每个占位符内容
  • 应当每一个数据库查询中使用参数化查询
  • 插入查询中每一种数据都应适当进行参数化
  • 参数占位符不能用于指定查询中表和列的名称
  • 参数占位符不能用于查询的任何其他部分,如ORDER BY或任何SQL关键字,因为它们属性查询结构的一部分

深层防御

  • 当访问数据库时,应用程序应尽可能使用最低权限的帐户
  • 许多企业数据库包含大量默认功能,可被能够执行任意SQL语句的攻击者利用
  • 应评估、测试并及时安装供应端发布的所有安全补丁

3.5 会话校验

攻击会话管理

状态要求

1.执行会话最简单、最常见的方法就是向每名用户发布一个唯一的会话令牌或标识符。用户在随后向应用程序提出的每一个请求中提交这个令牌。大多数情况下使用Cookie

2.存在的主要漏洞:

  • 会话令牌生成过程中的薄弱环节
  • 在整个生命周期过程中处理会话信息的薄弱环节

3.会话替代方案:HTTP验证(基本、摘要、NTLM验证等)、无会话状态机制

会话令牌生成过程中的薄弱环节

1.令牌有一定含义

2.令牌可预测

  • 隐含序列
  • 时间依赖
  • 生成的数字随机性不强
  • 测试随机性强度:Burp Sequencer

3.加密令牌

  • ECB密码:对称加密算法,明文分组与密文分组完全对应,
  • CBC密码:在加密每个明文分组前,将它与前一个密文分组进行XOR运算(DES和AES)

会话令牌处理中的薄弱环节

1.在网络上泄露令牌

  • 在登录阶段使用HTTPS但在会话其他阶段使用HTTP
  • 在站点中预告通过验证的区域(如首页)使用HTTP,但从登录页开始转换到HTTPS,很多情况下应用程序在用户访问时就给予令牌,而且登录后也不会修改
  • 用户对URL修改仍能通过HTTP进行登录
  • 静态内容使用HTTP

2.在日志中泄露令牌

3.令牌-会话映射易受攻击

  • 允许同一个用户账户同时分配几个有效的令牌
  • 静态令牌

4.会话终止易受攻击

  • 应用程序不执行退出功能
  • 仅删除了cookie

5.客户端暴露在令牌劫持风险之中

  • 跨站脚本攻击查询用户cookie
  • 跨站请求伪造(CSRF)

6.宽泛的cookie范围

保障会话管理的安全

1.生成强大的令牌

  • 使用数量极其庞大的一组可能值
  • 包含强大的伪随机源,确保令牌以无法猜测的方式平均分布在可能值范围内
  • 合并一些信息作为熵源:来源IP及接收请求的端口号、请求中的User-Agent消息头、请求时间(毫秒)
  • 使用适当的散列算法(SHA-256等)

2.在整个生命周期保障令牌安全

  • 令牌只能通过HTTPS传送,最好全站HTTPS,如不行,cookie加上secure标识,将敏感内容的请求重定向到HTTPS
  • 绝不能在URL中传送会话令牌
  • 应总是执行退出 功能
  • 会话牌非活动大癫大废一段时间后,应执行会话终止
  • 应防止并行登录,一名用户登录就发布一个新令牌并废止其他属于该用户的令牌
  • 如果应用程序包含任何可以查看会话令牌的管理或诊断功能,应对这种功能加以严密保护,以防止未授权的访问
  • 应尽可能限定应用程序会话cookie的域和路径范围
  • 应严格审查应用程序的代码库,以确定并删除任何跨站点脚本漏洞
  • 不应接受用户提交,但服务器并不认可的任意令牌
  • 在执行转账之类的重要操作之前,要求进行两步确认或重新验证可有效防御跨站点请求伪造和其他会话攻击
  • 不完全依赖HTTP cookie传送会话令牌
  • 成功验证后总是建立一个新的会话

3.每页面令牌

  • 每次用户请求一个页面,都会建立一个新的页面令牌
  • 会给“前进”“后退”等导航造成影响

4.日志、监控与警报

p-6.jpg

  • 应用程序应监控包含无效令牌的请求
  • 很难完全阻止针对会话令牌的蛮力攻击,在收到大量包含无效令牌的请求时将其来源IP屏蔽一段时间
  • 即使无法立即有效防止针对会话的蛮力攻击,但保留详细的日志并向管理员发出警报仍然有用
  • 只要有可能,应向用户警告与会话有关的反常事件

5.反应性会话终止

  • 只要收到反常请求,就马上终止会话

3.6 密码和信息校验

p-2.jpg

单从输入密码的角度来说,安全的预防主要是提高密码格式的安全性和加密两种方式。关于加密的话由于内容太多就不一一展开。

这里特别讲一下非输入密码的校验。用户不想要输入密码来访问或使用应用程序的某些功能。
遗憾的是,你仍然需要一些方法来确定用户的身份。接下来描述了一些成熟的方案(你如今可以实现的),这有助于你找到最合适的解决方案。

使用口令

p-3.jpg

口令是一种部分可读的语句。你可以组合字母、数字以及特殊字符,让密码更复杂。例如,你可以创建一个I love flowers这样的口令。这一口令包含了大写和小写字母、数字以及特殊字符。它能对抗字典和其他常用的暴力攻击。它可能会比多数用户采用的密码长。但是,其仍然很好记。用户不需要把口令写下来。

今天的用户确实有理由抱怨他们需要记住的密码的长度。一种可以考虑的作为解决方案的技术是密码保险箱。密码保险箱能以一种安全的方式保存大量用户密码,可让用户继续使用复杂的密码。

使用生物识别的方案

p-4.jpg

  • 指纹
  • 虹膜
  • 声纹

这三种解决方案都有缺陷,黑客有攻克它们的方法,所以你可能要选择另一种生物识别方案或将其中一种与其他认证方式结合使用。相关供应商有一些正在开发中的生物识别替代方案,下面描述了其中的一些。

  • 心跳:一个更有趣的生物识别替代方案是结合带分析算法的心率监视器。
  • 人脸识别
  • 耳形
  • 输入识别技术:每个人都有不同的输入方式。打字的速度、按住键的时间,甚至是输入字母的间隔,都能识别出作为打字者的你。通过输入一段特定的语句并监控你如何输入,应用程序可创建一种双因素认证,这与只是输入密码并没有什么不同。但是,现在黑客窃取到密码后仍然用不了它。

为什么使用双因素认证:大多数单因素认证方案的问题在于它们有一个很容易被利用的弱点。例如,黑客可通过社会工程学的攻击或是暴力来窃取密码或口令。通过使用双因素认证,可以降低认证过程被攻克的风险。当然,有人会说三因素或四因素认证会更好,但那样会导致没有人能登录进自家账号的情况。有很多类型的双因素认证。例如,你可以给用户一个密码和一个令牌。你还可以将密码与生物特征识别方案结合起来。许多银行目前就使用了双因素认证。

*依靠钥匙卡

个人电脑也会使用钥匙卡技术。你能用它来控制对整个个人电脑的访问,或者控制对某个应用程序的访问。当用于访问某个应用程序时,开发人员需要开发读取卡信息的代码,检测其有效性,并认证用户。
使用钥匙卡的主要优点是,它能提供复杂的密码及潜在的其他细节来帮助识别用户。为了防范黑客,密码可以设得尽可能复杂。根据所使用的技术,你甚至可以很容易地改变钥匙卡的信息,所以密码的更改操作不会有太高的成本。钥匙卡通常也比较大,用户不会经常弄丢(虽然你可以预见有些用户至少会把一些钥匙卡忘在什么地方)。因为该技术由来已久,所以比起其他安全解决方案,钥匙卡的成本相对比较低。用户也比较倾向于选择钥匙卡(丢失时除外),因为它们比较快且易于使用。
钥匙卡的主要缺点是用户会忘记将其放在哪里或遗忘在家里。丢失的钥匙卡能为黑客提供对公司造成真正损害的入侵机会。即使只是把钥匙卡遗忘在家里,提供一张临时卡也是种额外的支持开销。当然,还有在用户不再需要时回收临时钥匙卡的问题。

*依靠USB key

USB key 实质上是一个包含一个或多个密码或令牌的闪存驱动器。你将 USB key 插入电脑并启动,电脑会使用其中的数据登录系统。同一个 key 中可以包含访问多个应用程序的多个密码。应用程序需要识别 key 中的密码,但该技术可以实现在不输入密码或任何其他信息的情况下登录应用程序。

与钥匙卡相比,USB key 有以下显著的优点:

  • 不需要获取新的 USB key 就能更改密码
  • 能包含多个密码
  • 总体成本低于使用钥匙卡
  • 可以升级各类凭据
    当然,USB key 有许多与钥匙卡类似的缺点。例如,用户不管是丢失了钥匙卡还是 USB key,结果都是相同的,该用户不再能登录应用程序而其他人可以。事实上,由于 USB key比钥匙卡小,因此用户会更有可能丢失 USB key,并且泄露的不仅仅是一个密码。

实现令牌策略

你通常会用智能手机来实现一套令牌策略。
在大部分情况下,在双因素认证系统中,应用程序会将令牌作为第二认证方式。第一认证方式仍然是钥匙卡、生物学特征、密码或口令。从理论上说,如果愿意,你也可以将令牌作为主认证方式。比起其他认证方法,这种方式会带来以下这些你需要解决的问题。

  • 用户需要一直将智能手机带在身边。
  • 丢失手机可能会损害作为登录应用程序方式的令牌系统。
  • 该方案只能用于登录除智能手机外的设备,而如今的用户在可能的情况下都想使用智能
    手机而不是其他电脑设备。
  • 用于用户登录的计算机需要有接收令牌所需的设备。

攻击验证机制

验证技术
  • 1.基于HTML表单的验证
  • 2.多元机制,如组合型密码和物理令牌
  • 3.客户端SLL证书或智能卡
  • 4.HTTP基本和摘要验证
  • 5.使用NTLM或Kerberos整合Windows的验证
  • 6.验证服务

验证机制设计缺陷

1.密码保密性不强

  • 非常短或空白的密码
  • 以常用的字典词汇或名称为密码
  • 密码和用户名完全相同
  • 仍然使用默认密码

2.蛮力攻击登录:如果应用程序允许使用者使用不同的密码重复进行登录尝试,直到找到正确的密码,那么它就非常容易遭受攻击

3.详细的失败消息

4.证书传输易受攻击

  • 如果以查询字符串参数、而不是在POST请求主体中传送证书,许多地方都可能记录这些证书
  • 虽然大多数Web应用程序确实使用POST请求主体提交HTML登录表单,但令人奇怪的是,应用程序常常通过重定向到一个不同的URL来处理登录请求,而以查询字符串的形式提交证书
  • Web应用程序有时将用户证书保存在cookie中,通常是为了执行设计不佳的登录、密码修改、“记住我”等机制

5.密码修改功能

  • 提供了详细的错误信息,说明被请求的用户名是否有效
  • 允许攻击者无限制猜测“现有密码”字段
  • 在验证现有密码后,仅检查“新密码”与“确认新密码”字段的值是否相同,允许攻击者不需入侵即可成功查明现有密码

6.忘记密码功能

  • 忘记密码功能常常向用户提出一个次要质询以代替主要登录功能,用户可能设置极不安全的质询问题
  • 与密码修改功能一样,即使应用程序开发者在主登录页面阻止攻击者向密码恢复质询的响应发动蛮力攻击,他们也往往会在忘记密码功能中忽略这种攻击的可能性
  • 一些应用程序 使用一个简单的密码“暗示”代替恢复质询
  • 在用户正确响应一个质询后,应用程序即允许用户重新控制他们的账户,这种机制非常容易遭受攻击
  • 一些应用程序允许用户在成功完成一个质询后直接重新设置密码,并且不向用户发送任何电子邮件通知

7.“记住我”功能

  • 一些“记住我”功能通过一个简单的cookie执行
  • 一些“记住我”功能设置一个cookie,其中并不包含用户名,而是使用一个持久会话标识符
  • 即使cookie中保存的用于重新识别用户的信息得到适当的你别担心,以防止其他用户对此进行推断或猜测,但攻击者通过跨站点脚本之类的漏洞或本地访问的用户计算机依然可以轻易获得这些信息

8.用户伪装功能

  • 伪装功能可以通过“隐藏”功能的形式执行,不受常规访问控制管理
  • 当判定用户是否进行伪装时,应用程序可能会信任由用户控制的数据
  • 如果应用程序允许管理用户被伪装,那么伪装逻辑中存在的任何缺陷都可能导致垂直权限提升漏洞
  • 某种伪装功能能够以简单“后门”密码的形式执行,该密码可和任何用户一起向标准登录页面提交,以作为该用户进行验证

9.证书确认不完善(密码)

10.非唯一性用户名

11.可预测的用户名:一些应用程序根据某种规则自动生成用户名

12.可预测的初始密码:一些应用程序一次性或大批量创建用户,并自动指定初始密码,然后以某种方式将密码分配给所有用户

13.证书分配不安全

验证机制执行缺陷

1.故障开放登录机制:由于某种原因产生异常但用户仍然登录成功,虽然产生的会话可能并不属于某个特殊的用户,但仍然可以通过这种方法访问一些敏感数据或功能

2.多阶段登录机制中的缺陷

  • 执行多次验证检查可能会显著提高登录机制的安全性,但相应地,这个过程也存在更多的执行缺陷。
  • 应用程序可能认为访问第三阶段的用户已经完成第一、第二阶段的验证,因此,它可能允许直接由第一阶段进入第三阶段并且提供正确证书的攻击者通过验证
  • 应用程序可能会信任由第二阶段处理的一些数据,但攻击者能够在第二阶段操控这些数据,提供一个不同于第一阶段的值
  • 应用程序可能认为每个阶段的用户身份不会发生变化,因此,它并不在每个阶段明确确认用户身份
  • 如果有数据不止提交一次,深度在另一个阶段提交一个不同的值,看看是否仍然能够成功登录
  • 特别注意任何通过客户端传送、并不由用户直接输入的数据

3.不安全的证书存储

  • 明文存储密码
  • 简单加密

保障验证机制的安全

1.考虑:

  • 应用程序所提供功能的安全程度
  • 用户对不同类型的验证控制的容忍和接受程度
  • 支持一个不够友好的用户界面系统所需的成本
  • 竞争性解决方案相对于应用程序可能产生的收入方面的金融成本或它所保护资产的价值

2.使用可靠的证书

  • 应强制执行适当的最小密码强度要求
  • 应使用唯一的用户名
  • 系统生成的任何用户名和密码应具有足够的随机性
  • 允许用户设置足够强大的密码

3.安全处理证书

  • 应以不会造成非授权泄露的方式创建、保存和传送所有证书
  • 应使用公认的加密技术保护客户端与服务器间的所有通信
  • 如果认为最好在应用程序的不需验证的区域使用HTTP,必须保证使用HTTPS加载登录表单,而不是在提交登录信息时才转换到HTTPS
  • 只能使用POST请求向服务器传输证书
  • 所有服务器-客户端应用程序组件应这样保存证书:即使攻击者能够访问应用程序数据库中存储的所有相关数据,他们也无法轻易恢复证书的原始值
  • 客户端“记住我”功能应仅记忆如用户名之类的非保密数据
  • 应使用一种密码修改工具,要求用户定期修改其密码
  • 如果以非正常交互的形式向新建账户分配证书,应以尽可能安全的形式传送会话,并设置时间限制,要求用户在第一次登录时更改证书,并告诉用户在初次使用后销毁通信渠道
  • 应考虑在适当的地方使用下拉菜单而非文本字段截取用户的一些登录信息

4.正确确认证书

  • 应确认完整的密码
  • 应用程序应在登录处理过程中主动防御无法预料的事件
  • 应对验证逻辑的伪代码和实际的应用程序源代码进行仔细的代码审查,以确定故障开放条件之类的逻辑错误
  • 如果应用程序执行支持用户伪装功能,应严格控制这种功能,以防止攻击者滥用它获得未授权访问
  • 应对多阶段登录进行严格控制,以防止攻击者破坏登录阶段之间的转换关系
  • 如果在登录过程中需要回答一个随机变化的问题,请确保攻击者无法选择回答的问题

5.防止信息泄露

  • 应用程序使用的各种验证机制不应通过公开的消息,或者通过从应用程序的其他行为进行推断
  • 应由单独一个代码组件使用一条常规消息负责响应所有失败的登录尝试
  • 如果应用程序实行某种账户锁定以防止蛮力攻击,应小心处理以防造成信息泄露
  • 如果应用程序支持自我注册,那么它能够以两种方式防止这种功能被用于枚举现有用户名:不允许自我选择用户名、可以使用电子邮件地址作为用户名

6.防止蛮力攻击

  • 必须对验证功能执行的各种质询采取保护措施,防止攻击者企图使用自动工具响应这些质询
  • 使用无法预测的用户名,同时阻止用户名枚举
  • 一些对安全性要求极高的应用程序在检测到少数几次登录失败后应立即禁用该账户
  • 使用验证码进行人机质询

7.防止滥用密码修改功能

  • 应用程序应始终执行密码修改功能,允许定期使用的密码到期终止并允许用户修改密码
  • 只能从已通过验证的会话中访问该功能
  • 不应以任何方式直接提供用户名,也不能通过隐藏表单字段或cookie提供用户名
  • 作为一项高级防御措施,应用程序应对密码修改功能加以保护,防止攻击者通过其他安全缺陷,如会话劫持漏洞、跨站点脚本,甚至是无人看管的终端获得未授权访问
  • 为防止错误,新密码应输入两次
  • 该功能应阻止可能针对主要登录机制的各种攻击
  • 应使用非常规方式通知用户其密码已被修改,但通知消息不得包含用户的旧证书或新证书

8.防止滥用账户恢复功能

  • 当用户遗忘密码时,许多安全性至关重要的应用程序通过非常规方式完成账户恢复
  • 精心设计的密码恢复机制需要防止账户被未授权方殹 ,避免给合法用户造成任何使用中断
  • 绝对不要使用密码“暗示”之类的特性
  • 通过电子邮件给用户发送一个唯一的、具有时间限制的、无法猜测的一次性恢复URL是帮助用户重新控制账户的最佳自动化解决方案

9.日志、监控与通知

  • 应用程序应在日志中记录所有与验证有关的事件
  • 应用程序的实时警报与入侵防御功能应对验证过程中的异常事件进行处理
  • 应以非常规方式向用户通报经常发生的安全事件

3.7 三方库/api

fe.png

关于三方库最近比较出名的就是去年lodash的安全漏洞,可访问《Lodash库爆出严重安全漏洞,波及400万+项目》

调研三方库

任何时候你选择将一个库添加进自己的应用程序中,就展示了对库作者的信任。即使有称职的安全专家的帮助,将一个库拿出来并对其每一处的代码进行测试(假设能得到完整的代码)会花费比从头开发库更多的时间。(确保你拿到的不是压缩版的库,不然会很难检查,因为供应商移除了空白字符。)因此,你必须考虑将这个库作为你创建的应用程序解决方案的一部分,带来的风险是否足够小。当研究一个库时,考虑一下以下问题。

  • 行业杂志是否以负面的方式讨论过这个库?(如果这个库有已知的未解决的安全漏洞,你可能需要重新考虑是否将其用于自己的应用程序中。)
  • 是否有其他公司使用了该库且没有问题?
  • 开发这个库的公司在回答关于库的完整性问题时是否是积极的?
  • 创建这个库的公司是否提供了一致的 bug 修复和更新?
  • 人们在这个库的在线支持中问了哪些问题?
  • 这个库存在了多长时间?(存在时间很长的库通常问题更少,并且创建者的支持工作也做得更好。)

精确定义库的使用

没有人会使用应用程序中每个库的每个功能。有些研究网站宣称开发人员只会使用库的一个或两个功能。用文档记录你要如何使用一个库,可将注意力聚焦在相关部分,从而帮你规避使用库所带来的风险。更重要的是,跟踪具体的使用部分能告诉你何时必须执行一次更新,或如何通过移除用不到的功能来缩小库的规模。对于如何使用库来执行特定的应用任务了解得越多,就越能降低使用它时的风险。

处理三方库

外部库带来了许多有趣的可靠性问题。

提升使用外部库可靠性的最好方式之一就是将库下载到本地磁盘并使用这一副本,而不是直接使用供应商网站上的副本。

一个折中的方案是将库代码下载到本地,持续跟踪库的更新,并为应用程序安排更新的时间,以便让你所使用的主要库与所需的安全及特性更新保持一致。这就意味着要按你的时刻表执行更新,而不是按供应商的时刻表。虽然这一方案看起来是一个完美的解决方案,但其实并不是。黑客常常依靠零日(zero-day)攻击对最多数量的应用程序造成最大的伤害。因为你的应用程序不会自动更新,所以你还要面对发生灾难性的零日攻击的可能性。

保持库的小规模和内容聚焦

只要有可能,就应将第三方库保持在小规模且聚焦于特定的需求。这意味着你要移除你不会使用的代码,因为这些代码会制造以下问题。

  • 拖慢下载速度
  • 增加安全问题
  • 降低可靠性
  • 导致不必要的更新

使用构建器意味着你创建的库只包含你确实需要的元素。当然,其缺点是你必须提供对这个库的维护,这意味着当作者有更新时你得不到自动的更新。如果你选择了这一方案,关键是要定期检查是否有更新库的需要。

保持更新

处理外部API

解决这种情况下的可靠性问题的一个方法是为调用计时。当应用程序检测到调用花费的时间比平时长,它就有可能给出一些反馈,比如告诉用户连接比较慢、联系管理员或以某些其他方式对问题作出反应。关键是要确保你能跟踪每次调用花费多长时间并恰当地采取行动。

执行必需的测试

在将任何库放到生产环境中之前,你必须构建一个测试套件,以确定这个库是否能如你期望的那样工作。你可以使用一个供应商指定的测试套件,但使用自己设计的、能模拟你的应用程序如何使用这个库的测试套件也是很重要的。测试过程应该包含对合法和不合法的输入数据的检查。重要的是要确保对于合法的输入你能得到预期的输出,而对于不合法的输入你能得到某些异常。

3.8 关注设备

为了让移动设备更安全,你需要考虑执行以下这些步骤

  • 让应用程序的所有利益相关者(包括用户、CIO、CISO、人力资源以及开发团队以外的
    其他人)参与到应用程序特性的决策过程中来
  • 以书面形式制定一个移动安全策略。
  • 确保管理层理解为安全措施提供资金支持的需求。
  • 获取正确的工具来创建安全的应用程序。以下是一些通常会用到的与解决该领域问题相关的工具:
    • a. 用户或系统认证
    • b. 数据加密
    • c. 移动设备管理
    • d. 通用的反病毒保护
    • e. 虚拟私有网络(virtual private network,VPN)支持(需要时)
    • f. 防止数据丢失
    • g. 主机入侵防御
  • 与有强大安全专业技能的公司建立合作关系(如果有必要)。
  • 开始开发工作。只有在为应用程序创建了强大的支持系统之后,你才能开始开发工作。

3.9 关注浏览器API使用

target="_blank"漏洞,可以使用rel属性:

1
<a href="https://an.evil.site" target="_blank" rel="noreferer noopener nofollow">Enter an "evil" website</a>

不过noreferer兼容不太好,所以最好还是使用js来打开新窗口:

1
2
3
4
5
function openUrl(url) {
let newTab = window.open();
newTab.opener = null;
newTab.location = url;
}

*target="_blank"性能问题

如果网站使用了target="_blank",则新打开的选项卡的性能将影响当前页面。这个时候如果在新打开的页面执行非常臃肿的js脚本,原始选项卡将受影响,并且会出现停滞现象。
如果将noopener添加到链接中,则两个选项卡 不会相互干扰,因此原始页面的性能不好受到新页面的影响。

3.10 代码审查

p-7.jpg

查找源代码中的漏洞

1.“黑盒”测试与“白盒”测试

  • “黑盒”主要从外部攻击应用程序,并监控其输入与输出,而之前并不了解它的内部工作机制
  • “白盒”需要分析应用程序的内部动作,查阅所有设计文档、源代码与其他资料
  • 白盒代码审查可非常高效地发现应用程序中存在的漏洞
  • 应该相互补充

2.代码审查方法

  • 3个步骤:
    • 从进入点开始追踪用户向应用程序提交的数据,审查处理这些数据的代码
    • 在代码中搜索表示存在常见漏洞的签名,并审查这些签名,确定某个漏洞是否存在
    • 对内存危险的代码进行逐行审查 ,理解应用程序逻辑,并确定其中存在的所有问题
  • 需要仔细审查的功能组件:应用程序中的关键安全机制(验证、会话管理、访问控制与任何应用程序范围内的输入确认)、外部组件接口,以及任何本地代码

3.11 设计开发团队安全协议

p-8.jpg

朝着创建一个可靠应用程序的目标所做的任何努力都必须考虑整个团队。开发团队需要从一开始就具有设计和构建可靠应用的意识。在这个过程中,团队还需要记住保持平衡。如果一个应用程序因为运行太慢而无人使用,那将它做得既可靠又安全也没有什么意义。

为了给公司制定合适的协议,你需要以某些方式将任务分解。开发应用程序的团队必须从以下三个不同的级别考虑可靠性的问题。

  • 偶然发生的设计或执行错误
  • 更改技术
    • 面向未来的
    • 黑客的改进
  • 恶意

团队成员之间的沟通是很重要的,但确保沟通没有被误解则更加重要。想当然的假设制造了各种问题,而人们特别擅长用假设来填补信息鸿沟。当然,一名团队成员的假设可能不是由同一个团队的其他成员来执行。开发团队所需的沟通应包括以下这些最佳实践

  • 可靠性和安全性培训
  • 可靠性要求
  • 可靠的设计
  • 可靠的编码
  • 安全源代码处理
  • 可靠性测试
  • 可靠性和安全性文档
  • 可靠性和安全性准备
  • 可靠性和安全性响应
  • 完整性检查
  • 安全性与可靠性研究

创建经验教训的反馈回路

  • 质量
  • 故障点
  • 培训

考虑三方成套解决方案的问题

重新造轮子通常是错误的做法。很有可能其他人已经创建了一个能很好地满足你的需求的安全解决方案,所以你能直接使用它而不需要创建自己的解决方案。

  • 1.发现第三方安全解决方案
  • 2.考虑云安全方案
  • 3.选择产品类型

4 检测(漏洞挖掘)

p-9.jpg

4.1 像黑客一样思考,定义Web安全扫描的需求

考虑测试系统的使用

你需要一个测试系统,这样你就能自由探索黑客会采用的各种攻击手段。除非充分了解如今的大部分应用程序是何等脆弱,否则你真的无法修复自己的应用程序。开发人员会犯各种错误,在当时看起来是无害的,但后面会导致安全问题。小到代码中的一些错误注释都可能导致问题。使用生产系统来测试是一个糟糕的想法,因为本书所描述的方法可能会让你遭受真正的攻击。你需要一个能够破坏并恢复的系统,以确保你真正掌握所学。
这里的要点是对有害条件下的各种应用程序进行测试,但是以安全的方式进行,不会真的损害任何真实数据或任何生产系统。给测试环境注入病毒可以让你发现应用程序会如何应对,而无需真的在生产环境中试验这个病毒。当然,你的测试系统不能连接到你的生产网络(否则病毒可能会跑出来并感染生产系统)。你也可以使用这个环境来测试各种漏洞,并确定黑客会采用什么手段来破坏你的应用程序。
但是,测试系统不止能用来测试应用程序。你还可以用它测试对策的效率或者特定配置的漏洞。测试整体的系统有助于确保应用程序不会轻易被其他部分的漏洞所破坏。测试整个环境是很关键的,因为任何黑客都会这样做。

接受必需的训练

  • 通用原则(General principles)
  • 代码质量(Code quality)
  • 并发(Concurrency
  • 未验证的参数(Unvalidated parameters)
  • 访问控制缺陷(Access control flaws)
  • 认证缺陷(Authentication flaws)
  • 会话管理缺陷(Session management flaws)
  • 跨站脚本攻击(Cross-site scripting,XSS)
  • 缓存溢出(Buffer overflows)
  • 注入缺陷(Injection flaws)
  • 不安全的存储(Insecure storage)
  • 拒绝服务(Denial of service,DOS)
  • 配置(Configuration)
  • Web 服务(Web services)
  • AJAX 安全性(AJAX security)

缓冲区溢出漏洞:向一个确定目标发送较长的字符串并监控反常结果;即使实施了常规过滤,溢出可能依然存在;长度足够短、能够避开这种过滤的字符串也可能触发溢出;

XSS:XSS比较难挖掘,需要具体业务进行可能性分析和测试。比如检查页面URL或接口URL是否有query(?)标志。

CSRF:

  • 目标表单是否有有效的token随机串
  • 目标表单是否有验证码
  • 目标是否判断力Referer来源
  • 网站根目录下crossdomain.xml的”allow-access-from domain”是否是通配符
  • 目标JSON数据似乎可以自定义callbak函数等。

用户操作劫持:

  • 目标的HTTP响应头是否设置好了X-Frame-Options字段
  • 目标是否有javascript的Frame Busting机制
  • 更简单的就是用iframe嵌入目标网站试试。若成功,则说明漏洞存在。

枚举内容与功能

  • 1.Web抓取
  • 2.用户指定的抓取
  • 3.发现隐藏的内容
  • 4.应用程序页面与功能路径
  • 5.发现隐藏的参数

分析应用程序

  • 1.分析应用程序的功能
    • 应用程序的核心功能
    • 其他较为外围的应用程序行为
    • 核心安全机制及其动作方式
    • 应用程序处理用户提交的输入的所有不同位置
    • 客户端使用的技术
    • 服务器端使用的技术
    • 任何可收集到的、关于服务器端应用程序内部结构与功能的其他信息
  • 2.确定用户输入入口点
    • 每个URL字符串
    • URL查询字符串中提交的每个参数
    • POST请求主体中提交的每个参数
    • 每个cookie
    • HTTP请求头
  • 3.确定服务端技术
    • 提取版本信息:Server头
    • HTTP指纹识别
    • 文件扩展名
    • 目录名称
    • 会话令牌:PHPSESSID、JSESSIONID(java)
    • 第三方代码组件
  • 4.确定服务器端功能
    • 仔细分析请求
    • 推测应用程序的行为
    • 隔离独特的应用程序行为
  • 5.解析受攻击面

修复

修复过程应该包含对应用程序各部件的更新和补丁进行检查的策略。为了达成这一目标,必须维护良好的应用文档。当然,为了确保安全问题不再发生,开发团队需要对所有应用程序需要的更新进行测试。最后,你需要确保数据在整个过程中始终保持安全,并执行应用程序所需的所有数据恢复。

5 后果

破坏金融管理秩序罪,金融诈骗罪,扰乱市场秩序罪,侵犯公民人身权利、民主权利罪,侵犯财产罪。

做遵纪守法的好公民,不然刑法千万条,总有一条适合你。

p-5.jpg

相关资料