2012-07-10 88 views
6

我想創建一個AJAX腳本,它需要兩個GET變量,類和方法,並將它們映射到我們設計的方法(類似於CodeIgniter如何代理Ajax,I很確定)。由於我依靠用戶輸入來確定要執行的類和方法,所以我擔心黑客可能會使用某種方法來利用該技術。安全地調用一個基於用戶輸入的函數

代碼:

//Grab and clean (just in case, why not) the class and method variables from GET 
$class = urlencode(trim($_GET['c'])); 
$method = urlencode(trim($_GET['m'])); 

//Ensure the passed function is callable 
if(method_exists($class, $method)){ 
    $class::$method(); 
} 

有什麼缺點或安全手錶奏我應該知道在使用這種技術的?

回答

6
<?php 
class AjaxCallableFunction 
{ 
    public static $callable_from_ajax = TRUE; 
} 

$class = $_POST['class']; 
$method = $_POST['method']; 

if (class_exists($class) && isset($class::$callable_from_ajax) && $class::$callable_from_ajax) { 
    call_user_func($class, $method); 
} 

結合一些其他的答案以獲得最佳效果。需要PHP 5.3.0或更高版本。你甚至可以實現一個接口

<?php 
interface AjaxCallable {} 

class MyClass implements AjaxCallable 
{ 
    // Your code here 
} 

$class = $_POST['class']; 
$method = $_POST['method']; 

if (class_exists($class) && in_array('AjaxCallable', class_implements($class))) { 
    call_user_func($class, $method); 
} 

這種方法如下OOP的原則,非常詳細(易於維護),並且不要求你保持一個數組,類可以被稱爲,哪些不能。

+1

AjaxCallable接口是一個好主意,完美地工作。謝謝! – ACobbs 2012-07-11 13:35:10

+0

很高興爲你工作:) – 2012-07-11 14:37:56

4

考慮到你沒有傳遞任何參數,現在這是相對安全的。但我想在添加有效的類的列表你如果諸如:

//Ensure the passed function is callable 
if(method_exists($class, $method)){ 
    if(in_array($class, array('controller1', 'controller2'))){ 
     $class::$method(); 
    } 
} 

這樣,黑客真的不能調用框架中的任何可能的類這種方式,但只有那些你允許他。

14

檢查是否被允許的方法由用戶名爲:

// methods that user can call: 
$user_methods = array("method1", "method2", "method3",); 

//Ensure the passed function is callable 
if(method_exists($class, $method) and in_array($method, $user_methods){ 
    $class::$method(); 
} 

否則,你就無法控制哪些用戶將能夠做到。

+4

+1。白名單,不要黑名單。 – Polynomial 2012-07-10 14:33:24

+2

很好的答案;單獨使用method_exists仍然會導致意想不到的事情開心。 – Erik 2012-07-10 14:48:34

+0

也是可怕的事情。 – 2012-07-30 12:18:24

2

在這種情況下,您必須使用Reflection進行處理。

以下是您需要的示例。

<?php 
class Apple { 
    public function firstMethod() { } 
    final protected function secondMethod() { } 
    private static function thirdMethod() { } 
} 

$class = new ReflectionClass('Apple'); 
$methods = $class->getMethods(); 
var_dump($methods); 
?> 

執行的方法也能像這樣使用ReflectionMethods:invoke

<?php 
class HelloWorld { 

    public function sayHelloTo($name) { 
     return 'Hello ' . $name; 
    } 

} 

$reflectionMethod = new ReflectionMethod('HelloWorld', 'sayHelloTo'); 
echo $reflectionMethod->invoke(new HelloWorld(), 'Mike'); 
?> 

因此,我們終於可以:

$class = urlencode(trim($_GET['c'])); 
    $method = urlencode(trim($_GET['m'])); 

    $allowed_methods = array("insert", "update", "delete"); 

    if(method_exists($class, $method) and in_array($method, $allowed_methods){ 
    $reflectionMethod = new ReflectionMethod($class, $method); 
    $reflectionMethod->invoke(new $class, 'First Argument'); 
    } 
+1

只需直接調用方法,使用Reflection提供什麼好處? – ACobbs 2012-07-10 13:52:17

+0

@ACobbs我不確定你是否首先調用字符串的方法,接下來的事情是,如果有人攻擊你的網站,你將不會與參考不匹配。它會使用它對它所屬的類的引用來調用該方法。 – Burimi 2012-07-10 13:55:37

+0

@Cody您可以請**爲「允許的功能」添加一個數組,基本上包括Secator的答案在自己的?那麼你的無疑將是我可以投票的唯一答案。 – 2012-07-10 14:30:12

1

urlencode()讓我有點擔心。即使它可能是安全的,我也會更嚴格地進行消毒。我只允許字母,數字和下劃線。你不應該真的需要任何類或方法名稱與其他字符。我不認爲我曾見過任何人。

我在所有的項目中使用此爲的東西很多

function very_safe_string($string) 
{ 
    return preg_replace("/[^A-Za-z0-9_]/" , '' , $string); 
} 

正如其他海報所說,你絕對應該有一些類型的白名單明確地允許(在班至少,因爲我確定不是每個類都需要從ajax訪問)。以及檢查class_exists()和method_exists()。

如果其中任何一項檢查失敗,我還會推薦一些類型的電子郵件警報系統。我確定你想知道是否有人試圖hax0r j00。