2010-11-06 3 views
0

Je crée un programme qui exécutera un code C++ de PHP. Comment puis-je compiler, exécuter, retourner la sortie d'un programme C++ en toute sécurité? Par sécurité, je veux dire comment puis-je le faire sans rendre mon système vulnérable aux pirates? Je suppose que j'utiliserais juste le comman exec à GCC pour compiler le programme puis exécuter le programme en utilisant exec. Mais comment puis-je le faire en toute sécurité?Compiler, exécuter et retourner la sortie du programme C++, en toute sécurité à partir de PHP

+3

Est-ce que votre question "comment laisser quelqu'un exécuter du code arbitraire sur votre machine en toute sécurité ?? – thetaiko

+0

Tout ce qui est inférieur à la compilation et à l'exécution du code dans une machine virtuelle non connectée peut probablement être considéré »et« relativement dangereux ». Surtout si vous n'avez pas assez de connaissances techniques pour comprendre les étapes exactes nécessaires pour utiliser le sandbox avec une approche non-VM –

Répondre

2

C'est quelque chose d'un peu plus avancé que quelque chose que vous seriez en mesure de faire avec un serveur non personnalisé. Probablement. Parce que la plupart des fournisseurs de serveurs ne vous laisseront pas exécuter des processus, et même si, ils ne vous laisseront pas installer GCC là-bas et exécuter du code potentiellement dangereux sur leur machine (processus d'exécution, vous souvenez?) ...

Je pensais de faire quelque chose comme ça (outils de développement en ligne avec des compilateurs multilingues, sandbox, SVC ...) un jour, mais juste parce que j'ai beaucoup d'espace ainsi qu'un serveur personnalisé juste à côté de mon ordinateur normal.

Si vous avez un serveur personnalisé (en supposant qu'il est Linux, et très probablement LAMP):

  • ont gcc ou mieux encore g ++ installé
  • ont une machine virtuelle (par exemple Bochs) installé, ainsi que d'une installation de base de toute Linux (autre plate-forme) - ce qui est juste pour C et D étapes
  • mettre les fichiers sur un endroit temporaire
  • utilisation proc_open pour démarrer le g ++ avec les fichiers répertoriés, mais assurez-vous d'exécuter cela comme un utilisateur dédié - par exemple gccuser - un utilisateur sans autorisations, mais à lire à partir du répertoire où les fichiers sont stockés
  • A) lire la sortie (succès ou les erreurs/avertissements) de g ++
  • B) permet à l'utilisateur de télécharger le fichier résultat
  • C) mettre le fichier résultat par un éditeur de liens, puis écrire ce fichier sur le disque dur de la machine virtuelle - Puis exécutez-le, et vous pouvez montrer la sortie à l'utilisateur
  • D) (le plus avancé) - faire une chose GUI (terminal) dans JavaSc ript/AS pour parler au fichier en cours en temps réel - ajouter une limite de temps ... ceci signifie cependant que vous avez besoin de plus d'un Bochs en même temps (plus d'utilisateurs) - cela signifie que vous devez copier un Bochs à une température répertoire, avec un disque dur vide (avec seulement OS), l'exécuter sur celui-là, lorsque vous avez terminé - supprimer

proc_open-http://php.net/manual/en/function.proc-open.php

+1

Même dans ce cas, ce n'est pas très sécurisé. – Gabe

+0

Oui, je pensais juste à BOCHS ... Mais là encore, l'ajout d'une VM à tout le processus rend encore plus difficile l'installation d'un autre Linux sur la VM ... Le fait que cette VM peut être endommagée à tout moment - signifie la maintenir ... Hm ... Si je pense à ce sujet n'est pas si difficile juste garder un fichier de disque dur "vide" (juste installé par Linux) et toujours remplacer le fichier "usagé" par le fichier de sauvegarde lorsque vous avez terminé. Mais oh bien. C'est déjà quelque chose de très gros. –

+0

Ajout de la VM ... –

0

Vérifiez this projet. En bref, ce projet entier est ce que vous essayez d'accomplir (et le svn subdir que je vous ai donné est la partie sandbox dont vous avez besoin.) Si vous voulez le faire seul, c'est ici que vous devriez commencer: chroot Si vous êtes sur les fenêtres, vous devez vous appuyer fortement sur l'API Windows.Recherchez msdn pour cela

0

Je l'ai déjà fait, mais à la place, le binaire qui en résulte sort le binaire en téléchargement. téléchargez le fichier binaire et exécutez-le dans leur ordinateur.Laisser les utilisateurs compiler et exécuter du code arbitraire sur votre serveur est une grande vulnérabilité IMO.

