澳门新葡萄京官网注册 1

澳门新葡萄京官网注册java安全编码规范(一)

本文由码农网 –
小峰原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!

虽然,JavaEE
内置了一些非常优秀的安全机制,但是它不能全面应对应用程序面临的各种威胁,尤其许多最常见的攻击:跨站攻击(XSS),SQL
注入,Cross-Site Request Forgery (CSRF), 与 XML eXternal Entities (XXE)
等。如果你不对系统做大量的安全测试、漏洞修补以及购买应用级安全防护工具,应用程序就完全暴露在这些攻击之下。

写着玩

JavaEE有一些超赞的内置安全机制,但它们远远不能覆盖应用程序要面临的所有威胁。很多常见攻击,例如跨站点脚本攻击(XSS)、SQL注入、跨站点伪造请求(CSRF),以及XML外部实体(XXE)丝毫没有涵盖。你可以阻止web应用程序和web服务暴露于这些攻击,但这需要一定量的工作和测试。幸运的是,Open
Web Application Security
Project(OWASP)公布了“10大最关键的web应用程序安全风险”的报告。

幸运的是,开源 Web 应用安全组织(OWASP)已经将这下面10个 Web
问题列为最重要的安全攻击,详情请参见:「Ten Most Critical Web
Application Security Risks」 报告。 希望引起大家这些安全问题的足够重视。

 
安全问题其实是很多程序员想了解又容易忽略的问题,以下介绍一些常见的安全问题和解决方案,当然有的问题使用阿里云服务器之类的都给解决了,但还是知道的好。

澳门新葡萄京官网注册 1

下面就详细解释一下这些最著名的安全攻击在 JavaEE 的 Web 应用程序和 Web
服务上是如何工作的:

 一、输入验证和表示

 
输入验证和表示问题通常是由特殊字符、编码和数字表示所引起的,这类安全问题的发生是对输入的信任所造成的。这些问题包括:缓冲区溢出、跨站脚本攻击、SQL注入和其他等等。

1.1命令注入

l问题简介

在没有指定完整路径的情况下执行命令可能使得攻击者可以通过改变$PATH或者其他环境变量来执行恶意代码。

l详细描述

命令注入攻击有两种形式:

1)攻击者可以改变应用程序执行的命令

2)攻击者可以改变命令执行的环境。在此我们主要关心第二种情况,即攻击者可以通过改变环境变量或者在搜索路径中插入可执行恶意代码来改变命令的原有目的。

这种类型的命令注入攻击通常发生在:

1)攻击者改变应用程序的环境

2)应用程序执行命令时没有指定一个完整的路径或者校验执行的代码

3)通过执行该命令,应用程序会给予攻击者特殊的权限或者能力,而这些权限或能力是攻击者不应该具有的。

Example
1:下面代码使用系统变量APPHOME来定位程序安装的目录,然后根据此目录的相关路径来执行初始化脚本。

string val =Environment.GetEnvironmentVariable(“APPHOME”);

string cmd = val + INITCMD;

ProcessStartInfo startInfo = newProcessStartInfo(cmd);
Process.Start(startInfo);

示例1中的代码中,攻击者可以通过修改系统变量APPHOME,使其指向一个包含恶意代码的路径,进而利用应用程序的高级权限来执行任意命令。因为程序没有对读入的环境变量值进行验证,如果攻击者能够控制系统的环境变量值APPHOME,那么攻击者就能欺骗应用程序,让其执行恶意代码,从而控制系统。

Example
2:下面的代码来自于一个web管理程序,它允许用户使用批处理文件包裹来开始对Oracle数据库的备份,然后运行cleanup.bat脚本来删除临时文件。脚本rmanDB.bat接收一条命令行参数来决定进行何种备份。因为对数据库的访问是受限制的,所以应用程序会以特殊权限来执行备份。

String btype =request.getParameter(“backuptype”); String cmd =
newString(“cmd.exe /K

“c:\util\rmanDB.bat”+btype+”&&c:\utl\cleanup.bat””)System.Runtime.getRuntime().exec(cmd);

澳门新葡萄京官网注册,这里的问题是程序没有对从用户处读取的backuptype参数进行任何验证。通常Runtime.exec()函数不会执行多个命令,但是在这里,程序为了在只调用一次Runtime.exec()的情况下运行多个命令,先运行了cmd.exe。一旦该接口被调用,它将会执行由&&分隔开的多个命令。如果攻击者传入一个“&&
del
c:\dbms\*.*”形式的字符串,那么应用程序会将该命令与程序指定的其它命令一起执行。因为应用程序需要有足够的权限来与数据库交互,这就意味着攻击者注入的任何命令都将以同样的权限执行。

