2009-12-10 15 views
24

PHP ha 2 funzioni strettamente correlate, escapeshellarg() e escapeshellcmd(). Entrambi sembrano fare cose simili, ovvero aiutare a rendere una stringa più sicura da usare in system()/exec()/ecc.Qual è la differenza tra escapeshellarg e escapeshellcmd?

Quale dovrei usare? Voglio solo essere in grado di prendere qualche input da parte dell'utente ed eseguire un comando su di esso, e non far esplodere tutto. Se PHP avesse una funzione di tipo exec che prendesse una serie di stringhe (come argv), che scavalca la shell, la userei. Simile alla funzione subprocess.call() di Python.

risposta

7

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

escapeshellarg() aggiunge apici intorno una stringa e citazioni/sfugge qualsiasi apici permettendo esistente passare una stringa direttamente a una funzione shell e averlo trattato come a argomento sicuro singolo.

escapeshellarg, come indica il nome, viene utilizzato come argomento della shell passata. Ad esempio, si desidera elencare directory corrente,

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

Entrambi fare cose simili e semplicemente dipende da come si gestisce la logica, non assicurarsi che il proprio normalizzare e convalidare l'input prima di passare direttamente a questi metodi per una maggiore sicurezza.

+29

Questa non è una risposta. La domanda era quali sono le differenze. – cyphunk

+2

La vera domanda è "Quale dovrei usare?". Penso che Jay abbia risposto a questa domanda. –

3

La documentazione PHP precisare la differenza:

escapeshellcmd:

seguenti caratteri sono preceduti da un backslash:? # &; `| * ~ <> ^() [] { } $ \, \ x0A e \ xFF. . 'E "sono sfuggiti solo se non sono in coppia In di Windows, tutti questi personaggi, più% vengono sostituiti da uno spazio invece

escapeshellarg:.

aggiunge virgolette singole intorno una stringa e citazioni/sfugge eventuali apici esistenti consentendo di passare una stringa direttamente a una funzione shell e averlo essere trattata come un singolo argomento.

Fonte:

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

65

In generale, ti consigliamo di utilizzare escapeshellarg, fare un solo argomento per sicuro un comando di shell. Ecco perché:

Supponiamo di aver bisogno di ottenere un elenco di file in una directory.Si arriva con il seguente:

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

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

(Questo è un cattivo modo di fare questo, ma per l'illustrazione orso con me)

Questo funziona "grande" per questo percorso, ma supponiamo che il percorso dato era qualcosa di più pericoloso:

Poiché il percorso indicato è stato utilizzato non approvato, è possibile eseguire qualsiasi comando. Possiamo usare i metodi escapeshell* per cercare di impedirlo.

primo luogo, utilizzando escapeshellcmd:.

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

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

Questo metodo sfugge solo i caratteri che potrebbero portare ad esecuzione più comandi, così mentre si ferma il maggiore rischio per la sicurezza, può ancora portare a parametri multipli di essere passati in

Ora, usando escapeshellarg:

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

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

che ci dà il risultato che vogliamo. Noterai che è citato l'intero argomento, quindi gli spazi individuali, ecc., Non hanno bisogno di essere sfuggiti. Se l'argomento avesse le citazioni stesse, sarebbero citate.

Per riepilogare, escapeshellcmd si assicura che una stringa sia solo un comando, mentre escapeshellarg rende una stringa sicura da utilizzare come singolo argomento per un comando.

4

Una soluzione semplice per determinare la differenza tra due funzioni PHP dal suono simile è scrivere un rapido script da riga di comando in PHP che restituisce l'intero spazio di ricerca possibile e mostra solo le differenze (in questo caso, confrontando 256 valori) :

<?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"; 
    } 
?> 

Esecuzione del sopra sotto PHP 5.6 sulle uscite del prompt dei comandi di 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: \ != \\ 

Esecuzione dello stesso script sotto PHP 5.5 per le uscite di Linux:

012.351.641,061 mila
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 differenza principale è che PHP escapeshellcmd() sotto Windows precede i caratteri con un segno di omissione^invece di una barra rovesciata \. Le stranezze sotto Linux da chr (128) a chr (255) per escapeshellcmd() e escapeshellarg() possono essere spiegate dall'uso di punti di codice UTF-8 non validi che vengono rilasciati, troncati o interpretati erroneamente.

Si noti inoltre che escapeshellarg() riesce a sfuggire molti meno caratteri e continua a svolgere il lavoro.

In termini di sicurezza generale del sistema e dell'applicazione e sicurezza, è meglio usare escapeshellarg() e sfuggire individualmente ad ogni argomento che consiste nell'input dell'utente.

Un ultimo esempio:

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

uscite Windows:

uscite
"something here" 
"'something here'" 
" something here " 

Linux:

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

PHP escapeshellarg() in Windows circonda la stringa con il doppio citazione " personaggio mentre Linux usa il carattere "citazione singola". PHP su Windows sostituisce completamente il doubl interno e-virgolette con spazi (che potrebbe essere un problema in alcuni casi). PHP su Linux fa un po 'a modo suo per sfuggire alle virgolette singole e ai backslash \ sono sfuggiti \\ su Windows. Anche PHP escapeshellarg() su Windows sostituisce! e% caratteri con spazi. Tutte le piattaforme sostituiscono \ 0 con spazi.

Si noti che il comportamento non è necessariamente coerente tra le versioni di PHP e la documentazione di PHP non riflette sempre la realtà. Scrivere un veloce script o leggere il codice sorgente di PHP sono due modi per capire cosa sta succedendo dietro le quinte.

Problemi correlati