码迷,mamicode.com
首页 > Web开发 > 详细

PHP动物书总结09-13

时间:2018-01-07 17:35:40      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:告诉   选项设置   图像   页面布局   errors   cti   ash   report   长度   

9.图像 10.PDF 11.XML
这三章用到的时候再看

12.安全

1.过滤输入

所有非程序生成的数据都可能是恶意的,都需要过滤
过滤时要判断输入数据大小长度是否合适,是否在规定的有效数据集当中
先使用静态条件过滤,再使用数据库过滤
示例:

//颜色值必须在规定的颜色集当中
if (!in_array($color, $color_set)) {
    return false;
}
//中文名长度必须在3到10之间
$len = mb_strlen($cn_name);
if ($len >= 10 || $len <= 3) {
    return false;
}
//英文名只允许字母、空格、单引号、连字符
if (!preg_match(‘/[^A-Za-z \‘\-]/‘), $en_name) {
    return false;
}
2.跨站脚本攻击XSS

XSS是最常见的网页程序安全漏洞,它允许恶意web用户将恶意代码植入到提供给其它用户的页面中,恶意代码可以在其它页面上执行窃取信息等操作。
为了预防XSS,需要从输出中转义上下文:

$html = array(
    ‘username‘ => htmlentities($_POST[‘username‘], ENT_QUOTES, ‘UTF-8‘),
);
echo $html[‘username‘];

应该过滤输入来提供冗余保护,但不能依赖过滤,因为它不是问题的根源(根源在输出,所以输出要转义才行)。
关于html实体:http://www.w3school.com.cn/html/html_entities.asp
有些符号想要显示在页面上,比如<,在html文件中不能写<,会被浏览器当做html标签处理,正确的方法是使用<对应的html实体符号&lt。

3.SQL注入

(1)示例:

$username = $_POST[‘username‘];
$hash = hash($_POST[‘password‘]);
$sql = "SELECT count(*) FROM users WHERE username = ‘{$username}‘ and password = ‘{$hash}‘ ";

这里的问题是没有转义用户名,它的值可以篡改SQL查询的格式,鉴于此漏洞很常见,很多攻击者会使用如下用户名:
chris‘ --
这样就可以不用密码就可以用chris访问账户
篡改后的SQL查询是:

SELECT count(*) FROM users WHERE username = chris --‘ AND password = ‘xxx

两个破折号(--)表示sql注释,这个查询等同于:

SELECT * FROM users WHERE username = chris

(2)SQL注入出问题的是plain sql,使用参数绑定param bind sql可以很好解决这个问题
bind param sql防SQL注入原理:数据库服务器会把完整参数当做sql语句的参数来执行sql语句,参数的任何部分都不会被执行,这样就不会出现SQL注入的问题了
所以,所有根据用户输入数据进行sql查询的地方理论上都应该使用param bind sql
(3)防止针对plain sql的SQL注入,可以在拼接参数之前对参数过滤和转义。示例如下:

if (preg_match(...), $username) {
    return false;
}
$username = mysql_real_escape_string($username);

实际上,为了安全-不只是防止SQL注入的目的,所有用户输入数据都应该过滤

4.文件名攻击

可以通过传入特殊的文件名进行攻击
(1)使用相对路径访问特殊文件
比如想要访问用户资料文件,文件放在/usr/local/目录下,以用户名作文件名,例如:

include("/usr/local/{$username}");

如果传入的$username值为../../etc/passwd作为用户名,就可能输出/etc/passwd的内容
(2)使用远程文件
默认情况下,php可以用打开本地文件的函数打开远程文件,fopen、include、require等函数可以通过传递URL做文件名打开远程文件,例如:

chdir(‘/usr/local/‘);
$fp = fopen($username, ‘r‘);

如果$username的值为http://www.example.com/myfile,打开的就是一个远程文件,而不是本地的
如果允许用户告诉你要include哪个文件,情况会更糟糕,例如:

$file = $_REQUEST[‘theme‘];
include($file);

如果用户传递了http://www.example.com/badcode.inc作为theme字段的值,并且variables_order配置包括GET或POST,php脚本将会加载远程代码执行
有多种方法可以检查文件名限制此类攻击:禁用远程文件访问、用realpath和basename检查真正的文件名是否和传入参数一致、配置open_basedir选项限制超出网站目录的文件系统访问
例子:

$filename = $_POST[‘username‘];
$vetted = basename(realpath($filename));
if ($filename !== $vetted) {
    die("{$filename} is not a good username.");
}
include("/usr/local/{$filename}");

 

5.会话攻击

攻击者嵌入会话标识符的链接:

<a href="http://host/login.php?PHPSESSID=1234">Log In</a>

受害者单击了链接以会话标识符1234继续访问,如果受害人进行了登录,攻击者可以劫持受害者的会话来提升权限
还有一些这种攻击的变体,比如用cookie达到同样的目的
防护很简单,当权限等级改变时,比如用户登录,用session_generate_id()重新生成会话标识符:

if (check_auth($_POST[‘username‘], $_POST[‘password‘])) {
    $_SESSION[‘auth‘] = TRUE;
    session_regerate_id(TRUE);
}

 