Example
3:下面的代码来自一个web应用程序,它允许用户通过访问接口来修改他们的系统密码。在网络环境中,修改密码的步骤之一是在/var/yp目录运行make命令。

System.Runtime.getRuntime().exec(“make”);

这里的问题是程序没有指定一个完整的路径,并且在执行Runtime.exec()调用前没有清理环境。如果攻击者能够修改环境变量$PATH,让其指向一个叫做make的恶意二进制代码,并使程序在该环境中执行,那么程序原本希望装载的二进制代码将会被恶意代码替代。因为程序需要有足够的权限来执行系统操作,这就意味着攻击者的make将能够以同样的权限运行,这很有可能使攻击者能够完全控制整个系统。

l解决方案

命令注入攻击主要是因为对用户输入或者环境变量值没有进行验证所造成的。为了防范命令注入攻击,我们应该对用户输入进行校验,过滤非法字符(如“&&”等)。同时,在程序中应该尽量不要从环境变量中读入数据,即使不得不依赖环境变量,也应该严格限制这些变量的路径和所起的作用,减少程序受到的影响。此外,还可以去除应用程序不必要的特殊权限。因为很多攻击只有在获得高级特权时才有意义,所以减少程序拥有的特权可以降低被攻击的风险。

1.2跨站脚本

l问题简介

向浏览器发送非法的数据会使浏览器执行恶意代码,通过XML编码进行身份认证也会导致浏览器执行非法代码。

l详细描述

跨站脚本发生在以下两种情况:

1)数据通过不可靠的源进入Web application,大多数情况下是web request。

2)包含在动态内容中的数据在没有经过安全检测就发送给网络用户。

发给web浏览器的恶意内容通常以JavaScript段的形式出现,但也包括HTML,
Flash或者其他浏览器能够执行的代码类型,基于XSS的攻击种类几乎是无限的,但是它们通常会包括:传送私有数据(如cookies或者其他session信息)给攻击者,将受害者的浏览器重定向到攻击者所控制的web内容中,或者假借有漏洞的站点在用户机器上进行其他恶意操作。

Example 1:下面的JSP代码段从一个HTTP
request中读雇员的eid,并将它显示出来如果eid包含源代码,该源代码就会被浏览器执行。

<% String eid =request.getParameter(“eid”); %>

Employee ID: <%= eid %>

Example
2:下面的JSP代码段根据一个雇员的ID在数据库中查询对应的名字,并将其打印出来。如果数据库中的数据来源于用户的输入并没有进行相应的安全性检查,将会造成用户的浏览器执行恶意代码。

<%…

Statement stmt =conn.createStatement();

ResultSet rs =stmt.executeQuery(“select * from emp where id=”+eid);

if (rs != null)

rs.next();

String name =rs.getString(“name”);

%>

Employee Name: <%= name %>

与示例1一样,当name符合规范的时候,这段代码能够正确运行。但当name有问题时,代码段中并没有任何措施来阻止其运行。同样的,这段代码看起来危险性较小,因为name的值是从数据库中读取的。很显然,数据库的内容是由应用程序所控制的。然而,如果name的值来自于用户所提供的数据,那么这个数据库就会成为恶意内容的渠道。如果对数据库中存储的所有数据没有一个适当的输入验证,那么攻击者就能够在用户的浏览器上执行恶意内容。这种类型的攻击被称为存储型XSS,它显得尤为隐蔽,因为数据存储所带来的间接性使得这种威胁更难被识别,也使得攻击者能够侵袭多的用户。XSS攻击可以采用如下形式:一个web站点对访问者进行来宾登记(譬如经常使用的留言簿程序),攻击者在来宾登记中注入JavaScript代码,之后所有进入来宾登记页面的访问者都会执行该恶意代码。

正如上面的示例所述,造成XSS攻击的原因是HTTP响应中包含了未经验证的数据。XSS攻击可以通过三种媒介侵入受害者:

