写出安全的YII WEB应用(四) [ 技术分享 ]
接着上篇继续翻译,上篇地址
跨站请求伪造(CSRF)
需要对数据进行增、删、改,需要客户端的发起POST请求。这是一个好习惯,也是REST架构推荐的方式。这样可以防止浏览器的一些的误操作而引起数据的变化。但是POST请求并不能防止CSRF,从安全角度来说POST的并没有提高安全性。但YII有一套机制可以防止CSRF,只不过默认并不有开启。
配置WEB服务器
本章节讨论是基于类UNIX系统(Linux,BSD,OSX)上安装的Apache服务器,PHP作为Apache的一个模块运行。其它的环境(如Windows,nginx,PHP-fpm…)配置可能不同,但其它原理是一样的。
DEBUG变量的设置
如果在生产环境中,把YII的YII_DEBUG设置为’true’,系统的调试信息会被打印到浏览器。设想一下,如果用户发现了系统的输入字段没有验证,那么用户发送了可能会发送在表单字段中发送一个数组,这样会导致PHP函数接收了错误的参数类型。如果在debug模式下,YII会打印出详细的调试信息。
不方便的是,YII_DEBUG是在YII应用的index.php中设置。所以,这个变量需要在开发环境、测试环境和生产环境中设置成不同的值。有一个解决方案是使用版本控制器设置,但这样很不方便。
推荐的方式是重写index.php,以便读取debug的配置。可以有如下两种方式:
- Index.php读取配置文件里的debug变量。
- 从WEB服务器上读取debug变量。
Apache中如下设置环境变量:
SetEnv YII_ENV testing
这个变量可以在配置文件或者.htaccess中设置。PHP程序可以通过$_SERVER[‘YII_ENV’]读取YII_ENV变量,如果没有设置,默认为生产环境。
YII应用需要注意的
YII框架所在的目录不应该放在WEB服务器的根目录里,要确保用户通过浏览器不能访问框架的文件,如’yiilite.php’。
YII应用中的三个目录:’assets’,’protected/data’,’protected/runtime’;web服务器需要对这三个目录的写权限。除此之外的所有目录,web服务器应该只有读的权限。
即使如此,黑客有可能创建或修改这三个目录的文件。特别是’assets’目录是可写的,又是可以直接通过HTTP请求访问。因此,’assets’目录里的PHP文件只能被当成文本类文件,不能被解析。
YII的应用默认提供了.htaccess文件用来防止’protected/’和’theme/class/views/’被浏览器直接访问。如果在Apache里配置,会更安全、更高效。下面示例了如何禁止运行’assets’文件夹里的PHP文件。
[apache]
示例:配置YII应用
Alias /web/path/for/myapp "/home/myapp/www"
<Directory "/home/myapp/www">
AllowOverride None
</Directory>
<Directory "/home/myapp/www/protected">
Deny from All
</Directory>
<Directory "/home/myapp/www/assets">
#关闭PHP解析引擎
php_admin_flag engine off
Options -Indexes
</Directory>
下面示例:YII应用在虚拟机中设置:
[apache]
# Example config for Yii-myapp as an Apache VirtualHost
# Please set the paths and the host name to their right values
<VirtualHost *:80>
ServerName myapp.com
DocumentRootAlias /home/myapp/www
ErrorLog /var/log/apache2/myapp-error.log
CustomLog /var/log/apache2/myapp-access.log common
<Directory "/home/myapp/www">
Options +FollowSymLinks
# 从PHP5.4起已经被移除下面两个属性
php_flag register_globals Off
php_flag gpc_magic_quotes Off
# 禁止 .htaccess 重写
AllowOverride None
#重写URL
<IfModule mod_rewrite.c>
# 以下配置是隐藏URL中的index.php
# 需要配置YII的 urlManager.showScriptName = false
IndexIgnore */*
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php
</IfModule>
</Directory>
# 禁止通过浏览器访问YII应用 的protected目录
<Directory "/home/myapp/www/protected">
Deny from All
</Directory>
# 保护YII应用中没有PHP脚本的目录
<DirectoryMatch "/home/myapp/www/(assets|css|images|js)$">
# 禁止执行PHP脚本
php_admin_flag engine off
# 禁止浏览目录下的文件目录
Options -Indexes
</DirectoryMatch>
</VirtualHost>
PHP项目一些有用的指令
指令 说明
* allow_url_include 关闭
* register_globals 关闭
* magic_quotes_gpc 关闭,因为YII应用忽略此函数的作用
* open_basedir 谨慎使用
* display_errors 在生产环境下关闭
* error_reporting 至少要报告E_ERROR。官方文档
这些指令可以在php.ini中配置。如果appache设置AllowOverride Options,那么在.htaccess中可以如下所示配置:
[apache]
# .htaccess 文件
php_flag display_errors off
php_value error_reporting -1
如果不允许在.htaccess文件和ini_set()中改变php.ini中配置的变量,则可以在appache的配置文件(如:httpd.conf)使用php_admin_flag指定。
[apache]
# Apache 配置文件
<Directory "/var/www/myapp">
php_admin_value open_basedir /var/www/myapp/:/tmp/
</Directory>
注意:SSL不在本文讨论的范围内。
授权
授权是保证用户只能访问权限内的资源,这个就说来话长了。不过,YII很方便的为我们提供了些类来处理授权问题。详情可以访问详情说明。
其它一些资源:
验证
密码强度
为了防止弱密码的出现,我们可以自己写检验规则,也可以使用现成的YII扩展epasswordstrength。
下面示例:自定义密码强度验证
<?php
class User extends CActiveRecord
{
public function rules()
{
return array(
array('password', 'checkPasswordStrength'),
);
}
protected function checkPasswordStrength($attribute, $params)
{
$password = $this->$attribute;
$valid = true;
$valid = $valid && preg_match('/[0-9]/', $password); // 含数字
$valid = $valid && preg_match('/\W/', $password); // 含其它字符
// ... 其它验证规则 ...
$valid = $valid && (strlen($password) > 7); // 最小长度
if ($valid) {
return true;
} else {
$this->addError($attribute, "密码格式不符合要求");
return false;
}
}
}
?>
也可以先在客户端用JS对密码进行验证,用户可以立刻知道输入的密码是否符合要求。但不要忘记在后端也要用PHP进行验证。客户端的验证的YII扩展estrongpassword。
密码加密
本文只讨论在常规应用应用服务器中的密码验证;其它服务不在讨论之列,如LDAP, SSO, OpenID。
对于用户的密码不能使用明文存储,需要加密存储。一个方便的方法是使用 PHPass。如下示例:
<?php
// autoload "protected/lib/PasswordHash.php"
Yii::import('application.lib.PasswordHash');
class User extends CActiveRecord
{
public function validatePassword($password) // 用户输入$password
{
//
$hasher = new PasswordHash(8, FALSE);
return $hasher->checkPassword($password, $this->password);
}
public function beforeSave()
{
// 用密文替换明文
if (isset($this->password)) {
$hasher = new PasswordHash(8, FALSE);
$this->password = $hasher->HashPassword($this->password);
}
return parent::beforeSave();
}
}
加密函数可以自己写,但PHPass很安全和成熟。其作者开发过密码密码破解软件john the ripper。
常用工具
一些常用用的安全检测工具。
* Skipfish
* Nikto
* W3af, Web Application Attack and Audit Framework
* RatProxy
至此,全部翻译完毕
共 2 条回复
-
yedong0839 回复于 2014-09-22 12:29 举报
舰长才辛苦,感谢舰长为我们提供交流的平台
yedong0839 成都
最后登录:2019-07-16
在线时长:27小时57分
- 粉丝14
- 金钱1980
- 威望0
- 积分2250