小墨の博客

梦想需要付诸行动,否则只能是梦

web开发常出现的代码缺陷

本文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

尊重他人劳动成果,共创和谐网络环境。点击版权声明查看本站相关条款。

    发表评论:

    搜索
    本文二维码
    标签列表
    站点信息
    • 文章总数:547
    • 页面总数:20
    • 分类总数:96
    • 标签总数:213
    • 评论总数:63
    • 浏览总数:287025

    | | |
    | |  Z-Blog PHP