1)如示例1所示,数据直接从HTTP请求中读取,在HTTP响应中反射回去。反射型XSS通常是由攻击者诱使用户向有漏洞的web应用程序提供危险内容,然后这些危险内容会反射给用户并由浏览器执行。传递恶意内容最常见的方法是将恶意内容作为一个参数包含在URL中,然后将URL公开发布或者通过email发给受害者。以这种形式构造的URL是很多钓鱼(phishing)圈套的核心,通过钓鱼圈套,攻击者获取受害者的信任,诱使受害者访问指向有漏洞站点的URL。当站点将攻击者的内容反射给用户后,恶意内容将被执行,从用户机器上窃取用户的私有信息(如包含session信息的cookies)发送给攻击者或者进行其他恶意活动。

2)如示例2所示,应用程序在数据库或者其它可信数据源中存储了危险数据。这些危险数据随后被应用程序读取并包含在动态内容中。存储型XSS通常是由攻击者将危险内容注入数据存储中,然后该内容被读出并包含在动态内容中。在攻击者看来,注入恶意内容最理想的地方要么是用户访问量大的地方,要么是能引起用户兴趣的地方。这些被攻击者感兴趣的用户通常能够提高该应用程序的权限或者交互一些对攻击者而言有价值的敏感数据。如果这种用户执行恶意内容,攻击者就有可能假冒用户执行一些特殊操作或者访问属于用户的敏感数据。

3)应用程序外部的数据源中存储了危险数据,这些危险数据随后被应用程序作为可信数据读取并包含在动态内容中。

l解决方案

跨站脚本攻击都是由于对用户的输入没有进行严格的过滤造成的,所以我们必须在所有数据进入应用程序之前把可能的危险拦截。针对非法的HTML代码包括单双引号等,可以编写函数对其进行过滤。

1.3跨站脚本:缺乏验证

l问题简介

依赖XML编码来校验用户输入会导致浏览器执行恶意代码。

l详细描述

使用escapeXml=”true”属性(默认设置)的标签可以防止一些攻击,但并不能防止所有的跨站脚本攻击。依赖于数据所处的context,像<,>,&,’和”这些字符作为XML的特殊字符,具有特殊的含义。依靠escapeXml=”true”(这相当于是一个弱黑名单)来防止跨站脚本,这可能使得攻击者能够注入恶意代码在浏览器中执行。跨站脚本发生在以下两种情况:

1)数据通过不可靠的源进入Web application,大多数情况下是web request。

2)包含在动态内容中的数据在没有经过安全检测就发送给网络用户。

发给web浏览器的恶意内容通常以JavaScript段的形式出现,但也包括HTML,
Flash或者其他浏览器能够执行的代码类型。基于XSS的攻击种类几乎是无限的,但是它们通常会包括:传送私有数据(如cookies或者其他session信息)给攻击者,将受害者的浏览器重定向到攻击者所控制的web内容中,或者假借有漏洞的站点在用户机器上进行其他恶意操作。

Example 1:下面的JSP代码段从一个HTTP
request中读雇员的eid,并将它显示出来,如果eid包含源代码,该源代码就会被浏览器执行。

<% String eid =request.getParameter(“eid”); %>

Employee ID: <%= eid %>

Example
2:下面的JSP代码段根据一个雇员的ID在数据库中查询对应的名字,并将其打印出来。如果数据库中的数据来源于用户的输入并没有进行相应的安全性检查,将会造成用户的浏览器执行恶意代码。

<%…

Statement stmt =conn.createStatement();

ResultSet rs =stmt.executeQuery(“select * from emp where id=”+eid);

if (rs != null)

rs.next();

String name = rs.getString(“name”);

%>

Employee Name: <%= name %>

与示例1一样,当name符合规范的时候,这段代码能够正确运行。但当name有问题时,代码段中并没有任何措施来阻止其运行。同样的,这段代码看起来危险性较小,因为name的值是从数据库中读取的。很显然,数据库的内容是由应用程序所控制的。然而,如果name的值来自于用户所提供的数据,那么这个数据库就会成为恶意内容的渠道。如果对数据库中存储的所有数据没有一个适当的输入验证,那么攻击者就能够在用户的浏览器上执行恶意内容。这种类型的攻击被称为存储型XSS,它显得尤为隐蔽,因为数据存储所带来的间接性使得这种威胁更难被识别,也使得攻击者能够侵袭更多的用户。XSS攻击可以采用如下形式:一个web站点对访问者进行来宾登记,攻击者在来宾登记中注入JavaScript代码,之后所有进入来宾登记页面的访问者都会执行该恶意代码。

