It's not safe to require $input . '.php'. To then institate a class. How can I make it secure, without needing to use say a whitelist of classes that can be inistiated.
要求$输入是不安全的。 '.PHP'。然后开始上课。如何使其安全,无需使用可以被提及的类的白名单。
Ex 1. (bad code).
例1.(错误代码)。
<?php
$input = $_GET['controller'];
require $input . '.php';
new $input;
?>
10 个解决方案
#1
13
Disclaimer
放弃
I should start by saying that defining static routes in your system is secure by design whereas this answer, even though I've made efforts to mitigate security issues, should be thoroughly tested and understood before trusting its operation.
我首先应该说,在您的系统中定义静态路由是安全的设计,而这个答案,即使我已经努力减轻安全问题,应该在信任其操作之前进行全面测试和理解。
The basics
基础
First, make sure the controller contains a valid variable name using a regular expression as taken from the manual; this weeds out obvious erroneous entries:
首先,使用从手册中获取的正则表达式确保控制器包含有效的变量名称;这清除了明显错误的条目:
$controller = filter_input(INPUT_GET, FILTER_VALIDATE_REGEXP, [
'options' => [
'regexp' => '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/',
'flags' => FILTER_NULL_ON_FAILURE,
]
]);
if ($controller !== null) {
// load and use controller
require_once("$controller.php");
$c = new $controller();
}
Enforcing hierarchy
执行层次结构
This works well, but what if someone tries to load an internal class instead? It might horribly fail the application.
这很好用,但如果有人试图加载内部类呢?它可能会使应用程序失败。
You could introduce an abstract base class or interface that all your controllers must extend or implement:
您可以引入一个所有控制器必须扩展或实现的抽象基类或接口:
abstract class Controller {}
// e.g. controller for '?controller=admin'
class Admin extends Controller {}
Btw, to avoid name conflicts, you could define these inside a separate namespace.
顺便说一句,为避免名称冲突,您可以在单独的命名空间中定义它们。
And this is how you would enforce such a hierarchy:
这就是你如何强制执行这样的层次结构:
if ($controller !== null) {
// load and use controller
require_once("$controller.php");
if (is_subclass_of($controller, 'Controller')) {
$c = new $controller();
}
}
I'm using is_subclass_of()
to type check before instantiating the class.
我在实例化类之前使用is_subclass_of()来键入check。
Auto loading
自动加载
Instead of using a require_once()
in this case, you could use an auto loader instead:
在这种情况下,您可以使用自动加载器代替使用require_once():
// register our custom auto loader
spl_autoload_register(function($class) {
$file = "$class.php"; // admin -> admin.class.php
if (file_exists($file)) {
require_once $file; // this can be changed
}
});
This is also the place where you can normalize the class name, so that it maps better to a file name, as well as enforcing a custom namespace, e.g. "App\\$class.php"
.
这也是您可以规范化类名称的地方,以便它更好地映射到文件名,以及强制执行自定义命名空间,例如“应用程序\\ $ class.php”。
This reduces the code by one line, but making the loading more flexible:
这将代码减少了一行,但使加载更加灵活:
if ($controller !== null) {
// check hierarchy (this will attempt auto loading)
if (class_exists($controller) && is_subclass_of($controller, 'Controller')) {
$c = new $controller();
}
}
All this code assumes you have proper error handling code in place; for implementation suggestions you can look at this answer.
所有这些代码都假定您有适当的错误处理代码;对于实施建议,您可以查看此答案。
#2
3
A couple of suggestions:
一些建议:
- Put your controller classes in its own dedicated folder, containing ONLY controller classes
- 将控制器类放在其自己的专用文件夹中,该文件夹仅包含控制器类
-
Make your filter as strict as possible eg.
使您的过滤器尽可能严格,例如。
/* is $_GET['controller'] set? */ if (!isset($_GET['controller'])) { // load error or default controller??? } $loadController = $_GET['controller']; /* replace any characters NOT matching a-z or _ (whitelist approach), case insensitive */ $loadController = preg_replace('/[^a-z_]+/i', '', $loadController); /* verify var is not empty now :) */ if (!$loadController) { // load error or default controller??? } /* if your classes are named in a certain fashion, eg. "Classname", format the incoming text to match ** NEVER TRUST USER INPUT ** */ $loadController = ucfirst(strtolower($loadController));
-
Check if the file exists Why not file_exists? see desc
检查文件是否存在为什么不存在file_exists?见desc
/* avoiding using file_exists as it also matches folders... */ if (!is_file($myControllerClassesPath.$loadController.'.php')) { // load error or default controller??? }
-
Then require the file, and verify that the class itself exists
然后需要该文件,并验证该类本身是否存在
require($myControllerClassesPath.$loadController.'.php'); /* of course, this assumes filename === classname, adjust accordingly */ if (!class_exists($loadController)) { // load error or default controller??? }
-
Then of course, new instance of X
然后当然是X的新实例
new $loadController;
#3
1
Most anwsers are using a variation of auto_load
instead of include to make it more secure. But the provided examples fail to mention that the way they use it, auto_load
is just a fancy include. Instead of including the file manually and then calling the class, the file is included automatically. This offers no security advantage as one could still call any available class.
大多数anwsers使用auto_load的变体而不是include来使其更安全。但是提供的示例没有提到他们使用它的方式,auto_load只是一个奇特的包含。不是手动包含文件然后调用类,而是自动包含该文件。这没有任何安全优势,因为仍然可以调用任何可用的类。
In my opion using include
instead of require
and then catching the error is the best practise and easiest to implement. To make it secure you must add an extra part to the filenames you allow to be included. EG: "Controller". Now if you have a class called Home
, then you call the file homeController.php. This way we can only require files that end with 'Controller.php'.
在我的opion中使用include而不是require然后捕获错误是最佳实践并且最容易实现。为了确保安全,您必须在允许包含的文件名中添加额外的部分。 EG:“控制器”。现在,如果您有一个名为Home的类,则调用homeController.php文件。这样我们只能要求以'Controller.php'结尾的文件。
Just as an extra precaution I added basename()
to the input to prevent network access on windows systems
作为额外的预防措施,我在输入中添加了basename()以防止在Windows系统上进行网络访问
<?php
//EG GET ?controller=home
$input = isset($_GET['controller']) ? $_GET['controller'] : "";
if (empty($input))
die('No controller');
$input = basename($input);
$filename = $input.'Controller.php';
//since only valid files can be included, you dont need to check for valid chars or anything. Just make sure that only your controller files end with 'Controller.php'
//use the @ to hide the warning when the file does not exist
if ((@include $filename) !== 1)
die('Unknown controller');
//no error, so we included a valid controller and now we can call it.
$controller = new $input();
?>
keep in mind that if you run on a none Windows server, your filenames are case-sensitive while your PHP classes are not. so if somebody would enter controller=HOME then the include would fail.
请记住,如果您在无Windows服务器上运行,则您的文件名区分大小写,而PHP类则不区分大小写。所以,如果有人进入controller = HOME,则包含将失败。
You could prevent this issue by makeing all files like 'homeController.php' with a lower case class prefix. Then you can use $filename = strtolower($input).'Controller.php';
您可以通过使用小写类前缀来生成所有类似'homeController.php'的文件来防止此问题。然后你可以使用$ filename = strtolower($ input)。'Controller.php';
#4
0
If you have few classes/files, you can get all php files within the folder where classes are stored and check if the class you want to include/require is one of them.
如果你有几个类/文件,你可以获取存储类的文件夹中的所有php文件,并检查你想要包含/要求的类是否是其中之一。
So something like this:
所以这样的事情:
$classDir = '/path/to/classes';
$classList = glob($classDir.'/*.php');
$classAbsolutePath = $classDir.'/'.$_GET['class'];
if (in_array($classAbsolutePath, $classList)) {
require $classAbsolutePath;
}
If you have sub directories you have to modify this code according to that. By the way, this is not the best solution, regarding performances, especially if you have a lot of files and a lot of subdirectories. Also, in_array()
is not very efficient so you should avoid it if you have big arrays.
如果您有子目录,则必须根据该目录修改此代码。顺便说一下,这不是关于性能的最佳解决方案,特别是如果你有很多文件和很多子目录。此外,in_array()效率不高,所以如果你有大数组,你应该避免使用它。
In my opinion the best way to do something like this is to have a whitelist. You can generate it automatically via code. Every time you rebuild or deploy your project you can regenerate the list so that you will always have a valid one.
在我看来,做这样的事情的最好方法是拥有一个白名单。您可以通过代码自动生成它。每次重建或部署项目时,都可以重新生成列表,以便始终拥有有效的列表。
#5
0
I would suggest you to introduce special tag into allowed files. Then before you include the file, read it as plain text and look for the tag. Only if the tag is present, include it. The tag can be inside PHP comment at the beginning of allowed files.
我建议你在允许的文件中引入特殊标签。然后在包含文件之前,将其作为纯文本阅读并查找标记。只有标签存在时,才包含它。标签可以在允许的文件开头的PHP注释内。
$class = $_GET['class'];
if (preg_match('/^[a-zA-Z]+$/', $class))
{
$file = $class.".php";
if (is_file($file)) {
{
$content = file_get_contents($file);
if (strpos($content, "THECLASSMAGIC") !== false)
{
require($file);
}
}
else
{
die(...);
}
}
else
{
die(...);
}
#6
0
Consider using spl_autoload_register()
. This would you save a lot of effort in validating files/classes etc.
考虑使用spl_autoload_register()。这样可以省去验证文件/类等的大量工作。
<?php
function autoloadClasses($class) {
if (file_exists('core/'.$class.'.php')) {
include 'core/'.$class . '.php';
}
}
spl_autoload_register('autoloadClasses');
?>
Then save a file name dart.php
in core-folder (filename and classname has to be the same)
然后在core-folder中保存文件名dart.php(filename和classname必须相同)
When you then create an object: new dart();
the file will be included when needed.
然后,当您创建一个对象时:new dart();必要时将包含该文件。
More information about this: http://php.net/manual/en/function.spl-autoload-register.php
有关此内容的更多信息:http://php.net/manual/en/function.spl-autoload-register.php
#7
0
First add this function.
首先添加此功能。
function __autoload ( $class ) {
$path = "../path/to/class/dir/" . $class . TOKEN . ".php";
if ( file_exists ($path) ) {
require_once ( $path );
} else {
// class not found.
}
}
Then simply access class,
然后只需访问课程,
$class = new input();
It will check if file "../path/to/class/dir/input_secretToken.php"
exists, and include it automatically.
它将检查文件“../path/to/class/dir/input_secretToken.php”是否存在,并自动包含它。
Here TOKEN
is a secret word defined in config file, and used as suffix to all class files. So, only class file with token suffix will load.
这里TOKEN是配置文件中定义的密码,用作所有类文件的后缀。因此,只会加载带有标记后缀的类文件。
#8
0
You could use the spl_autoload_register()
你可以使用spl_autoload_register()
function my_autoload($className) {
$phpFolders = array('models', 'controllers');
foreach($phpFolders as $folder) {
if(file_exists($folder . '/' . $className . '.php')) {
require_once $folder . '/' . $className . '.php';
}
}
}
spl_autoload_register('my_autoload');
$input = $_GET['controller'];
new $input();
#9
0
As far as security goes, there's nothing wrong with accepting resources' identifier from input, whether it's an image or some code. But it is inevitable to avoid some sort of authorization if one is expected (obviously it's a paradox to have authorization but not to have one). So if you insist on not having an ACL (or 'white list' as you call it) I have to say that what you want is not possible.
就安全性而言,从输入接受资源的标识符没有任何问题,无论是图像还是某些代码。但是,如果有人预期的话,避免某种授权是不可避免的(显然,获得授权是一种悖论,但没有授权)。因此,如果您坚持不使用ACL(或称为“白名单”),我必须说您想要的是不可能的。
On the other hand, if you can come to terms with ACL, then the rest is straightforward. All you need to do is to see your controllers as resources and group your users into roles (this last part is optional). Then specify which role or user can access which controller. Here's how it's done using Zend Framework.
另一方面,如果您可以接受ACL,那么其余的就是直截了当的。您需要做的就是将控制器视为资源并将用户分组为角色(最后一部分是可选的)。然后指定哪个角色或用户可以访问哪个控制器。以下是使用Zend Framework完成的工作。
$acl = new Zend_Acl();
$acl->addRole(new Zend_Acl_Role('guest'))
->addRole(new Zend_Acl_Role('member'))
->addRole(new Zend_Acl_Role('admin'));
$parents = array('guest', 'member', 'admin');
$acl->addRole(new Zend_Acl_Role('someUser'), $parents);
$acl->add(new Zend_Acl_Resource('someController'));
$acl->deny('guest', 'someController');
$acl->allow('member', 'someController');
Then when some requests is arrived you can question its authorization simply like this:
然后,当一些请求到达时,您可以像下面这样询问其授权:
if ($acl->isAllowed('currentUser', $_GET['controller'])) {
$ctrlClass = $_GET['controller'];
$controller = new $ctrlClass();
}
Assuming that some autoloader is already set.
假设已经设置了一些自动加载器。
#10
-1
In what instance are you going to allow a user to instantiate a controller via a query string paramater, but not have an idea of what they’re actually trying to instantiate? Sounds like a recipe for disaster.
在什么情况下,您将允许用户通过查询字符串参数实例化控制器,但不知道他们实际尝试实例化的是什么?听起来像灾难的食谱。
Saying that, I’d just restrict input to letters only (assuming your classes are named MyClass.php, MyOtherClass.php etc) and locked to a particular directory.
这样说,我只是将输入限制为仅限于字母(假设您的类名为MyClass.php,MyOtherClass.php等)并锁定到特定目录。
<?php
$className = $_GET['file'];
$dir = '/path/to/classes/';
$file = $dir . $className . '.php';
if (preg_match('/^[a-zA-Z]+$/', $className) && is_file($file)) {
require($file);
$class = new $className;
}
else {
die('Class not found');
}
#1
13
Disclaimer
放弃
I should start by saying that defining static routes in your system is secure by design whereas this answer, even though I've made efforts to mitigate security issues, should be thoroughly tested and understood before trusting its operation.
我首先应该说,在您的系统中定义静态路由是安全的设计,而这个答案,即使我已经努力减轻安全问题,应该在信任其操作之前进行全面测试和理解。
The basics
基础
First, make sure the controller contains a valid variable name using a regular expression as taken from the manual; this weeds out obvious erroneous entries:
首先,使用从手册中获取的正则表达式确保控制器包含有效的变量名称;这清除了明显错误的条目:
$controller = filter_input(INPUT_GET, FILTER_VALIDATE_REGEXP, [
'options' => [
'regexp' => '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/',
'flags' => FILTER_NULL_ON_FAILURE,
]
]);
if ($controller !== null) {
// load and use controller
require_once("$controller.php");
$c = new $controller();
}
Enforcing hierarchy
执行层次结构
This works well, but what if someone tries to load an internal class instead? It might horribly fail the application.
这很好用,但如果有人试图加载内部类呢?它可能会使应用程序失败。
You could introduce an abstract base class or interface that all your controllers must extend or implement:
您可以引入一个所有控制器必须扩展或实现的抽象基类或接口:
abstract class Controller {}
// e.g. controller for '?controller=admin'
class Admin extends Controller {}
Btw, to avoid name conflicts, you could define these inside a separate namespace.
顺便说一句,为避免名称冲突,您可以在单独的命名空间中定义它们。
And this is how you would enforce such a hierarchy:
这就是你如何强制执行这样的层次结构:
if ($controller !== null) {
// load and use controller
require_once("$controller.php");
if (is_subclass_of($controller, 'Controller')) {
$c = new $controller();
}
}
I'm using is_subclass_of()
to type check before instantiating the class.
我在实例化类之前使用is_subclass_of()来键入check。
Auto loading
自动加载
Instead of using a require_once()
in this case, you could use an auto loader instead:
在这种情况下,您可以使用自动加载器代替使用require_once():
// register our custom auto loader
spl_autoload_register(function($class) {
$file = "$class.php"; // admin -> admin.class.php
if (file_exists($file)) {
require_once $file; // this can be changed
}
});
This is also the place where you can normalize the class name, so that it maps better to a file name, as well as enforcing a custom namespace, e.g. "App\\$class.php"
.
这也是您可以规范化类名称的地方,以便它更好地映射到文件名,以及强制执行自定义命名空间,例如“应用程序\\ $ class.php”。
This reduces the code by one line, but making the loading more flexible:
这将代码减少了一行,但使加载更加灵活:
if ($controller !== null) {
// check hierarchy (this will attempt auto loading)
if (class_exists($controller) && is_subclass_of($controller, 'Controller')) {
$c = new $controller();
}
}
All this code assumes you have proper error handling code in place; for implementation suggestions you can look at this answer.
所有这些代码都假定您有适当的错误处理代码;对于实施建议,您可以查看此答案。
#2
3
A couple of suggestions:
一些建议:
- Put your controller classes in its own dedicated folder, containing ONLY controller classes
- 将控制器类放在其自己的专用文件夹中,该文件夹仅包含控制器类
-
Make your filter as strict as possible eg.
使您的过滤器尽可能严格,例如。
/* is $_GET['controller'] set? */ if (!isset($_GET['controller'])) { // load error or default controller??? } $loadController = $_GET['controller']; /* replace any characters NOT matching a-z or _ (whitelist approach), case insensitive */ $loadController = preg_replace('/[^a-z_]+/i', '', $loadController); /* verify var is not empty now :) */ if (!$loadController) { // load error or default controller??? } /* if your classes are named in a certain fashion, eg. "Classname", format the incoming text to match ** NEVER TRUST USER INPUT ** */ $loadController = ucfirst(strtolower($loadController));
-
Check if the file exists Why not file_exists? see desc
检查文件是否存在为什么不存在file_exists?见desc
/* avoiding using file_exists as it also matches folders... */ if (!is_file($myControllerClassesPath.$loadController.'.php')) { // load error or default controller??? }
-
Then require the file, and verify that the class itself exists
然后需要该文件,并验证该类本身是否存在
require($myControllerClassesPath.$loadController.'.php'); /* of course, this assumes filename === classname, adjust accordingly */ if (!class_exists($loadController)) { // load error or default controller??? }
-
Then of course, new instance of X
然后当然是X的新实例
new $loadController;
#3
1
Most anwsers are using a variation of auto_load
instead of include to make it more secure. But the provided examples fail to mention that the way they use it, auto_load
is just a fancy include. Instead of including the file manually and then calling the class, the file is included automatically. This offers no security advantage as one could still call any available class.
大多数anwsers使用auto_load的变体而不是include来使其更安全。但是提供的示例没有提到他们使用它的方式,auto_load只是一个奇特的包含。不是手动包含文件然后调用类,而是自动包含该文件。这没有任何安全优势,因为仍然可以调用任何可用的类。
In my opion using include
instead of require
and then catching the error is the best practise and easiest to implement. To make it secure you must add an extra part to the filenames you allow to be included. EG: "Controller". Now if you have a class called Home
, then you call the file homeController.php. This way we can only require files that end with 'Controller.php'.
在我的opion中使用include而不是require然后捕获错误是最佳实践并且最容易实现。为了确保安全,您必须在允许包含的文件名中添加额外的部分。 EG:“控制器”。现在,如果您有一个名为Home的类,则调用homeController.php文件。这样我们只能要求以'Controller.php'结尾的文件。
Just as an extra precaution I added basename()
to the input to prevent network access on windows systems
作为额外的预防措施,我在输入中添加了basename()以防止在Windows系统上进行网络访问
<?php
//EG GET ?controller=home
$input = isset($_GET['controller']) ? $_GET['controller'] : "";
if (empty($input))
die('No controller');
$input = basename($input);
$filename = $input.'Controller.php';
//since only valid files can be included, you dont need to check for valid chars or anything. Just make sure that only your controller files end with 'Controller.php'
//use the @ to hide the warning when the file does not exist
if ((@include $filename) !== 1)
die('Unknown controller');
//no error, so we included a valid controller and now we can call it.
$controller = new $input();
?>
keep in mind that if you run on a none Windows server, your filenames are case-sensitive while your PHP classes are not. so if somebody would enter controller=HOME then the include would fail.
请记住,如果您在无Windows服务器上运行,则您的文件名区分大小写,而PHP类则不区分大小写。所以,如果有人进入controller = HOME,则包含将失败。
You could prevent this issue by makeing all files like 'homeController.php' with a lower case class prefix. Then you can use $filename = strtolower($input).'Controller.php';
您可以通过使用小写类前缀来生成所有类似'homeController.php'的文件来防止此问题。然后你可以使用$ filename = strtolower($ input)。'Controller.php';
#4
0
If you have few classes/files, you can get all php files within the folder where classes are stored and check if the class you want to include/require is one of them.
如果你有几个类/文件,你可以获取存储类的文件夹中的所有php文件,并检查你想要包含/要求的类是否是其中之一。
So something like this:
所以这样的事情:
$classDir = '/path/to/classes';
$classList = glob($classDir.'/*.php');
$classAbsolutePath = $classDir.'/'.$_GET['class'];
if (in_array($classAbsolutePath, $classList)) {
require $classAbsolutePath;
}
If you have sub directories you have to modify this code according to that. By the way, this is not the best solution, regarding performances, especially if you have a lot of files and a lot of subdirectories. Also, in_array()
is not very efficient so you should avoid it if you have big arrays.
如果您有子目录,则必须根据该目录修改此代码。顺便说一下,这不是关于性能的最佳解决方案,特别是如果你有很多文件和很多子目录。此外,in_array()效率不高,所以如果你有大数组,你应该避免使用它。
In my opinion the best way to do something like this is to have a whitelist. You can generate it automatically via code. Every time you rebuild or deploy your project you can regenerate the list so that you will always have a valid one.
在我看来,做这样的事情的最好方法是拥有一个白名单。您可以通过代码自动生成它。每次重建或部署项目时,都可以重新生成列表,以便始终拥有有效的列表。
#5
0
I would suggest you to introduce special tag into allowed files. Then before you include the file, read it as plain text and look for the tag. Only if the tag is present, include it. The tag can be inside PHP comment at the beginning of allowed files.
我建议你在允许的文件中引入特殊标签。然后在包含文件之前,将其作为纯文本阅读并查找标记。只有标签存在时,才包含它。标签可以在允许的文件开头的PHP注释内。
$class = $_GET['class'];
if (preg_match('/^[a-zA-Z]+$/', $class))
{
$file = $class.".php";
if (is_file($file)) {
{
$content = file_get_contents($file);
if (strpos($content, "THECLASSMAGIC") !== false)
{
require($file);
}
}
else
{
die(...);
}
}
else
{
die(...);
}
#6
0
Consider using spl_autoload_register()
. This would you save a lot of effort in validating files/classes etc.
考虑使用spl_autoload_register()。这样可以省去验证文件/类等的大量工作。
<?php
function autoloadClasses($class) {
if (file_exists('core/'.$class.'.php')) {
include 'core/'.$class . '.php';
}
}
spl_autoload_register('autoloadClasses');
?>
Then save a file name dart.php
in core-folder (filename and classname has to be the same)
然后在core-folder中保存文件名dart.php(filename和classname必须相同)
When you then create an object: new dart();
the file will be included when needed.
然后,当您创建一个对象时:new dart();必要时将包含该文件。
More information about this: http://php.net/manual/en/function.spl-autoload-register.php
有关此内容的更多信息:http://php.net/manual/en/function.spl-autoload-register.php
#7
0
First add this function.
首先添加此功能。
function __autoload ( $class ) {
$path = "../path/to/class/dir/" . $class . TOKEN . ".php";
if ( file_exists ($path) ) {
require_once ( $path );
} else {
// class not found.
}
}
Then simply access class,
然后只需访问课程,
$class = new input();
It will check if file "../path/to/class/dir/input_secretToken.php"
exists, and include it automatically.
它将检查文件“../path/to/class/dir/input_secretToken.php”是否存在,并自动包含它。
Here TOKEN
is a secret word defined in config file, and used as suffix to all class files. So, only class file with token suffix will load.
这里TOKEN是配置文件中定义的密码,用作所有类文件的后缀。因此,只会加载带有标记后缀的类文件。
#8
0
You could use the spl_autoload_register()
你可以使用spl_autoload_register()
function my_autoload($className) {
$phpFolders = array('models', 'controllers');
foreach($phpFolders as $folder) {
if(file_exists($folder . '/' . $className . '.php')) {
require_once $folder . '/' . $className . '.php';
}
}
}
spl_autoload_register('my_autoload');
$input = $_GET['controller'];
new $input();
#9
0
As far as security goes, there's nothing wrong with accepting resources' identifier from input, whether it's an image or some code. But it is inevitable to avoid some sort of authorization if one is expected (obviously it's a paradox to have authorization but not to have one). So if you insist on not having an ACL (or 'white list' as you call it) I have to say that what you want is not possible.
就安全性而言,从输入接受资源的标识符没有任何问题,无论是图像还是某些代码。但是,如果有人预期的话,避免某种授权是不可避免的(显然,获得授权是一种悖论,但没有授权)。因此,如果您坚持不使用ACL(或称为“白名单”),我必须说您想要的是不可能的。
On the other hand, if you can come to terms with ACL, then the rest is straightforward. All you need to do is to see your controllers as resources and group your users into roles (this last part is optional). Then specify which role or user can access which controller. Here's how it's done using Zend Framework.
另一方面,如果您可以接受ACL,那么其余的就是直截了当的。您需要做的就是将控制器视为资源并将用户分组为角色(最后一部分是可选的)。然后指定哪个角色或用户可以访问哪个控制器。以下是使用Zend Framework完成的工作。
$acl = new Zend_Acl();
$acl->addRole(new Zend_Acl_Role('guest'))
->addRole(new Zend_Acl_Role('member'))
->addRole(new Zend_Acl_Role('admin'));
$parents = array('guest', 'member', 'admin');
$acl->addRole(new Zend_Acl_Role('someUser'), $parents);
$acl->add(new Zend_Acl_Resource('someController'));
$acl->deny('guest', 'someController');
$acl->allow('member', 'someController');
Then when some requests is arrived you can question its authorization simply like this:
然后,当一些请求到达时,您可以像下面这样询问其授权:
if ($acl->isAllowed('currentUser', $_GET['controller'])) {
$ctrlClass = $_GET['controller'];
$controller = new $ctrlClass();
}
Assuming that some autoloader is already set.
假设已经设置了一些自动加载器。
#10
-1
In what instance are you going to allow a user to instantiate a controller via a query string paramater, but not have an idea of what they’re actually trying to instantiate? Sounds like a recipe for disaster.
在什么情况下,您将允许用户通过查询字符串参数实例化控制器,但不知道他们实际尝试实例化的是什么?听起来像灾难的食谱。
Saying that, I’d just restrict input to letters only (assuming your classes are named MyClass.php, MyOtherClass.php etc) and locked to a particular directory.
这样说,我只是将输入限制为仅限于字母(假设您的类名为MyClass.php,MyOtherClass.php等)并锁定到特定目录。
<?php
$className = $_GET['file'];
$dir = '/path/to/classes/';
$file = $dir . $className . '.php';
if (preg_match('/^[a-zA-Z]+$/', $className) && is_file($file)) {
require($file);
$class = new $className;
}
else {
die('Class not found');
}