Quoi qu'il en soit, voici ma mise en œuvre rapide:

index.php

<?php 
include 'compiler-gcc-mingw.php'; 

$docompile = intval($_REQUEST['docompile']); 
if($docompile){ 
    //compile 
    setUpDirectory(); 
    compile(); 
    if(IsError()){ 
     // 
     cleanUp(); 
    } 
    else { 
     getExecutable(); 
     cleanUp(); 
     downloadExecutable(); 
     exit(); 
    } 
} 

$defaultSource = " 
#include <iostream> 

using namespace std; 
int main(){ 
    cout<<\"Hello Word!\"<<endl; 
    getchar(); 
    return 0; 
} 
"; 
?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<title>Online C++ Compiler v1.0</title> 
<link href="style.css" rel="stylesheet" type="text/css" />  
</head> 
<body> 
<h1>Online Compiler v1.0</h1> 
<p>Online Windows C++ compiler using Mingw compiler </p> 

<?php 
if(IsError()){ 
    $error = getError(); 
    echo '<p><b>Compilation Error! Check your source code</b></p>'; 
    echo '<p>'.$error.'</p>'; 
} 
?> 
<form name="compile" method="post"> 
<input type="hidden" name="docompile" value="1" /> 
<p><b>Source Code:</b></p> 
<textarea name="source" rows="20" cols="80"><?php 
if($docompile) echo stripslashes($_REQUEST['source']); 
else echo $defaultSource; 
?> 
</textarea> <br /> 
<input type="submit" name="Submit" value="Compile"> 
</form> 

</body> 
</html> 

compilateur gcc-mingw.php

<?php 
    $dir = ''; 
    $exeData; 
    $errorFlag; 
    $errorDetail = array(); 

    function makeDir(){ 
     // 
     global $dir; 
     $count = 0; 
     do{ 
      $count++; 
      $dir = 'source/data'.$count; 
     }while([email protected]($dir)); 
    } 

    function setUpDirectory(){ 
     //make source dir : source001, source 002 etc 
     //make source file 
     global $dir; 
     makeDir(); 
     $source = stripslashes($_REQUEST['source']); 
     file_put_contents($dir.'/source.cpp', $source); 
    } 

    function compile(){ 
     // compile, get error message, assuming the compiler is in the system PATH 
     // cd to compile dir 
     global $dir; 
     $compileString = 'g++ '.$dir.'/source.cpp -o '.$dir.'/a.exe '; 
     global $errorFlag; 
     global $errorDetail; 
     $output = exec($compileString, $errorDetail, $errorFlag); 

    } 

    function isError(){ 
     // if error return true 
     global $errorFlag; 
     return $errorFlag; 
    } 

    function getError(){ 
     // get error detail 
     global $errorDetail; 
     $data = ''; 
     foreach($errorDetail as $key=>$value){ 
      $data .= $value.'<br />'; 
     } 
     return $data; 
    } 

    function getExecutable(){ 
     // retrieve exe data to memory 
     global $exeData; 
     global $dir; 
     $exeData = @file_get_contents($dir.'/a.exe'); 
    } 

    function cleanUp(){ 
     // delete all temporary files 
     global $dir; 
     $alist = scandir($dir); 
     foreach($alist as $key => $value){ 
      if(is_file($dir.'/'.$value)) { 
       unlink($dir.'/'.$value); 
      } 
     } 

     rmdir($dir); 
    } 

    function downloadExecutable(){ 
     // download to browser 
     global $exeData; 
     outputFile('program.exe', $exeData); 
    } 

    /** 
    * download content 
    * return value: false=cannot output the header, true=success 
    */ 
    function outputFile($filename, $data){ 
     //Download file 
     if(ob_get_contents()) 
      return false; 
     if(isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'],'MSIE')) 
      header('Content-Type: application/force-download'); 
     else 
      header('Content-Type: application/octet-stream'); 
     if(headers_sent()) 
      return false; 
     header('Content-Length: '.strlen($data)); 
     header('Content-disposition: attachment; filename="'.$filename.'"'); 
     echo $data; 
    } 
?> 

Fondamentalement, il compilez le code écrit dans la zone de texte, enregistrez-le dans un fichier temporaire dans un dossier temporaire, compilez-le (j'utilise mingw compi ler), lisez le binaire résultant, supprimez tous les fichiers temporaires (y compris * .o et les fichiers binaires * .exe) et offrez le binaire résultant en téléchargement à l'utilisateur.

Questions connexes