正如上面的示例所述,造成XSS攻击的原因是HTTP响应中包含了未经验证的数据。XSS攻击可以通过三种媒介侵入受害者:

4)如示例1所示,数据直接从HTTP请求中读取,在HTTP响应中反射回去。反射型XSS通常是由攻击者诱使用户向有漏洞的web应用程序提供危险内容,然后这些危险内容会反射给用户并由浏览器执行。传递恶意内容最常见的方法是将恶意内容作为一个参数包含在URL中,然后将URL公开发布或者通过email发给受害者。以这种形式构造的URL是很多钓鱼(phishing)圈套的核心,通过钓鱼圈套,攻击者获取受害者的信任,诱使受害者访问指向有漏洞站点的URL。当站点将攻击者的内容反射给用户后,恶意内容将被执行,从用户机器上窃取用户的私有信息(如包含session信息的cookies)发送给攻击者或者进行其他恶意活动。

5)如示例2所示,应用程序在数据库或者其它可信数据源中存储了危险数据。这些危险数据随后被应用程序读取并包含在动态内容中。存储型XSS通常是由攻击者将危险内容注入数据存储中,然后该内容被读出并包含在动态内容中。在攻击者看来,注入恶意内容最理想的地方要么是用户访问量大的地方,要么是能引起用户兴趣的地方。感兴趣的用户通常会提高该应用程序的权限或者交互一些对攻击者而言有价值的敏感数据。如果这种用户执行了恶意内容,攻击者就有可能假冒用户执行一些特殊操作或者访问属于用户的敏感数据。

6)应用程序外部的数据源中存储了危险数据,这些危险数据随后被应用程序作为可信数据读取并包含在动态内容中。

l解决方案

跨站脚本攻击都是由于对用户的输入没有进行严格的过滤造成的,所以我们必须在所有数据进入应用程序之前把可能的危险拦截。针对非法的HTML代码包括单双引号等,可以编写函数对其进行过滤。

1.4拒绝服务

l问题简介

攻击者能够使程序发生冲突或者使合法用户无法获取资源。

l详细描述

攻击者可以通过向应用程序发送大量请求来使得应用程序无法向合法用户提供服务,但是这种洪水攻击(Flooding
Attack)通常能在网络层进行防范。更重要的是有的bug使得攻击者可以通过使用少量的请求来让应用程序过载,这类bug使得攻击者可以指定请求所消耗的系统资源数量或者所占用系统资源的时间。

Example
1:下面的代码允许用户指定线程睡眠的时间。攻击者可以通过指定一个巨大的数字来无限期的占用该线程。通过少量的请求,攻击者就能够耗尽应用程序的线程池。

int usrSleepTime =

Integer.parseInt(usrInput); Thread.sleep(usrSleepTime);

Example
2:下面的代码从一个zip文件中读取一个字符串。因为它使用了ReadLine()方法,所以它将读取一个无限制的输入。攻击者可以利用该代码来导致OutOfMemory
Exception,或者消耗大量的内存使得程序要耗费更多的时间来进行垃圾回收,又或者在接下来的操作中使得内存溢出。

InputStream zipInput =zipFile.getInputStream(zipEntry);

Reader zipReader = newInputStreamReader(zipInput);

BufferedReader br = newBufferedReader(zipReader);

String line = br.readLine();

l解决方案

拒绝服务攻击是一种滥用资源性的攻击。从程序代码角度讲,对涉及到系统资源的外部数据应该进行严格校验,防止大数目或者无限制的输入。从系统管理的角度来讲,主机应该:

1)关闭不必要的服务;

2)将数据包的连接数从缺省值128或512修改为2048或更大,以加长每次处理数据包队列的长度,以缓解和消化更多数据包的连接;

3)将连接超时时间设置得较短,以保证正常数据包的连接,屏蔽非法攻击包;

4)及时更新系统、安装补丁。此外,还可以对防火墙、路由器进行设置。禁止对主机非开放服务的访问,限制同时打开的数据包最大连接数,访问控制列表(ACL)过滤,设置数据包流量速率,利用负载均衡技术等等。

1.5HTTP响应截断

l问题简介

在HTTP响应头中包含未经验证的数据将可能导致缓存中毒(cache-poisoning)、跨站脚本(cross-site
scripting)、跨用户攻击(cross-user defacement)或者页面劫持(page
hijacking)攻击。

l详细描述

HTTP响应截断攻击发生在:

1)数据通过一个非可信源进入web应用程序,最可能的是通过HTTP请求。