6.文件上传攻击

(1)不要相信浏览器提供的文件名
浏览器可能会提供诸如/etc/passwd、/home/ramus/.forward的文件名
可以在与用户交互中使用浏览器提供的名字,但是要自己生成唯一的名字用作实际调用的文件
例子:

$browserName = $_FILES[‘image‘][‘name‘];
$tempName = $_FILES[‘image‘][‘tmp_name‘];
echo "Thanks for sending me {$browserName}";
$counter++;
$filename = "image_{$counter}";
if (is_uploaded_file[$tempName]) { //使用is_uploaded_file确保是上传的文件
    move_upload_file($tempName, "/web/images/{$filename}");
} else {
    die("There was a problem processing the file.");
}

(2)堤防文件系统填充
攻击者可能会上传很大的文件制造拒绝服务攻击
在php.ini中post_max_size选项设置请求最大尺寸,同时需要在相应的Apache/Nginx设置文件尺寸

(3)限制访问特定目录
php.ini中的open_basedir选项可以限制php只能操作该目录和它的子目录

(4)尽量不使用文件,而使用数据库
由于一个机器上php脚本都使用同一用户(www/nobody)运行,所以不同用户的文件、同一机器上不同网站的文件能被其它用户或网站访问到,比如存储在/tmp/sess_id的用户会话文件就可能被其它用户篡改或添加

(5)隐藏PHP代码库

如果网站根目录时/home/httpd/html,所有该目录下的文件都可以通过URL下载到,代码库、配置文件、日志文件和其它数据应该放在该目录外面,比如放进/home/httpd/myapp。同时应该在Web服务器配置,不可以下载.php等文件。

7.特殊函数

eval、exec、system等执行脚本的函数要谨慎使用,因为很容易被攻击者利用,如果用不到的话应该在php.ini禁用掉

13.应用技术

(1)代码库
利用常用的代码构建代码库,把涉及到的函数放到一个php文件里。例如一个辅助创建HTML表单元素的库文件:其中一个函数创建textarea,一个函数创建设置日期时间的弹出表单
(2)模板系统
模板系统分离php代码和页面布局,使设计者专注于页面设计,程序员专注于数据逻辑。模板系统最基本的思想是网页包含可被动态内容替换的特殊标记。
Smarty是一个高效的模板系统(需要研究下)
(3)输出缓冲
默认php使用echo或类似的命令在每个命令执行完后将结果发送到浏览器,可以用php的输出缓冲函数来收集想要发送到浏览器的数据,这样可以获取内容长度、调整内容、批量延迟输出、清空内容、压缩内容等。

ob_start([callback]) //callback是后处理函数,缓冲区刷新(flush)后会向函数传递收集到的输出,并且返回一个将要发送到浏览器的字符串。

ps:输出缓冲用来拦截输出,也包括var_dump等内置函数的输出
(4)错误报告
正常的,当php脚本发生错误时,错误信息会被插入到脚本的输出中,如果错误时致命的,脚本将会停止执行
有三种错误等级:提示notice、警告warning、错误error,error包括解析错误parse error,除了parse error外都是运行时错误
默认,除了notice都会捕获并且展示给用户,但可以在php.ini中使用error_reporting选项指定输出级别,或在脚本中使用error_reporting()函数来指定
所有错误error:E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR
除notice外的所有错误:E_ALL & ~E_NOTICE
使用@符号可以禁止语句输出错误信息(只能抑制输出错误信息,不能抑制错误造成的结果,致命错误仍然会导致程序停止运行)
(5)错误处理和记录
可以使用set_error_handler()函数注册错误处理器,当错误发生时,错误处理器会被触发。同时可以使用error_log()函数,把错误记录到管理员放置日志的地方。
例子:

//日志分流错误处理器
function log_roller($error, $errorString) {
    $file = ‘/var/log/php_errors.log‘;
    if (filesize($filesize) > 1024) { //保证日志不会大于1k
        rename($file, $file . (string)time()); 
        clearstatcache();
    }
    error_log($errorString, 3, $file);
}
set_error_handler(‘log_roller‘);
for ($i = 0; $i < 5000; $i++) {
    trigger_error(time() . ‘:Just an error\n‘);
}

php.ini中配置不显示错误,而是把错误输出到日志文件中

display_errors=off
log_errors=on
error_log=/tmp/errors.log

(6)性能调优
开始不要太关注优化,先让代码工作起来,然后找到慢的部分去优化。
优化代码的目标是缩短代码运行时间和内存占用,优化的代码可读性可能会差一些。
基准测试benchmark
可以用Apache基准测试工具ab来做性能测试

./ab -c 10 -n 1000 http://localhost/info.php //10个并发请求执行1000次

查看代码运行时间

$start = microtime();
phpinfo();
$end = microtime();
echo $end - $start; //执行时间

 

问题:tcp rpc相对于http rpc的优点是什么?

 

PHP动物书总结09-13

标签:告诉   选项设置   图像   页面布局   errors   cti   ash   report   长度   

原文地址:https://www.cnblogs.com/livepeace/p/8228299.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!