《代码安全介绍》PPT课件.ppt
1,代码安全介绍,2,第一章、序言,1.1 背景1.2编码中的安全问题,据美国IDC 公司2006年对企业信息安全的调查和统计,70%以上的信息安全问题是因为应用系统自身的安全问题而遭到黑客的攻击,而不是因为网络;同时 NIST对近几年的信息安全的事故的跟踪调查显示,几乎92%的信息安全事故都与软件相关。,3,在软件的编码阶段,主要软件安全问题来源于如下几个方面:软件自身的代码缺陷 用户恶意输入 不期望的连接 在整个软件系统中主要体现在如下几个方面带来安全隐患:输入验证与表示 API误用 安全特征 时间与状态 错误处理 代码质量 封装和环境等安全漏洞,第一章、序言,1.1 背景1.2 编码中的安全问题,4,这些威胁主要是由于开发人员缺乏安全编码的意识和自身对软件安全知识了解不足、所适用的对开发语言和开发技术的缺陷了解不足、没有以黑客思维去看待软件而导致的,表现为攻击者可以利用开发技术自身的漏洞、恶意输入以及异常连接等问题,对应用软件系统进行攻击,发现并利用软件中存在的安全漏洞。,第一章、序言,1.1 背景1.2 编码中的安全问题,5,目前软件代码中的风险非常多,根据CERT的统计,最近几年都稳定在5000多个。对这些安全漏洞的分类目前有很多种,本文主要采用了McGraw提出的分类方法。本文将软件代码中存在的安全漏洞分为8类,分别是:输入验证与表示,API误用,安全特征,时间与状态,错误处理,代码质量、环境和封装。,第二章、代码安全问题分类介绍,2.1 输入验证与表示2.2 API误用2.3安全特性2.4时间与状态2.5错误处理2.6代码质量2.7环境和封装,6,输入验证和表示问题通常是由特殊字符、编码和数字表示所引起的,这类安全问题的发生是对输入的信任所造成的。一些较大的安全问题往往都是由于对输入的信息过度信任造成的。,第二章、代码安全问题分类介绍,2.1 输入验证与表示2.2 API误用2.3安全特性2.4时间与状态2.5错误处理2.6代码质量2.7环境和封装,7,API是调用者与被调用者之间的一个约定,大多数的API误用是由于调用者没有理解约定的目的所造成的。比如如果一个编码人员继承了SecureRandom,返回的却是一个非随机值,那么他就违背了约定。,第二章、代码安全问题分类介绍,2.1 输入验证与表示2.2 API误用2.3安全特性2.4时间与状态2.5错误处理2.6代码质量2.7环境和封装,8,安全特征主要关系认证,访问控制,机密性,密码,权限管理等方面的内容。,第二章、代码安全问题分类介绍,2.1 输入验证与表示2.2 API误用2.3安全特性2.4时间与状态2.5错误处理2.6代码质量2.7环境和封装,9,分布式计算是与时间和状态有关的。也就是说,为了让多个部件之间交互,需要状态共享,而这要花费时间。大多数程序员将他们的工作人格化。他们认为控制器的一个线程会按照他们所想的方式来执行整个程序。然而,现在的计算机能在多任务之间快速切换,采用多核、多CPU或者说分布式系统,两个事件甚至能在同一时间发生。这样一来,在程序员所想的程序执行模式和实际发生的情况之间就会产生问题。这些问题可能涉及到线程、进程、时间和信息之间的非法交互。这些交互通过共享的状态产生:如信号量、变量、文件系统以及任何能够存储信息的东西。,第二章、代码安全问题分类介绍,2.1 输入验证与表示2.2 API误用2.3安全特性2.4时间与状态2.5错误处理2.6代码质量2.7环境和封装,10,错误和错误处理代表了一类API。与错误处理有关的错误是很常见的。与API误用相比,和错误处理相关的安全漏洞一般是两种方式造成的:第一种是:根本忘记处理错误或者只是简单的处理,并没有彻底解决;第二种则是:程序对可能的攻击者泄露了过多的信息或者涉及面太广没有人愿意去处理这些问题。,第二章、代码安全问题分类介绍,2.1 输入验证与表示2.2 API误用2.3安全特性2.4时间与状态2.5错误处理2.6代码质量2.7环境和封装,11,低劣的代码质量会导致不可预测的行为。从用户的角度来看,这通常会表现为低劣的可用性。对于攻击者而言,低劣的代码使他们可以以意想不到的方式威胁系统。,第二章、代码安全问题分类介绍,2.1 输入验证与表示2.2 API误用2.3安全特性2.4时间与状态2.5错误处理2.6代码质量2.7环境和封装,12,封装就是划定强力的分界线。在 web浏览器中,这就意味着你的代码模块不能被其他代码模块滥用。在服务端,这意味着要区分校验过的数据和未经校验的数据,区分不同用户的数据,或者区分用户能看到的和不能看到的数据。,第二章、代码安全问题分类介绍,2.1 输入验证与表示2.2 API误用2.3安全特性2.4时间与状态2.5错误处理2.6代码质量2.7环境和封装,13,把输入验证作为软件框架的一部分。集中处理输入验证框架带来的好处如下:1.所有的输入使用一致的输入验证:如果每个模块各自独立实现自己的输入验证,将会很难建立一个统一的输入验证策略。2.有效降低工作量:输入验证比较灵活,分别实现输入验证会导致其工作量成倍的增加。3.对输入验证进行统一的升级和修改:这样如果在输入验证逻辑里发现问题时就可以比较方便的修改。4.失败控制:如果一个集中处理输入验证框架收到它不知道如何处理的输入,很容易就拒绝掉该输入,如果没有采取集中输入验证,开发者很容易忘记进行输入验证。,第三章、安全建议输入处理,3.1集中输入验证3.2保证所有输入信息被验证过3.3建立可信边界3.4检测输入长度3.5拒绝验证失败数据3.6验证HTTP请求中的所有组成3.7对来自命令行、环境以及配置文件的输入进行校验3.8控制写入日志信息3.9输入验证时使用最强的形式3.10防范元字符攻击,14,确保在输入验证之前,新输入的数据不要被添加到程序中(输入的数据不能进入程序代码中被执行)。也就是说,程序默认情况下就要对输入的信息进行验证,不能通过验证的数据将会被拒绝。这样的话,开发者就不会忘记进行输入验证了。,第三章、安全建议输入处理,3.1集中输入验证3.2保证所有输入信息被验证过3.3建立可信边界3.4检测输入长度3.5拒绝验证失败数据3.6验证HTTP请求中的所有组成3.7对来自命令行、环境以及配置文件的输入进行校验3.8控制写入日志信息3.9输入验证时使用最强的形式3.10防范元字符攻击,15,将可信和不可信数据分别储存来保证输入验证总是被执行。可信边界可以被认为是在程序中划定的一条分隔线,一边的数据是不可信的而另一边则是可信的。当数据要从不可信的一侧到可信一侧的时候,需要使用验证逻辑进行判断。需要在程序中定义清晰的可信边界。在一些代码中使用的保存可信数据的数据结构,不能被用来在其它代码中存储不可信数据。使数据穿越可信边界的次数降到最低。当程序混淆了可信和不可信数据的界限时会导致安全边界发生问题,最容易导致这种错误的情况是把可信和不可信数据混合在一个数据结构里。这里举了一个例子:,第三章、安全建议输入处理,3.1集中输入验证3.2保证所有输入信息被验证过3.3建立可信边界3.4检测输入长度3.5拒绝验证失败数据3.6验证HTTP请求中的所有组成3.7对来自命令行、环境以及配置文件的输入进行校验3.8控制写入日志信息3.9输入验证时使用最强的形式3.10防范元字符攻击,16,验证的时候应该验证允许输入的最小和最大长度 如果对最大输入长度进行限制,攻击者就很难对系统的其它弱点进行攻击。譬如,对于一个很可能被用来进行跨站脚本攻击的输入域,如果攻击者可以输入任意长度的脚本,那么这显然要比限制输入长度更加危险。而对最短长度的检测可以使攻击者无法忽略强制要求输入的域,同时也无法输入与预期不符的数据。对输入长度的检测是输入验证最基本的要求,但是,好的输入验证并不是仅仅检测输入长度,还可以根据被验证程序的上下文进行更深入的检测。如果程序需要验证一个输入域,验证逻辑对该域的合法值限定得越详细,验证逻辑就能越好地工作。,第三章、安全建议输入处理,3.1集中输入验证3.2保证所有输入信息被验证过3.3建立可信边界3.4检测输入长度3.5拒绝验证失败数据3.6验证HTTP请求中的所有组成3.7对来自命令行、环境以及配置文件的输入进行校验3.8控制写入日志信息3.9输入验证时使用最强的形式3.10防范元字符攻击,17,拒绝验证失败的数据,不试图对其进行修复 通过设置默认值来保存一个丢失的输入,处理密码域时自动剪裁掉超过最大长度的输入,替换掉在输入框输入的 JavaScript字符等行为是很危险的,不要试图修复一个未能通过输入验证的请求,直接拒绝掉,这样才是安全的。输入验证本身就很复杂,如果和自动错误恢复的代码混合在一起的话,将会造成更大的复杂性,自动错误恢复代码很可能改变请求的含义或者截断验证逻辑。如果我们能够引导用户,使他们提交的请求能够通过输入验证,就能比专注于自动错误恢复代码有效得多。,第三章、安全建议输入处理,3.1集中输入验证3.2保证所有输入信息被验证过3.3建立可信边界3.4检测输入长度3.5拒绝验证失败数据3.6验证HTTP请求中的所有组成3.7对来自命令行、环境以及配置文件的输入进行校验3.8控制写入日志信息3.9输入验证时使用最强的形式3.10防范元字符攻击,18,验证来自HTTP请求中的所有数据,恶意数据可以从表单域,URL参数,cookie,http头以及 URL自身传入。无论一个 HTTP请求看起来多么的“正常”,都应该对它进行完整的检查。攻击者可以在你提供给他们的 web页面里输入任何内容,他们可以完全脱离浏览器和浏览器的一切验证,修改 Cookie、隐藏区域、name与 value的对应关系,他们可以为了“错误”的目的在“错误”的时间按“错误”的顺序提交 URL请求。,第三章、安全建议输入处理,3.1集中输入验证3.2保证所有输入信息被验证过3.3建立可信边界3.4检测输入长度3.5拒绝验证失败数据3.6验证HTTP请求中的所有组成3.7对来自命令行、环境以及配置文件的输入进行校验3.8控制写入日志信息3.9输入验证时使用最强的形式3.10防范元字符攻击,19,不要使你的软件的安全性依赖于配置和维护它的人 对来自命令行、系统属性,环境变量以及配置文件的输入都需要进行校验来保证它们是一致的和健全的。如果攻击者对系统的属性进行修改,可以通过命令行,环境以及配置文件来威胁软件系统,这里要求软件开发者不要相信来自命令行、环境以及配置文件的输入。,第三章、安全建议输入处理,3.1集中输入验证3.2保证所有输入信息被验证过3.3建立可信边界3.4检测输入长度3.5拒绝验证失败数据3.6验证HTTP请求中的所有组成3.7对来自命令行、环境以及配置文件的输入进行校验3.8控制写入日志信息3.9输入验证时使用最强的形式3.10防范元字符攻击,20,不要允许攻击者能够写任意的数据到日志里 正确的和长期的记录对于在已部署的软件系统中寻找缺陷和发现安全弱点是很重要的。我们可以手工或者自动的分析日志来查找重要的事件、一段时间内的趋势,它是检测系统和用户行为的宝贵资源。由于日志的价值,它也成为了攻击者的目标。如果攻击者可以控制写进日志文件的信息,他们就可以在输入中混入伪造的日志条目来伪造系统事件,更严重的是,如果负责进行日志分析的代码存在漏洞,特定的有恶意的输入很可能触发该漏洞,并引发更加严重的危害。,第三章、安全建议输入处理,3.1集中输入验证3.2保证所有输入信息被验证过3.3建立可信边界3.4检测输入长度3.5拒绝验证失败数据3.6验证HTTP请求中的所有组成3.7对来自命令行、环境以及配置文件的输入进行校验3.8控制写入日志信息3.9输入验证时使用最强的形式3.10防范元字符攻击,21,在指定的环境中使用最强的输入验证方式。按照间接选择,白名单以及黑名单的顺序进行验证。有很多方法来校验一段数据。根据安全的观点,输入验证的过程需要非常清晰,但是在一些复杂的环境中,那些“最安全的输入验证”并不一定切实可行。所以应该在特定的场景中选择一个相对“最强”的输入验证的形式,一方面满足需求,另一方面防止欺诈。不要为了平衡输入验证的安全性与可用性而困惑。正常的输入验证过程只需要捕获通用的错误并提供易于理解的输入验证反馈。而以安全为目标的输入验证过程则只针对那些不正常的输入。,第三章、安全建议输入处理,3.1集中输入验证3.2保证所有输入信息被验证过3.3建立可信边界3.4检测输入长度3.5拒绝验证失败数据3.6验证HTTP请求中的所有组成3.7对来自命令行、环境以及配置文件的输入进行校验3.8控制写入日志信息3.9输入验证时使用最强的形式3.10防范元字符攻击,22,不允许攻击者控制发送给文件系统、浏览器、数据库或者其它子系统的命令。所有类似脚本语言以及标记语言之类的强调易用性与交互性的技术都有一个共性:其可以接受可变的控制结构与数据。例如,SQL查询:select*from emp where name=Brian 由“select”,“from”,“where”,and“=”with the data“*”,“emp”,“name”以及 Brian这些关键字组合。控制结构与数据的组合可以保证这些语言易于被使用。,第三章、安全建议输入处理,3.1集中输入验证3.2保证所有输入信息被验证过3.3建立可信边界3.4检测输入长度3.5拒绝验证失败数据3.6验证HTTP请求中的所有组成3.7对来自命令行、环境以及配置文件的输入进行校验3.8控制写入日志信息3.9输入验证时使用最强的形式3.10防范元字符攻击,23,开发安全的 web应用程序是很有挑战性的,主要原因如下:1由于用户可以很容易的访问应用程序,恶意用户也可以这样做。2 HTTP不是为应用设计的,自然更不是为安全的应用设计的。HTTP的安全问题与标准 C库中的字符串函数带来的缓冲区溢出问题一样麻烦。程序员需要通过自己的方法来确认应用是安全的。3应用不只需要防护恶意用户,还需要帮助正常用户防御恶意用户。换句话说,恶意用户希望通过应用作为其攻击的跳板。,第四章、安全建议web应用程序,4.1基础4.2会话,24,使用 HTTP POST方法来保证 Request参数的安全。使用 Get方法传递的参数包含在 URL里,所以他们理所当然的可以被记录在日志文件里,通过 HTTP头的 referrer发送到其它站点上,被存储在浏览器历史记录里。而 Post方法几乎在所有情况下都需要被使用,很显然,它需要验证表单来确保账户信息的安全。禁止使用 Get方法可以防止很多跨站脚本攻击漏洞,因为这样可以使攻击者无法向用户发送含有恶意Get参数的URL。,第四章、安全建议web应用程序,4.1基础 使用 POST而不是 GET使用 SSL假设浏览器被控制假设浏览器是公开使用JavaScript是不安全的不能依赖Request到达的顺序在恶意环境中保护浏览器创建一个默认的错误页面使用通用错误消息4.2会话,25,SSL对所有涉及保密信息的通信都使用SSL,拒绝不使用SSL的请求。SSL确实能够带来一定的好处。如果合理的使用,它就能对嗅探攻击和中间人攻击做出有效的防御,同时它还可以为主机和客户机提供可信的验证,但是大部分的终端用户并不使用主机验证,也很少有站点使用SSL来验证终端用户。SSL并不应该是可选的方案:一个安全的程序不应该在使用443端口(SSL通信端口)的同时也接受80端口(一般的HTTP服务端口)请求,不应允许用户选择安全级别。,第四章、安全建议web应用程序,4.1基础 使用 POST而不是 GET使用 SSL假设浏览器被控制假设浏览器是公开使用JavaScript是不安全的不能依赖Request到达的顺序在恶意环境中保护浏览器创建一个默认的错误页面使用通用错误消息4.2会话,26,不管在客户端是否经过输入验证,在服务端仍要进行验证。Web程序总会接收到来自攻击者的请求,对客户习惯做出的任何假设都有可能会被用来对你的程序发起攻击。在验证之前请不要相信来自客户端的任何数据,包括那些不常被客户修改的值(如cookies,隐藏的域)。只使用客户端的某些特性(如JavaScript代码)来给合法用户提供反馈是不安全的。开发者有很多方法来创建动态和交互的web页面,包括JavaScript,、Flash、Java Applets、ActiveX等,这些技术有一个共同的弱点:攻击者可以绕过他们而直接与服务器通信。,第四章、安全建议web应用程序,4.1基础 使用 POST而不是 GET使用 SSL假设浏览器被控制假设浏览器是公开使用JavaScript是不安全的不能依赖Request到达的顺序在恶意环境中保护浏览器创建一个默认的错误页面使用通用错误消息4.2会话,27,要假设攻击者可以了解学习你发送给他们的任何数据,即使这些信息没有在浏览器中显示。攻击者在进行攻击之前会先了解你的程序运作方式,观察程序返回的HTTP应答包是最容易的一种方法了,他们通过这种方式来寻找URL的格式,URL的参数,隐藏的表单,cookie值等,还可以读取页面源码、HTML中的注释(包括错误页面的HTML),解析JavaScript,根据命名习惯进行预测,还会使用搜索引擎发掘该程序其它用户的信息。你不但不能相信来自客户端的任何数据,而且不能在应答包中包含任何秘密信息。,第四章、安全建议web应用程序,4.1基础 使用 POST而不是 GET使用 SSL假设浏览器被控制假设浏览器是公开使用JavaScript是不安全的不能依赖Request到达的顺序在恶意环境中保护浏览器创建一个默认的错误页面使用通用错误消息4.2会话,28,不要信任在客户端进行的验证 攻击者很容易就可以绕过你设定的那些请求页面和浏览器,直接与你的应用服务器通信。这就意味着他们可以绕过在客户端所做的任何设置,譬如 JavaScript验证逻辑。JavaScript可以帮助合法的用户对不正常的输入信息进行检测,但是不能确保服务器接收到数据的安全性。所以,要在服务器端进行安全验证。,第四章、安全建议web应用程序,4.1基础 使用 POST而不是 GET使用 SSL假设浏览器被控制假设浏览器是公开使用JavaScript是不安全的不能依赖Request到达的顺序在恶意环境中保护浏览器创建一个默认的错误页面使用通用错误消息4.2会话,29,攻击者可以通过改变请求顺序绕过有设计缺陷的系统的验证 攻击者可以随意控制 request到达的顺序来适合自己的需要。例如,如果你的程序通过不同页面来搜集信息,在较早的表单里验证了信息,而在修改信息的表单则没有进行验证,那么攻击者就可以利用后者来绕过你的输入验证。,第四章、安全建议web应用程序,4.1基础 使用 POST而不是 GET使用 SSL假设浏览器被控制假设浏览器是公开使用JavaScript是不安全的不能依赖Request到达的顺序在恶意环境中保护浏览器创建一个默认的错误页面使用通用错误消息4.2会话,30,在数据发送给客户前进行编码或者加密 浏览器一直以来就有很多问题。攻击者可以通过有问题的程序攻击存在漏洞的客户端。因此不要让你的程序成为这种工具。很多情况下这种问题可以理解为输入验证的问题,但是从深度防御的角度考虑,它也是一个输出编码(加密)的问题。例如,你可以通过对 HTTP请求进行校验来防御来自外部的跨站脚本攻击,但是如果你对 HTTP应答都进行了编码,这样就可以防御来自外部和内部的跨站脚本。,第四章、安全建议web应用程序,4.1基础 使用 POST而不是 GET使用 SSL假设浏览器被控制假设浏览器是公开使用JavaScript是不安全的不能依赖Request到达的顺序在恶意环境中保护浏览器创建一个默认的错误页面使用通用错误消息4.2会话,31,对所有的异常构造统一的错误页面,包括 HTTP错误和未经处理的异常 为 HTTP错误建立一个默认的错误页面,丢弃掉所有的异常,这样的话就能够防止攻击者从应用程序的默认出错页面中得到系统信息。,第四章、安全建议web应用程序,4.1基础 使用 POST而不是 GET使用 SSL假设浏览器被控制假设浏览器是公开使用JavaScript是不安全的不能依赖Request到达的顺序在恶意环境中保护浏览器创建一个默认的错误页面使用通用错误消息4.2会话,32,要确定你的应用错误提示信息不会泄露系统信息以及出错原因等敏感信息 精心构造错误提示信息来防止诸如用户 id,网络,应用程序以及服务器环境的细节等重要的敏感信息的泄漏。主要包括:不区分错误的用户名和错误的密码;在返回的报告中不包含主机信息、网络信息、DNS信息、软件版本信息、错误代码或者其它发生的错误的详细信息;不要把错误的细节放在错误页面的注释里。,第四章、安全建议web应用程序,4.1基础 使用 POST而不是 GET使用 SSL假设浏览器被控制假设浏览器是公开使用JavaScript是不安全的不能依赖Request到达的顺序在恶意环境中保护浏览器创建一个默认的错误页面使用通用错误消息4.2会话,33,使用最具限制性的域和路径来限制对会话使用的 cookie的访问 如果出于结构要求需要与 cookie有关的域或者路径是开放的,请在重构时候注意安全性。出于安全性的考虑,应该在建立 Session时要求用户以 SSL方式连接,并且将该会话的安全标识设置为 cookie只能通过安全连接进行传输。,第四章、安全建议web应用程序,4.1基础4.2会话保护会话中使用的cookie强制执行一个会话最大空闲时间强制执行一个会话最大生存周期允许用户终止其会话在会话终止时清空其数据,34,使用最具限制性的域和路径来限制对会话使用的 cookie的访问 如果出于结构要求需要与 cookie有关的域或者路径是开放的,请在重构时候注意安全性。出于安全性的考虑,应该在建立 Session时要求用户以 SSL方式连接,并且将该会话的安全标识设置为 cookie只能通过安全连接进行传输。,第四章、安全建议web应用程序,4.1基础4.2会话保护会话中使用的cookie强制执行一个会话最大空闲时间强制执行一个会话最大生存周期允许用户终止其会话在会话终止时清空其数据,35,强制执行一个会话最大空闲时间来增加安全性和稳定性 强制执行一个会话最大空闲时间可以带来如下的好处:缩短那些未能及时注销的用户暴露在外的时间;减少了可供攻击者猜解的 session id的平均数目。许多应用程序框架将会话最大空闲时间设置为配置参数,将其统一起来,使相关人员知道如何正确的设置,使用户知道什么是可判断的。对一个中等安全程度的系统,建议将超时时间设置为小于 30分钟。,第四章、安全建议web应用程序,4.1基础4.2会话保护会话中使用的cookie强制执行一个会话最大空闲时间强制执行一个会话最大生存周期允许用户终止其会话在会话终止时清空其数据,36,强制执行会话最大生存周期来增加安全性和稳定性 只有在不超过会话 id最大生存周期的时候,才允许一个会话不用再次进行对用户的认证。通过进行重新认证,可以防止攻击者窃取会话 id。对一个中等安全程度的系统,建议一个会话最大生存周期设置为不大于 6小时。,第四章、安全建议web应用程序,4.1基础4.2会话保护会话中使用的cookie强制执行一个会话最大空闲时间强制执行一个会话最大生存周期允许用户终止其会话在会话终止时清空其数据,37,允许用户通过注销来保护自己的帐号允许用户终止其会话能够带来如下好处:在一个公共设备上的用户只能通过这种方法才能防止在这个设备上的后来使用的用户访问其帐户。允许用户终止会话,可以防止后来取得该台电脑控制权的攻击者攻击其帐户。通过结束不使用的 session,可以减少可供攻击者猜解的会话 id的平均次数。,第四章、安全建议web应用程序,4.1基础4.2会话保护会话中使用的cookie强制执行一个会话最大空闲时间强制执行一个会话最大生存周期允许用户终止其会话在会话终止时清空其数据,