2)包含在HTTP响应头中发送给web用户的数据没有对恶意字符进行验证。与很多软件安全攻击一样,HTTP响应截断是一种达到目的的手段,它本身并不是目的。起初,这种攻击很简单:攻击者传递恶意数据给有漏洞的应用程序,应用程序将这些数据包含在HTTP响应头中。要想成功地使用该攻击,应用程序必须允许响应头中包含CR(回车,即%0d或者r)和LF(换行,即%0a或者n)字符。这些字符不仅使得攻击者可以控制应用程序发送的部分响应头和响应体,还使得攻击者可以创建能够完全控制的HTTP响应。

Example:面的代码段从HTTP请求中读取一篇博客文章的作者名author,然后将它放入HTTP响应的cookie头。

String author =request.getParameter(AUTHOR_PARAM);

Cookie cookie = newCookie(“author”, author);

cookie.setMaxAge(cookieExpiration);

response.addCookie(cookie);

假如在HTTP请求中提交的字符串是由标准的文字和数字字符组成,如“Jane

Smith”,那么HTTP响应中包含的cookie可能是如下形式:

HTTP/1.1 200 OK

Set-Cookie: author=Jane Smith

然而,因为cookie的值是根据未经验证的用户输入生成的,所以只有当提交的Author.Text的值中不包含任何CR和LF字符时,HTTP响应才会是以上形式。如果攻击者提交了一个恶意字符串,比如“WileyHackerrnHTTP/1.1200

OKrn…”,那么HTTP响应将被分割为如下两个响应:

HTTP/1.1 200 OK

Set-Cookie: author=Wiley Hacker

HTTP/1.1 200 OK

…显然,第二个响应是由攻击者完全控制的,它能够构成任何攻击者想要的响应头和响应体。这种攻击者可以构造任意HTTP响应的能力可以导致各种攻击,包括跨用户攻击、web和浏览器缓存中毒、跨站脚本和页面劫持。跨用户攻击:攻击者可以制作一个专门的请求发给有漏洞的服务端,服务端将会创建两个响应,第二个响应会被误解为是另一个请求的响应,这个请求是由使用同一个TCP连接访问服务端的另一个用户发来的。当攻击者诱使用户自己提交恶意请求时,或者更隐蔽的,当攻击者与用户共用同一个TCP连接到服务端(比如共享的代理服务)时,就可以完成上述攻击。最好的情况下,攻击者可以通过这种攻击使用户认为应用程序已经被修改了,导致用户对应用程序的安全性失去信心。最糟的情况下,攻击者可以模仿应用程序,提供相似的内容,诱使用户将私有信息(如账号和密码)发送给攻击者。跨站脚本:一旦攻击者可以控制应用程序发送的响应,他们就可以选择各种恶意内容来提供给用户。跨站脚本是最常见的攻击,它在用户浏览器上执行响应中包含的恶意JavaScript或者其他代码。基于XSS的攻击种类几乎是无限的,但是它们通常会包括:传送私有数据(如cookies或者其他session信息)给攻击者,将受害者的浏览器重定向到攻击者所控制的web内容中,或者假借有漏洞的站点在用户机器上进行其他恶意操作。针对一个有漏洞的应用程序的用户,最常见的也是最危险的攻击方式是通过JavaScript将session和认证信息发送给攻击者,使得攻击者能够完全控制受害者的账号。页面劫持:除了通过有漏洞的应用程序来发送恶意内容给用户以外,这种攻击还能够将服务端生成的要发送给用户的敏感内容重定向给攻击者。攻击者通过一个请求生成两个响应,一个是服务端原有的响应,一个是攻击者制造的响应。然后攻击者通过一个中间节点,如共享的代理服务,将服务端产生的发给用户的响应指向攻击者。因为攻击者制造的请求产生了两个响应,第一个作为攻击者请求的响应,第二个会保留在响应池中。当用户通过同一个TCP连接提出HTTP请求时,由于攻击者制造的响应已经存在,所以该响应会被当作用户的响应发送给用户。然后攻击者发送第二次请求给服务端,此时代理服务器就会把服务端生成的原本要发给用户的响应当作攻击者的响应发送给攻击者,这样攻击者就能从该响应中获取危及用户安全的敏感信息。

l解决方案

要想进行HTTP响应截断攻击,应用程序必须允许响应头中包含CR(回车,即%0d或者r)和LF(换行,即%0a或者n)字符。所以我们可以在数据进入应用程序之前把可能的危险拦截,针对CR和LF字符进行过滤。

