2009-12-10 8 views
24

PHP tiene 2 funciones estrechamente relacionadas, escapeshellarg() y escapeshellcmd(). Ambos parecen hacer cosas similares, es decir, ayudan a hacer que una cadena sea más segura para usar en system()/exec()/etc.¿Cuál es la diferencia entre escapeshellarg y escapeshellcmd?

¿Cuál debo usar? Solo quiero poder ingresar algunos datos del usuario y ejecutar un comando sobre él, y no hacer explotar todo. Si PHP tuviera una función de tipo exec que tomara una matriz de cadenas (como argv), que pasa por alto el shell, yo usaría eso. Similar a la función subprocess.call() de Python.

Respuesta

7

De http://ie2.php.net/manual/en/function.escapeshellarg.php

escapeshellarg() agrega comillas simples alrededor de una cuerda y cotizaciones/escapa a cualquier comillas simples que le permiten existente para pasar una cadena directamente a una función de shell y que tiene que ser tratado como un único argumento seguro.

escapeshellarg, como su nombre indica, se utiliza como argumento (s) de shell que pasa. Por ejemplo, desea listar directorio actual,

$dir = "."; 
system('ls '.escapeshellarg($dir)); 
escapeshellcmd('ls $dir'); 

Ambos hacen cosas similares y simplemente depende de la forma de manejar la lógica, no asegurarse de que su normalizar y validar su entrada antes de pasar directamente a estos métodos para una mejor seguridad.

+29

Esto no es una respuesta. La pregunta era ¿cuáles son las diferencias? – cyphunk

+2

La verdadera pregunta es "¿Cuál debería usar?". Creo que Jay respondió esa pregunta. –

3

Los documentos PHP explican la diferencia:

escapeshellcmd:

siguientes caracteres son precedidos por una barra invertida:? # &; `| * ~ <> ^() [] { } $ \, \ x0A y \ xFF. . "Y" se escapó sólo si no están emparejados En de Windows, todos estos caracteres más% son reemplazados por un espacio en lugar

escapeshellarg:.

agrega comillas simples alrededor de una cuerda y cotizaciones/escapa a cualquier comillas simples existentes que le permite pasar una cadena directamente a una función de shell y que tiene que ser tratado como un solo argumento segura.

Fuente:

http://www.php.net/manual/en/function.escapeshellcmd.php http://www.php.net/manual/en/function.escapeshellarg.php

65

Por lo general, tendrá que utilizar escapeshellarg, haciendo un solo argumento a un comando de shell segura. He aquí por qué:

Supongamos que necesita obtener una lista de archivos en un directorio.A llegar a la siguiente:

$path = 'path/to/directory'; // From user input 

$files = shell_exec('ls '.$path); 
// Executes `ls path/to/directory` 

(Esta es una mala manera de hacer esto, pero por ejemplo del oso conmigo)

Esto funciona "grande" para esta ruta, pero supongamos que el camino dado fue algo más peligroso:

$path = 'path; rm -rf /'; 

$files = shell_exec('ls '.$path); 
// Executes `ls path`, then `rm -rf /`; 

Como la ruta dada se usó sin anonimato, se puede ejecutar cualquier comando. Podemos usar los métodos escapeshell* para tratar de evitar esto.

En primer lugar, el uso de escapeshellcmd:.

$path = 'path; rm -rf /'; 

$files = shell_exec(escapeshellcmd('ls '.$path)); 
// Executes `ls path\; rm -rf /`; 

Este método sólo se escapa caracteres que podrían conducir a la ejecución de varios comandos, así que mientras que se detenga el importante riesgo de seguridad, todavía puede dar lugar a múltiples parámetros que se están aprobadas en

Ahora, usando escapeshellarg:

$path = 'path; rm -rf /'; 

$files = shell_exec('ls '.escapeshellarg($path)); 
// Executes `ls 'path; rm -rf /'`; 

que nos da el resultado que queremos. Notarás que se cita todo el argumento, por lo que no es necesario escapar de los espacios individuales. Si el argumento fuera a tener citas, serían citadas.

En resumen, escapeshellcmd se asegura de que una cadena sea solo un comando, mientras que escapeshellarg hace que una cadena sea segura para usar como un único argumento para un comando.

4

Una solución simple para determinar la diferencia entre dos funciones similares de PHP es escribir un script de línea de comandos rápido en PHP que genera todo el espacio de búsqueda posible y solo muestra diferencias (en este caso, comparando 256 valores) :

