本文TXT下载:web开发常出现的代码缺陷.txt
反射型XSS攻击【高危】
详细信息
应用程序通过Web请求获取不可信的数据,在未检验数据是否存在恶意代码的情况下,便将其传送给了Web用户,应用程序将容易受到反射型XSS攻击。
例如,下面PHP代码中,将用户输入的参数直接输出到页面上:
$param = $_GET['param']; //Attackers may input code such as “alert(document.cookie);”
echo "
".$param."
";
?>
如果param里有包含恶意代码,那么Web浏览器就会执行该代码,应用程序将受到反射型XSS攻击。
部分现代浏览器已经能较好的识别并阻止反射型XSS攻击,不过我们不应该依赖这种机制,毕竟不是所有的浏览器都能很好的识别这种攻击。
修复建议
为了避免反射型XSS攻击,建议采用以下方式进行防御:
(1)输入验证:对用户的输入进行合理验证(比如只允许输入字母或数字)。
(2)输出编码:根据数据在HTML文档中出现的位置(HTML标签、HTML属性、JavaScript脚本、CSS、URL等),对所有不可信数据进行恰当的输出编码。例如,在HTML标签或者HTML属性中输出不可信的数据,可以采用htmlentities()和htmlspecialchars()进行HTML编码。
(3)为Cookie设置HTTPOnly属性,浏览器将禁止页面的JavaScript访问带有HTTPOnly属性的Cookie,从而避免攻击者利用跨站脚本漏洞进行Cookie劫持攻击。给Cookie添加HTTPOnly属性的代码如下:
setcookie("abc", "test", 0, "abc", "app.abc.com", true, true); //最后一个参数用来设置HTTPOnly属性。
?>
SQL注入【高危】
详细信息
SQL注入是一种数据库攻击手段。攻击者通过向应用程序提交恶意代码来改变原SQL语句的含义,进而执行任意SQL命令,达到入侵数据库乃至操作系统的目的。
例如,下面代码使用用户提交的数据来构造SQL查询:
$name = $_POST['name'];
mysql_query("SELECT * FROM tbl_users WHERE userLogin = '$name'");
?>
如果攻击者提供如下的name字符串进行SQL注入:
validuser' OR '1'='1
当其注入到命令时,命令就会变成:
SELECT * FROM tbl_users WHERE userLogin = 'validuser' or '1' = '1'
这样就导致tbl_users表的所有信息被泄露。
更坏的情况是,攻击者可以输入如下的字符串:
validuser'; DELETE FROM tbl_users; SELECT * FROM tbl_users WHERE '1'='1
这样,SQL语句就变成了三条,导致整个tbl_users表被删除。
修复建议
SQL注入的根本在于本应是数据的部分,被当作了SQL命令来执行。防止SQL注入的方法如下:
(1)正确使用预编译SQL语句,绑定变量。例如,可以将描述的例子改写为使用参数化SQL查询的方式:
$mysqli = new mysqli($host,$user, $password, $db);
$name = $_POST['name'];
$query = "SELECT * FROM tbl_users WHERE userLogin = ?";
$stmt = $mysqli->prepare($query);
$stmt->bind_param('s',$name);
$stmt->execute();
?>
(2)如果构造SQL指令时需要动态加入约束条件,可以通过创建一份白名单,从中选择需要约束的条件字段,来避免SQL注入攻击。
路径遍历【高危】
详细信息
应用程序对用户输入未经合理校验,就作为路径传送给一个文件API,将导致路径遍历攻击。攻击者可能会使用一些特殊的字符(如“..”和“/”)绕过限制,访问一些受保护的文件或目录。
例如,下面的代码使用一个$_GET参数作为文件名:
$filename = $_GET['filename'];
unlink("/safe_dir/" . $filename);
?>
如果攻击者传入类似于“../../../../../../etc/passwd”的文件名,将可能导致系统的重要文件被删除。
修复建议
防止路径遍历的方法包括:
(1)避免让用户控制需要操作的路径。
(2)确实需要用户提供路径的,应该使用白名单来限制用户的输入范围。
(3)如果白名单无法满足业务逻辑的需要,则需要限制用户的输入(比如只允许输入字母数字等)来降低危害。
以下例子采用白名单来限制用户的输入:
$fileindex = intval($_GET["fileindex"]);
$files = array("a.txt", "b.txt", "c.txt");
unlink("/tmp/". $files[$fileindex]);
?>
硬编码密码【高危】、有风险的硬编码【低危】
详细信息
硬编码密码容易导致系统的安全性降低。
例如,以下代码使用硬编码密码,用于连接SQL服务器:
$password = "mypassword";
$conn = mysql_connect("server", "root", $password);
?>
任何对该代码具有访问权限的人都能获取到这个密码。另外,如果以后需要修改这个密码,则必须要修改源代码,在生产环境中修改源代码并不是一个好的选择。
在某些情况下,一些恶意开发者在代码中留下的后门,也会在代码中留下一段硬编码密码,以便攻击者利用该密码攻击系统。
修复建议
程序中不应采用硬编码密码,对于重要的密码信息,应该采取人工输入或其他安全的外部渠道来获取。
不安全的哈希算法【中危】
详细信息
在安全性要求较高的系统中,不应使用被业界公认的不安全的哈希算法(如MD5、SHA-1等)来保证数据的完整性。
例如,以下代码使用MD5算法来加密密码:
$password = $_GET['password'];
if(md5($password) === $db_pass){
//auth success
}
?>
修复建议
在安全性要求较高的系统中,应采用散列值>=224比特的SHA系列算法(如SHA-224、SHA-256、SHA-384和SHA-512)来保证敏感数据的完整性。
例如,以下是修改过的代码:
$password = $_GET['password'];
if(hash("sha384", $password) === $db_pass){
//auth success
}
?>
系统信息泄露:外部【中危】
详细信息
系统数据或调试信息通过网络连接或其他方式发送到远程机器,被攻击者查看到,将有助于攻击者了解系统并制定相应的攻击计划。
例如,下面代码片段中,堆栈信息被输出到浏览器:
debug_print_backtrace();
?>
修复建议
时刻对调试信息的处理保持警惕。特别是在生产环境中,避免使用调试函数。即使最简短的调试信息,也有可能给攻击者以提示。
侵犯隐私【中危】
详细信息
由于应用程序没有正确的处理一些私人数据(例如信用卡号),导致这些数据被不相关、未授权的账户获取到,这样就发生了隐私泄露。
例如,下面的例子演示了私人密码被记录到了日志中:
...
$pwd = get_password($user)
...
if($pwd != $input_pwd) {
log("Login failed:" . $user . "," . $input_pwd);
}
...
密码等隐私信息绝不允许直接存储到任何地方,包括开发者认为很安全的地方。
修复建议
当保护隐私和其他方面的问题发生冲突时,优先考虑保护隐私。
有风险的SQL查询【中危】
详细信息
SQL注入是一种数据库攻击手段。攻击者通过向应用程序提交恶意代码来改变原SQL语句的含义,进而执行任意SQL命令,达到入侵数据库乃至操作系统的目的。
例如,下面代码使用用户提交的数据来构造SQL查询:
$name = $_POST['name'];
mysql_query("SELECT * FROM tbl_users WHERE userLogin = '$name'");
?>
如果攻击者提供如下的name字符串进行SQL注入:
validuser' OR '1'='1
当其注入到命令时,命令就会变成:
SELECT * FROM tbl_users WHERE userLogin = 'validuser' or '1' = '1'
这样就导致tbl_users表的所有信息被泄露。
更坏的情况是,攻击者可以输入如下的字符串:
validuser'; DELETE FROM tbl_users; SELECT * FROM tbl_users WHERE '1'='1
这样,SQL语句就变成了三条,导致整个tbl_users表被删除。
程序员常常会使用过滤函数来对用户输入进行过滤,试图避免SQL注入,但这经常无法完全避免SQL注入。
例如,下面代码使用mysqli_real_escape_string过滤用户输入:
$id = $_POST[ 'id' ];
$id = mysqli_real_escape_string($conn, $id);
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
可以看到,例子中的参数并未用单引号包围,所以这里即使使用了过滤函数,我们依然可以构造任意的查询语句。
修复建议
SQL注入的根本在于本应是数据的部分,被当作了SQL命令来执行。防止SQL注入的方法如下:
(1)正确使用预编译SQL语句,绑定变量。例如,可以将描述的例子改写为使用参数化SQL查询的方式:
$mysqli = new mysqli($host,$user, $password, $db);
$name = $_POST['name'];
$query = "SELECT * FROM tbl_users WHERE userLogin = ?";
$stmt = $mysqli->prepare($query);
$stmt->bind_param('s',$name);
$stmt->execute();
?>
(2)如果构造SQL指令时需要动态加入约束条件,可以通过创建一份白名单,从中选择需要约束的条件字段,来避免SQL注入攻击。
HTTP响应截断【中危】
详细信息
程序从一个不可信的数据源获取数据,未进行验证就置于HTTP头部中发给用户,可能会使HTTP头部被篡改,导致跨站脚本、网页劫持、Cookie篡改、重定向、缓存中毒、用户信息涂改等攻击。
例如:下列代码片段中,程序从HTTP请求中获取author的值,并将其设置到HTTP响应的头部中。
$author = $_GET['AUTHOR_PARAM'];
header("author: $author");
?>
如果请求中提交的是一个“Jane Smith”字符串,那么包含该头部的HTTP响应可能表现为以下形式:
HTTP/1.1 200 OK
...
Author: Jane Smith
...
那么如果攻击者提交的是一个恶意字符串,比如“Wiley Hacker\r\nHTTP/1.1 200 OK\r\n...”,那么HTTP响应就会被分割成以下形式的两个响应:
HTTP/1.1 200 OK
...
Author: Wiley Hacker
HTTP/1.1 200 OK
...
这样第二个响应已完全由攻击者控制,攻击者可以用所需的HTTP头和正文内容构建该响应实施攻击。幸运的是,目前所有的主流Web服务器都已经对这种攻击做了妥善的处理。PHP在header的值中包含换行符时,会产生一个警告,并丢弃掉该HTTP头。尽管如此,对HTTP头部的篡改仍然会导致重定向、Cookie篡改等攻击。
修复建议
防止HTTP响应截断的方法:
(1)根据业务逻辑对输入进行验证,如输入只允许是数字或字母。
(2)采取白名单的方式,只允许特定的字符串出现在HTTP头部中。
例如,下面代码片段中,能过滤掉非法输入:
$author = intval($_GET['AUTHOR_PARAM']);
$safe_list = array("john", "xiao ming");
If($author < 0 || $author > 1){
$author = 1;
}
header("author: ".$safe_list[$author]);
?>
Cookie:未经过SSL加密【中危】
详细信息
程序创建Cookie时,未设置secure标记,存在安全风险。
现代浏览器支持为每个Cookie设置secure标记,用于通知浏览器,仅在HTTPS协议下传送Cookie。由于HTTP方式的通信安全性较差,存在窃听、篡改等风险,所以应该尽可能避免Cookie信息以HTTP方式传送,特别是当它包含敏感信息时。
例如,下面代码片段中,在生成Cookie时,未设置secure标记:
setcookie("privateCookie", "privateMessage", 0, "/", "www.example.com");
?>
由于没有设置secure标记,这个包含敏感信息的cookie就有可能通过HTTP方式发送。而由于HTTP的不安全特性,这些信息很容易被攻击者截获。
修复建议
为Cookie设置secure标记,浏览器将只能通过较安全的HTTPS方式发送Cookie,私密Cookie被窃取的风险大大降低。
PHP函数setcookie的第6个参数用于设置这个标记,例如,以下代码将Cookie的secure标记设置为 true:
setcookie("privateCookie", "privateMessage", 0, "/", "www.example.com", true);
?>
不安全的随机数【低危】
详细信息
伪随机数是由数学算法实现的,它真正随机的地方在于种子(seed)。种子一旦确定后,再通过同一伪随机数算法计算出来的随机数,其值是固定的,对此计算所得值的顺序也是固定的。如果使用rand()生成的随机数用于一些重要的地方,会比较危险。
例如,以下程序用rand()函数产生的随机数来作为重要的ID标识:
$id_check = rand();
?>
这个标识用来校验某ID是否登录,假如攻击者能猜出这个标识,那么就能获取到敏感信息:
$check = $_GET['check'];
if($check == $id_check){
//do some important things.
}
?>
修复建议
在安全性要求较高的应用中,应使用更安全的随机数生成器。
例如:在PHP5.3.0及其之后的版本中,若是支持openSSL扩展, 可以直接使用以下函数来生成随机数:
string openssl_random_pseudo_bytes ( int $length [, bool &$crypto_strong ] )
在PHP7中,引入了两个更安全的随机数生成函数random_bytes和random_int,用于取代PHP5的rand和mt_rand函数。
除此之外,在算法上还可以通过将多个随机数的组合,以增加随机数的复杂性。
注释中的密码【低危】
详细信息
应用程序在注释中保留密码等敏感信息,存在安全隐患。如果攻击者能够获取到源代码,那么注释中的密码信息将有助于攻击者获取更多信息或权限。
例如,以下代码在注释中保留了默认密码:
//Mysql username: root
//Mysql password: somepass
?>
修复建议
应用程序不应在注释中保留密码等敏感信息。
文件上传【低危】
详细信息
文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本获得了执行服务器端命令的能力。
应用系统如果需要文件上传功能,在文件上传后,服务器的处理逻辑做得不够安全,就会出现安全问题。文件上传导致的安全问题一般有:
(1)上传文件是Web脚本语言,服务器的脚本解释器解释并执行了用户上传了的脚本文件,导致代码执行。
(2)上传文件是Flash的策略文件crossdomain.xml, 攻击者可以控制Flash在该域下的行为。
(3)上传文件是病毒、木马文件,攻击者用以诱骗用户或者管理员下载执行。
(4)上传文件是钓鱼图片或者包含了脚本的图片,在某些版本的浏览器中会被作为脚本执行,被用于钓鱼和欺诈。
例如,在下面PHP代码片段中,通过“黑名单”的方式检测文件后缀,来确定上传的文件是否安全。
$Config['AllowedExtension']['File'] = array();
$Config['DeniedExtensions']['File'] = array('php','php3','php5','phtml','asp','aspx','ascx','jsp','cfm','cfc','pl','bat','exe','dll','reg','cgi');
黑名单很难过滤掉所有不合法的类型,如果上传类型是php2、php4、inc、pwml、asa、cer等文件,可能导致安全问题。
修复建议
如果应用程序不需要文件上传功能,应该禁用文件上传功能。PHP中禁用file_uploads的方式:
(1)在php.ini文件中配置:file_uploads = 'off'
(2)也可以在Apache httpd.conf文件中配置:php_flag file_uploads off
如果应用程序需要文件上传功能,可以参考以下建议:
(1)文件上传的目录设置为不可执行。
(2)采用白名单方式判断文件类型。在判断文件类型时,可采用MIME Type、 后缀检查等方式。
(3)使用随机数改写文件名和文件路径。 如果应用程序采用随机数改写了文件名和路径,可以很大程度上增加攻击的成本。
(4)对于图片的处理,可以采用压缩函数或者resize函数,在处理图片的同时,破坏图片中可能包含的脚本代码。
Cookie:路径范围过大【低危】
详细信息
开发者常常将Cookie路径设置为根路径。有些情况下,在同一个域下面部署了多个应用程序,这时,如果某应用程序将Cookie路径设置为”/“,那么同一域下的所有应用程序都将能访问到这个Cookie。
例如,某Web应用部署在http://www.phpcms.com/app上,当用户访问时,应用会给用户发送路径为”/“的Cookie:
setcookie("email", $email, 0, "/", "www.phpcms.com", true, true);
?>
如果攻击者控制了同一域下的另一个不太安全的Web应用http://www.phpcms.com/insecureapp,那么用户在访问这个不太安全的Web应用时,就有可能将自己的电子邮箱泄露给攻击者。
修复建议
尽可能缩小Cookie路径的范围,坚持权限最小原则。
例如,下面的代码片段中,将Cookie路径设置为“/app”:
setcookie("email", $email, 0, "/app", "www.phpcms.com", true, true);
?>
Cookie:未设置HttpOnly标记【低危】
详细信息
程序创建Cookie时,未设置HTTPOnly标记,存在安全风险。
现代浏览器支持为每个Cookie设置HTTPOnly标记,用于通知浏览器,不允许客户端脚本访问Cookie。使用客户端脚本访问Cookie,是攻击者利用XSS漏洞窃取用户隐私数据的主要方式。
例如,下面代码片段中,在生成Cookie时,未设置HTTPOnly标记:
setcookie("privateCookie", "privateMessage", 0, "/", "www.example.com", true);
?>
修复建议
为Cookie设置HTTPOnly标记,浏览器将不允许客户端脚本访问Cookie,可有效缓解XSS漏洞造成的威胁。
PHP函数setcookie的第7个参数用于设置这个标记,例如,以下代码将Cookie的HTTPOnly标记设置为 true:
setcookie("privateCookie", "privateMessage", 0, "/", "www.example.com", true, true);
?>
Cookie:持久【低危】
详细信息
默认情况下,PHP所创建的Cookie是非持久的,即关闭浏览器后就自动清除。可以通过调用PHP函数或配置ini文件来使浏览器保留这些Cookie,直到函数或ini配置所指定的日期。
例如,下列代码片段中,指定保存电子邮箱的Cookie在1年后过期:
setcookie("email", $email, time()+60*60*24*365);
?>
修复建议
避免在持久性Cookie中保存敏感信息。对于持久性Cookie中的数据,设置一个合理的过期时间。
例如,以下代码设置Cookie在关闭浏览器后过期:
setcookie("email", $email, 0, "/app", "www.phpcms.com", true, true);
?>
以上内容来自奇安信代码卫士
本站文章除注明转载/出处外,均为原创,若要转载请务必注明出处。转载后请将转载链接通过邮件告知我站,谢谢合作。本站邮箱:admin@only4.work
尊重他人劳动成果,共创和谐网络环境。点击版权声明查看本站相关条款。