这篇文章主要为大家详细介绍了PHP代码审核的简单示例,具有一定的参考价值,可以用来参考一下。
感兴趣的小伙伴,下面一起跟随四海网的小玲来看看吧!
概述
代码审核,是对应用程序源代码进行系统性检查的工作。它的目的是为了找到并且修复应用程序在开发阶段存在的一些漏洞或者程序逻辑错误,避免程序漏洞被非法利用给企业带来不必要的风险
代码审核不是简单的检查代码,审核代码的原因是确保代码能安全的做到对信息和资源进行足够的保护,所以熟悉整个应用程序的业务流程对于控制潜在的风险是非常重要的。
审核人员可以使用类似下面的问题对开发者进行访谈,来收集应用程序信息。
应用程序中包含什么类型的敏感信息,应用程序怎么保护这些信息的?
应用程序是对内提供服务,还是对外?哪些人会使用,他们都是可信用户么?
应用程序部署在哪里?
应用程序对于企业的重要性?
最好的方式是做一个 checklist,让开发人员填写。Checklist 能比较直观的反映应用程序的信息和开发人员所做的编码安全,它应该涵盖可能存在严重漏洞的模块,例如:数据验证、身份认证、会话管理、授权、加密、错误处理、日志、安全配置、网络架构。
输入验证和输出显示
大多数漏洞的形成原因主要都是未对输入数据进行安全验证或对输出数据未经过安全处理,比较严格的数据验证方式为:对数据进行精确匹配
接受白名单的数据
拒绝黑名单的数据
对匹配黑名单的数据进行编码
在 PHP 中可由用户输入的变量列表如下:
$_SERVER
$_GET
$_POST
$_COOKIE
$_REQUEST
$_FILES
$_ENV
$_HTTP_COOKIE_VARS
$_HTTP_ENV_VARS
$_HTTP_GET_VARS
$_HTTP_POST_FILES
$_HTTP_POST_VARS
$_HTTP_SERVER_VARS
我们应该对这些输入变量进行检查
命令注入
安全威胁
命令注入攻击是通过把HTML代码输入一个输入机制(例如缺乏有效验证限制的表格域)来改变网页的动态生成的内容,而这样就可能会导致恶意命令掌控用户的电脑和他们的网络。PHP执行系统命令可以使用以下几个函数:system、exec、passthru、``、shell_exec、popen、proc_open、pcntl_exec,我们通过在全部程序文件中搜索这些函数,确定函数的参数是否会因为外部提交而改变,检查这些参数是否有经过安全处理。
代码示例
例1:
代码如下:
//ex1.php
<?php
/* 四海网 www.q1010.com */
$dir = $_GET["dir"];
if (isset($dir))
{
echo "<pre>";
system("ls -al".$dir);
echo "</pre>";
}
?>
代码如下:
http:// localhost/ex1.php?dir=| cat /etc/passwd
代码如下:
system("ls -al | cat /etc/passwd");
防范方法
1、尽量不要执行外部命令
2、使用自定义函数或函数库来替代外部命令的功能
3、使用escapeshellarg函数来处理命令参数
4、使用safe_mode_exec_dir指定可执行文件的路径
esacpeshellarg函数会将任何引起参数或命令结束的字符转义,单引号“'”,替换成“\'”,双引号“"”,替换成“\"”,分号“;”替换成“\;”, 用safe_mode_exec_dir指定可执行文件的路径,可以把会使用的命令提前放入此路径内。
代码如下:
safe_mode = On
safe_mode_exec_di r= /usr/local/php/bin/
跨站脚本攻击有以下三种攻击形式:
(1) 反射型跨站脚本攻击
攻击者会通过社会工程学手段,发送一个 URL 连接给用户打开,在用户打开页面的同时,浏览器会执行页面中嵌入的恶意脚本。
(2) 存储型跨站脚本攻击
攻击者利用 web 应用程序提供的录入或修改数据功能,将数据存储到服务器或用户cookie 中,当其他用户浏览展示该数据的页面时,浏览器会执行页面中嵌入的恶意脚本。所有浏览者都会受到攻击。
(3) DOM 跨站攻击
由于 html 页面中,定义了一段 JS,根据用户的输入,显示一段 html 代码,攻击者可以在输入时,插入一段恶意脚本,最终展示时,会执行恶意脚本。DOM 跨站和以上两个跨站攻击的差别是,DOM 跨站是纯页面脚本的输出,只有规范使用 JAVASCRIPT,才可以防御。
恶意攻击者可以利用跨站脚本攻击做到:
(1) 盗取用户 cookie,伪造用户身份登录。
(2) 让浏览者被迫执行某页面操作,以用户身份向服务器发起请求,达到攻击目的。
(3) 结合浏览器漏洞,下载病毒木马到浏览者的计算机上执行。
(4) 衍生 URL 跳转漏洞。
(5) 让官方网站出现钓鱼页面。
(6) 蠕虫攻击
代码示例
直接在 html 页面展示“用户可控数据”,将直接导致跨站脚本威胁。
代码如下:
<?
echo “<span>$newsname</span>”;
echo “<a href=“$gifurl”>$gifname</a>”;
echo “<input type=text name=user value=\”$username\”>”;
echo “<span style=‘$stylelayout'>”. htmlentities($context).”</span>”;
?>
代码如下:
htmlspecialchars($outputString,ENT_QUOTES);
代码如下:
& --> &
< --> <
> --> >
" --> "
' --> '
代码如下:
/ --> \/
' --> \'
" --> \"
\ --> \\
安全威胁
当应用程序将用户输入的内容,拼接到 SQL 语句中,一起提交给数据库执行时,就会产生 SQL 注入威胁。由于用户的输入,也是 SQL 语句的一部分,所以攻击者可以利用这部分可以控制的内容,注入自己定义的语句,改变 SQL 语句执行逻辑,让数据库执行任意自己需要的指令。通过控制部分 SQL 语句,攻击者可以查询数据库中任何自己需要的数据,利用数据库的一些特性,可以直接获取数据库服务器的系统权限。本来 SQL 注入攻击需要攻击者对 SQL 语句非常了解,所以对攻击者的技术有一定要求。但是几年前,已经出现了大量 SQL 注入利用工具,可以让任何攻击者,只要点几下鼠标,就能达到攻击效果,这使得 SQL 注入的威胁,极大增加。
SQL注入攻击的一般步骤:
1、攻击者访问有SQL注入漏洞的站点,寻找注入点
2、攻击者构造注入语句,注入语句和程序中的SQL语句结合生成新的sql语句
3、新的sql语句被提交到数据库中执行 处理
4、数据库执行了新的SQL语句,引发SQL注入攻击
代码示例
对于输入检查不充分,导致 SQL 语句将用户提交的非法数据当作语句的一部分来执行。
示例:
代码如下:
<?
$id=$_GET['id'];
$name=$_GET['name'];
$sql="select * from news where `id`=$id and `username`='$name' ";
?>
解决方案
b)使用预处理执行 SQL 语句,对所有传入 SQL 语句中的变量,做绑定。这样,用户拼接进来的变量,无论内容是什么,都会被当做替代符号“?”所替代的值,数据库也不会
把恶意用户拼接进来的数据,当做部分 SQL 语句去解析。示例:
代码如下:
$stmt = mysqli_stmt_init($link);
if (mysqli_stmt_prepare($stmt, 'SELECT District FROM City WHERE Name=?'))
{
/* bind parameters for markers */
mysqli_stmt_bind_param($stmt, "s", $city);
/* execute query */
mysqli_stmt_execute($stmt);
/* bind result variables */
mysqli_stmt_bind_result($stmt, $district);
/* fetch value */
mysqli_stmt_fetch($stmt);
mysqli_stmt_close($stmt);
}
/* close connection */
mysqli_close($link);
文件上传威胁(File Upload)
代码如下:
<?
// oldUpload.php
if(isset($upload) && $myfile != "none“ && check($myfile_name)) {
copy($myfile, "/var/www/upload/".$myfile_name);
echo "文件".$file_name."上传成功!点击<a href=\"$PHP_SELF\">继续上传</a>";
exit;
}
//checkUpload.php
$DeniedExtensions=array('html','htm','php','php2','php3','php4','php5','ph
tml','pwml','inc','asp','aspx','ascx','jsp','cfm','cfc','pl','bat','exe','
com','dll','vbs','js','reg','cgi','htaccess','asis') ;
if($checkUpload($_FILE[‘myfile'][name], $DeniedExtensions)){copy($_FILE[‘myfile'][tmp_name],'upload/'.$_FILE[‘myfile'][name]);
}
?>
<title>文件上传</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body bgcolor="#FFFFFF">
<form enctype="multipart/form-data" method="post">
上传文件:
<input type="file" name=“myfile" size="30">
<input type="submit" name="upload" value="上传">
</form>
</body>
</html>
解决方案
安全威胁
Cross-Site Request Forgery(CSRF),伪造跨站请求。攻击者在用户浏览网页时,利用页面元素(例如 img 的 src),强迫受害者的浏览器向Web 应用程序发送一个改变用户信息的请求。由于发生 CSRF 攻击后,攻击者是强迫用户向服务器发送请求,所以会造成用户信息被迫修改,更严重者引发蠕虫攻击。
CSRF 攻击可以从站外和站内发起。从站内发起 CSRF 攻击,需要利用网站本身的业务,比如“自定义头像”功能,恶意用户指定自己的头像 URL 是一个修改用户信息的链接,当其他已登录用户浏览恶意用户头像时,会自动向这个链接发送修改信息请求。
从站外发送请求,则需要恶意用户在自己的服务器上,放一个自动提交修改个人信息的htm 页面,并把页面地址发给受害者用户,受害者用户打开时,会发起一个请求。
如果恶意用户能够知道网站管理后台某项功能的 URL,就可以直接攻击管理员,强迫管理员执行恶意用户定义的操作。
代码示例
一个没有 CSRF 安全防御的代码如下:
代码如下:
<?
$user=checkSQL($user);
$pass=checkSQL($pass);
$sql=“update UserTB set password=$user Where user=$pass”;
mysqli_stmt_execute($sql);
?>
代码中接收用户提交的参数“user,pass”,之后修改了该用户的数据,一旦接收到一个用户发来的请求,就执行修改操作。
代码如下:
<form action="http://localhost/servlet/modify" method="POST">
<input name="email">
<input name="tel">
</form>
代码如下:
<iframe src="b.htm" width="0" height="0"></frame>
代码如下:
<form id="modify" action="http://xxx.com/servlet/modify" method="POST">
<input name="email">
<input name="tel">
</form>
<script>
document.getElementById("modify").submit();
</script>
解决方案
CSRF 防御的原理是,在用户登录的时候,生成一个随机的 token,将它存储在 cookie中(默认情况,也可以放在 session 中),在生成表单时,生成一个隐藏域,隐藏域的值就等
于 token 的值。如果用户提交这个表单,就可以在接收用户请求的 web 应用中,判断隐藏域的 TOKEN 值是否和用户 COOKIE 中的 TOKEN 值一致,如果不一致或没有这个值,就判
断为 CSRF 攻击。攻击者无法预测每一个用户登录时生成的那个随机 TOKEN 值,所以无法伪造这个参数。
常见问题
(1) 为什么不直接验证 referer?
因为还有站内发出的 csrf,并且 referer 是可以被篡改的,是不可靠的数据
(2) 如果先发生 xss 攻击,攻击者可以拿到用户页面的 token 怎么办?
无解,请先做好 xss 防范。
文件包含
PHP 可 能 出 现文 件 包 含 的 函 数: include、 include_once 、 require、 require_once 、show_source、highlight_file、readfile、file_get_contents、fopen、file
防范方法:
对输入数据进行精确匹配,比如根据变量的值确定语言 en.php、cn.php,那么这两个文件放在同一个目录下'language/'.$_POST[‘lang'].'.php',
那么检查提交的数据是否是 en 或者 cn 是最严格的,检查是否只包含字母也不错,通过过滤参数中的/、..等字符。
HTTP 响应拆分
PHP 中可导致 HTTP 响应拆分的情况为:使用 header 函数和使用$_SERVER 变量。注意PHP 的高版本会禁止 HTTP 表头中出现换行字符,这类可以直接跳过本测试。
防范方法:
精确匹配输入数据
检测输入输入中如果有\r 或\n,直接拒绝
变量覆盖
PHP 变量覆盖会出现在下面几种情况:
遍历初始化变量
例:
代码如下:
foreach($_GET as $key => $value)
$$key = $value;
函数覆盖变量:parse_str、mb_parse_str、import_request_variables,Register_globals=ON 时,GET 方式提交变量会直接覆盖
防范方法:代码如下:
<?php
/* 四海网 www.q1010.com */
$myfunc=$_GET['myfunc'];
$myfunc();
?>
防御方法:
加密
明文存储密码
采用明文的形式存储密码会严重威胁到用户、应用程序、系统安全。
密码弱加密
使用容易破解的加密算法,MD5加密已经部分可以利用 md5破解网站来破解
参考方案
代码如下:
md5(md5($password).$salt)
密码存储在攻击者能访问到的文件
认证和授权
用户认证
检查代码进行用户认证的位置,是否能够绕过认证,例如:登录代码可能存在表单注入。
检查登录代码有无使用验证码等,防止暴力破解的手段
函数或文件的未认证调用
一些管理页面是禁止普通用户访问的,有时开发者会忘记对这些文件进行权限验证,导致漏洞发生
某些页面使用参数调用功能,没有经过权限验证,比如 index.php?action=upload
密码硬编码
有的程序会把数据库链接账号和密码,直接写到数据库链接函数中。
随机函数
rand() VS mt_rand()
rand()最大随机数是 32767,当使用 rand 处理 session 时,攻击者很容易破解出session,建议使用mt_rand()。
代码示例
代码如下:
<?php
/* 四海网 www.q1010.com */
//on windows
print mt_getrandmax(); //2147483647
print getrandmax();// 32767
?>
代码如下:
<?php
/* 四海网 www.q1010.com */
$a= md5(rand());
for($i=0;$i<=32767;$i++){
if(md5($i) ==$a ) {
print $i."-->ok!!<br>";exit;
}else { print $i."<br>";}
}
?>
当我们的程序使用 rand 处理 session 时,攻击者很容易暴力破解出你的 session,但是对于 mt_rand 是很难单纯的暴力的。
本文来自:http://www.q1010.com/173/15442-0.html
注:关于PHP代码审核的简单示例的内容就先介绍到这里,更多相关文章的可以留意四海网的其他信息。
关键词:代码审核
四海网收集整理一些常用的php代码,JS代码,数据库mysql等技术文章。