<?php 
    for ($x = 0; $x < 256; $x++) 
    { 
     if (chr($x) !== escapeshellcmd(chr($x))) echo $x . " - cmd: " . chr($x) . " != " . escapeshellcmd(chr($x)) . "\n"; 
    } 

    echo "\n\n"; 

    for ($x = 0; $x < 256; $x++) 
    { 
     if (chr($x) !== substr(escapeshellarg(chr($x)), 1, -1)) echo $x . " - arg: " . chr($x) . " != " . substr(escapeshellarg(chr($x)), 1, -1) . "\n"; 
    } 
?> 

Ejecución del anteriormente en PHP 5.6 en las salidas de comandos de Windows:

0 - cmd: != 
10 - cmd: 
!=^

33 - cmd: ! != ^! 
34 - cmd: " != ^" 
35 - cmd: # != ^# 
36 - cmd: $ != ^$ 
37 - cmd: % != ^% 
38 - cmd: & != ^& 
39 - cmd: ' != ^' 
40 - cmd: (!= ^(
41 - cmd: ) != ^) 
42 - cmd: * != ^* 
59 - cmd: ; != ^; 
60 - cmd: < != ^< 
62 - cmd: > != ^> 
63 - cmd: ? != ^? 
91 - cmd: [ != ^[ 
92 - cmd: \ != ^\ 
93 - cmd: ] != ^] 
94 - cmd:^!= ^^ 
96 - cmd: ` != ^` 
123 - cmd: { != ^{ 
124 - cmd: | != ^| 
125 - cmd: } != ^} 
126 - cmd: ~ != ^~ 
255 - cmd:   != ^  


0 - arg: != 
33 - arg: ! != 
34 - arg: " != 
37 - arg: % != 
92 - arg: \ != \\ 

Ejecutar el mismo guión bajo PHP 5.5 para Linux salidas:

0 - cmd: != 
10 - cmd: 
!= \ 

34 - cmd: " != \" 
35 - cmd: # != \# 
36 - cmd: $ != \$ 
38 - cmd: & != \& 
39 - cmd: ' != \' 
40 - cmd: (!= \(
41 - cmd: ) != \) 
42 - cmd: * != \* 
59 - cmd: ; != \; 
60 - cmd: < != \< 
62 - cmd: > != \> 
63 - cmd: ? != \? 
91 - cmd: [ != \[ 
92 - cmd: \ != \\ 
93 - cmd: ] != \] 
94 - cmd:^!= \^ 
96 - cmd: ` != \` 
123 - cmd: { != \{ 
124 - cmd: | != \| 
125 - cmd: } != \} 
126 - cmd: ~ != \~ 
128 - cmd: != 
... 
255 - cmd: ÿ != 


0 - arg: != 
39 - arg: ' != '\'' 
128 - arg: != 
... 
255 - arg: ÿ != 

La diferencia principal es que PHP escapeshellcmd() bajo los prefijos de Windows tiene caracteres con un^en lugar de una barra invertida \. Las rarezas bajo Linux de chr (128) a chr (255) para ambos escapeshellcmd() y escapeshellarg() pueden explicarse mediante el uso de puntos de código UTF-8 inválidos que se descartan, truncan o malinterpretan.

También es de destacar que escapeshellarg() escapa de muchos menos caracteres y aún así hace el trabajo.

En términos de seguridad general del sistema y la aplicación, es mejor que use escapeshellarg() y escape individualmente cada argumento que consiste en la entrada del usuario.

Un último ejemplo:

echo escapeshellarg("something here") . "\n"; 
echo escapeshellarg("'something here'") . "\n"; 
echo escapeshellarg("\"something here\"") . "\n"; 

salidas Windows:

salidas
"something here" 
"'something here'" 
" something here " 

Linux:

'something here' 
''\''something here'\''' 
'"something here"' 

escapeshellarg PHP() en Windows rodea la cadena con la doble cita " carácter mientras que Linux utiliza el carácter de comillas simples. PHP en Windows reemplaza completamente el documento interno Citas electrónicas con espacios (lo que podría ser un problema en algunos casos). PHP en Linux se sale un poco de su camino para escapar de las comillas simples y las barras invertidas \ escapadas \\ en Windows. PHP escapeshellarg() en Windows también reemplaza! y% personajes con espacios. Todas las plataformas reemplazan \ 0 con espacios.

Tenga en cuenta que el comportamiento no es necesariamente coherente entre las versiones de PHP y la documentación de PHP no siempre refleja la realidad. Escribir un guión rápido o leer el código fuente de PHP son dos formas de descubrir lo que sucede detrás de escena.

Cuestiones relacionadas