让我们来看看这些关键的风险如何应用于JavaEE的web应用程序和web服务:

1、注入攻击

在编写程序时,任何可疑的信息输入都可能是注入攻击,比如
request.getParameter(), request.getCookie()
以及request.getHeader(),甚至在用户命令行接口也存在注入风险。如果开发人员以数据和
SQL 命令拼接的方式形成 SQL 语句就存在 SQL 注入风险,比如: “SELECT *
FROM users WHERE username=‘“ + request.getParameter(“user”) + “‘ AND
password=‘“ + request.getParameter(“pass”) = “‘“;
开发者正确的写法应该是用 PreparedStatement 方式避免黑客有机会改变 SQL
语句的原意进而控制数据库。除了 SQL
注入还有很多注入攻击的方式,包括:Command Injection, LDAP Injection, 与
Expression Language (EL)
Injection,所有的这些注入都非常非常危险,在编写接受数据的模块时一定要非常非常小心。

1.注入

注入发生在开发人员获取不可信的信息,例如request.getParameter(),request.getCookie(),或request.getHeader(),并在命令接口中使用它的任何时候。例如,SQL注入在你连接不可信的数据到常规SQL查询,如“SELECT
* FROM users WHERE username=‘“ + request.getParameter(“user”) + “‘ AND
password=‘“ + request.getParameter(“pass”) =
“‘“时发生。开发人员应该使用PreparedStatement来防止攻击者改变查询的含义和接管数据库主机。还有许多其他类型的注入,如Command注入、LDAP注入以及Expression
Language (EL)
注入,所有这些都极度危险,因此在发送数据到这些解释器的时候要格外小心。

2、失效的身份和回话管理

JavaEE
对身份校验和会话管理都能够支持,但是安全方面做得很不够,有很多种方法可以破坏。程序员不得不确保每个身份校验都通过
SSL 安全通道,并且还要确保没有异常发生。如果不幸暴露了一个
JSESSIONID,黑客只要掌握了该 JSESSIONID
就可以劫持会话,很多时候为了防止会话固定攻击还不得不对 JSESSIONID
进行混淆。使用 response.encodeURL() 将 JSESSIONID 加到 URL
里面是非常危险的,JSESSIONID 很容易被偷窃,这种行为一定要避免。

2.损坏的验证和会话管理

JavaEE支持身份验证和会话管理,但这里有很多容易出错的地方。你必须确保所有经过验证流量都通过SSL,没有例外。如果你曾经暴露JSESSIONID,那么它就可被用来在你不知情的情况下劫持用户会话。你应该旋转JSESSIONID,在用户进行身份验证以防止会话固定攻击(Session
Fixation
attack)的时候。你应该避免使用response.encodeURL(),因为它会添加用户的JSESSIONID到URL,使得更容易被披露或被盗。

3、Cross-Site Scripting (XSS)

若应用程序收到不可信的数据,在没有进行适当的验证和转义的情况下,就将它发送给一个网页浏览器,就会产生跨站脚本攻击(简称
XSS)。XSS
允许攻击者在受害者的浏览器上执行脚本,从而劫持用户会话、危害网站、或者将用户转向恶意网站。

3.跨站点脚本攻击(XSS)

XSS发生在当JavaEE开发人员从HTTP请求获取不可信的信息,并把它放到HTTP响应中,而没有适当的上下文输出编码的时候。攻击者可以利用这个行为将他们的脚本注入网站,然后在这个网站上劫持会话和窃取数据。为了防止这些攻击,开发人员需要执行敏感的上下文输出编码。如果你把数据转换成HTML,使用&#xx;格式。请务必括号HTML属性,因为有很多不同字符而不带括号的属性会被终止。如果你把不可信的数据放到JavaScript,URL或CSS中,那么对于每一个你都应该使用相应的转义方法。并且在和嵌套上下文,如一个用Javascript写的在HTML属性中的URL打交道时,要非常小心。你可能会想要编码库,例如OWASP
ESAPI的帮助。

4、不安全的直接对象引用

当开发人员暴露一个对内部实现对象的引用时,例如,一个文件、目录或者数据库密匙,就会产生一个不安全的直接对象引用。在没有访问控制检测或其他保护时,攻击者会操控这些引用去访问未授权数据。

4.不安全的直接对象引用

任何时候应用程序暴露了一个内部标识符,例如数据库密钥,文件名,或hashmap索引,攻击者就可以尝试操纵这些标识符来访问未经授权的数据。例如,如果你将来自于HTTP请求的不可信的数据传递到Java文件构造器,攻击者就可以利用“../”或空字节攻击来欺骗你的验证。你应该考虑对你的数据使用间接引用,以防止这种类型的攻击。ESAPI库支持促进这种间接引用的ReferenceMaps。

5、安全配置错误

现代 JavaEE 应用程序和框架如 Struts,Spring
都有很多的安全配置,当使用这些框架一定要确保这些配置是正确的。比如在开发
Web 应用程序时一定要当心 <security-constraint> 里的
<http-method> 标签,该标签的意思是 security-constraint
只作用于标签里面列出的方法,黑客可以利用这个使用列表以外的方法如:HEAD
和 PUT 进行攻击,从而越过安全限制。大多数情况下开发者应该删掉 web.xml
里面的 <http-method>标签。

5.错误的安全配置

现代的JavaEE应用程序和框架,例如Struts和Spring中有着大量的安全设置。确定你已经浏览过这些安全设置,并按你想要的那样设置。例如,小心<security-constraint>中的<http-method>标签。这表明安全约束仅适用于列出的方法,允许攻击者使用其他HTTP方法,如HEAD和PUT,来绕过整个安全约束。也许你应该删除web.xml中的<http-method>标签。

6、敏感信息泄露

Java 使用扩展库的方式实现加解密,Java
提供通用的接口,任何用户,只需要简单的配置,都可以根据接口来实现加密,这样的好处是扩展性很强,弊端是如何正确使用密码库是非常不容易事情:第一步,找一个基于
JCE 的顶级加密库,提供简单、安全的加密方法,Jasypt 与 ESAPI
就非常不错。第二步,应该使用强加密算法如:加密用 AES,哈希用
SHA256,像密码这种敏感信息,广哈希是不够的,黑客可以通过 Rainbow
表来破译,因此需使用自适应安全算法如 bcrypt 或
PBKDF2。任何使用不当都可能造成敏感信息泄露。

6.敏感数据暴露

Java有大量的加密库,但它们不容易正确使用。你应该找到一个建立在JCE基础上的库,并且它能够方便、安全地提供有用的加密方法。比如Jasypt和ESAPI就是这样的库。你应该使用强大的算法,如AES用于加密,以及SHA256用于hashes。但是要小心密码hashes,因为它们可以利用Rainbow
Table被解密,所以要使用自适应算法,如bcrypt或PBKDF2。

7、功能级访问控制缺失

JavaEE 同时支持声明式和编程两种访问控制方式,像 Spring
等框架也支持基于注解的访问控制,但是很多应用程序还是选择创建自己的访问控制流程,其实这是非常危险的行为。更重要的是要确保每一个暴露出去的接口和
Web
服务要有正确的访问控制,千万不要想当然的假设客户应该可以控制一切,这样黑客就可以直接访问程序了。

7.缺少功能级访问控制

JavaEE支持声明式和程序式的访问控制,但很多应用程序仍然会选择创造它们自己的方案。像Spring框架也有基于注释的访问控制基元。最重要的事情是要确保每一个暴露的端口都要有适当的访问控制检查,包括web服务。不要以为客户端可以控制任何东西,因为攻击者会直接访问你的端点。

8、 跨站请求伪造(CSRF )

每一个状态改变,应用程序都应该校验该请求是否伪造,开发者在每一个用户会话里面放置一个随机令牌,然后每次请求进来都进行校验,否则攻击者可能会创建一些包含有害标签,例如:IMG,
SCRIPT, FRAME 或者
FORM,这些标签可能会指向没有保护的应用程序,当受害者访问这样的页面,浏览器就会自动产生一个伪造的
HTTP 请求到标签里指定的 URL,这个 URL 通常会包含受害者的凭证。

8.跨站点伪造请求(CSRF)

每个改变状态的端点需要验证请求有没有被伪造。开发人员应该在每个用户的会话中放入随机令牌,然后当请求到达的时候验证它。否则,攻击者就可以通过链接到未受保护的应用程序的恶意IMG,SCRIPT,
FRAME或FORM标签等创建“攻击”页面。当受害者浏览这种页面时,浏览器会生成一个“伪造”的HTTP请求到URL在标签中被指定的任何内容,并且自动包括受害人的认证信息。

9、使用含有已知漏洞的组件

现代 JavaEE
应用程序通常会包括数百种库,尤其像依赖管理工具问世5年来,这个数目更是爆炸式的增长。广泛应用的Java
库都包含了很多已知漏洞,这些漏洞非常危险。对这些漏洞没有其他办法,只能等库的提供商修复漏洞,及时更新到最新版本。

9.使用带有已知漏洞的组件

现代的JavaEE应用程序有数百个库。依赖性解析工具,如Maven,导致了这个数字在过去五年时间里出现爆炸式增长。许多广泛使用的Java库都有一些已知的漏洞,会让web应用程序被完全颠覆。解决的办法是及时更新库。不要只运行单一扫描,因为新的漏洞每天都在发布。

10、未验证的重定向和转发

Web
应用程序经常将用户重定向或转发到其他网页和网站,并且利用不可信的数据去判定目的页面。如果没有得到适当验证,攻击者可以重定向受害用户到钓鱼软件或恶意网站,或者使用转发去访问未授权的页面,
在 JavaEE Web 程序里当调用 response.sendRedirect() 在使用
request.getParameter() 或 request.getCookie()
去获取不信任的数据时,经常会发生这种情况。

每个 JavaEE
程序员一定会经常遇到这十个安全问题,同时新的攻击和漏洞不断地被发现,我们现在能做的就是在开发、测试和部署的过程中不断地用安全代码检查工具对项目进行扫描,检查不修复漏洞。

大家可以尝试用 Eclipse
的一些免费对比插件来检查这些漏洞,这些不仅是静态分析工具,C4E
是一个非常有代表意义的工具,它利用 Java Instrumentation API
去见监控应用中所有和安全相关的内容。
它还可以实时分析整个数据流,在一个复杂的应用里从请求开始跟踪数据。 比如
JavaEE Web 应用里常见的数据流如下:代码从 request 取得参数,用 base64
解码,把数据存到 Map 里,再将 Map 存到一个 Bean 里面,然后将这个Bean
放到 Session 里作为 attribute,最后从 JSP 里取出,使用 EL 语言将这个
Bean 值填入页面。Eclipse 对比工具就可以跟踪这个数据流并报告是否存在 XSS
漏洞。这个工具非常方便,甚至对使用了非常复杂的框架和库的应用程序也管用,较现有的很多分析工具在速度,准确性和易用性上都有明显优势。

当然,还有现在非常流行的
RASP(Runtime
Aplication Security
Protector),也是对付这十大安全问题的利器,它将代码实时检查和实时拦截相结合,将安全保护代码和应用程序结合在一起,像疫苗一样使应用程序具备自我免疫的能力。这是
Gartner
极力推荐的应用程序安全保护方案,它使用非常方便,保护实时彻底,容易使用,不需要修改任何应用程序代码就可以轻松实现安全保护。

10.未经验证的转址和转送

任何时候你的应用程序使用不可信的数据,例如request.getParameter()或request.getCookie(),在调用response.sendRedirect()时,攻击者可以强制受害者的浏览器转到一个不受信任的网站,目的在于安装恶意软件。forward也存在着类似的问题,不同之处在于攻击者可以转送他们自己到未经授权的功能,如管理页面。一定要仔细验证转址和转送目标。

你应该持续留意这些问题。新的攻击和漏洞总是在被发现。理想情况下,你可以集成安全检查到现有的构建、测试和部署过程。

要在应用程序中检查这些问题,可以尝试免费的Contrast for Eclipse插件
。这不是一个简单的静态分析工具。相反,C4E利用Java仪表化API,来监视应用程序中与安全相关的一切。
C4E甚至能实时地做到完整的数据流分析,因此它可以跟踪来自于请求的数据,通过一个复杂的应用程序。例如,假设你的代码获取了一个参数值,用base64解码它,再存储于map中,把map放到数据bean中,再将bean存储到一个会话属性中,在JSP中获取bean的值,并使用EL将这个值插入到网页。Contrast
for Eclipse可以跟踪这些数据并报告XSS漏洞。哪怕你正在使用的是复杂的框架和库。没有其他工具能在速度,精度和易用性方面与之媲美。

你可以在Eclipse Marketplace找到Contrast for
Eclipse。然后,只需转到服务器选项卡“Start with
Contrast”——剩下的就交给它办吧。

发表评论

电子邮件地址不会被公开。 必填项已用*标注