Modificación directa de superglobales

20

He visto personas (que generalmente escriben un buen código) directamente alterar la $_POSTmatriz con un código como este:

// Add some value that wasn't actually posted
$_POST['last_activity'] = time();

// Alter an existing post value
$_POST['name'] = trim($_POST['name']);

// Our pretend function
// Pass the entire $_POST array as data to work with in the function
// The function update_record() will read only the values we actually need
update_record($_POST);

// ...That sure was easier than creating a new array 
//  with only the $_POST values we actually need.

Tiene sentido que update_record()no se acceda a $ _POST directamente, por lo que podemos pasarle otras matrices de datos, por ejemplo, pero ¿seguramente esto es un diseño vago, malo o posiblemente simplemente incorrecto? Sin embargo, todavía estamos pasando una matriz válida update_record(), entonces, ¿por qué crear una nueva?

Este no es el punto de la pregunta, solo un ejemplo de uso. Sin embargo, he escuchado a mucha gente decir que esto no debería hacerse con $_REQUESTdatos, y es una mala práctica. ¿Pero por qué? Parece lo suficientemente inofensivo.

Ejemplos:

  • Establecer un valor predeterminado $_GET(o posterior) que realmente no existe

  • Agregar $_POSTvalores que no se publicaron realmente después de enviar un formulario

  • Desinfectar o filtrar directamente los $_GETvalores de la matriz o las claves muy temprano en el script (saneamiento alternativo ... ¿por qué no?)

  • Establecer un $_POSTvalor manualmente antes del envío del formulario para llenar una entrada con un valor predeterminado (cuando la entrada lee $_POSTsu valor predeterminado; lo he hecho)

  • ¿Inventar tus propios $_SERVERvalores? Claro, ¿por qué no?

  • ¿Qué hay de los demás, como $_COOKIEy $_SESSION? Por supuesto, tenemos que modificarlos directamente ¿verdad? Entonces, ¿por qué no los demás?

¿ Nunca se debe hacer una modificación directa de las superglobales , o está bien hacerlo en algunos casos?

Wesley Murch
fuente
Estoy de acuerdo con # 1, # 2 y # 3 porque es un uso inesperado (especialmente # 1 y # 2).
Kevin Peno
Buena pregunta. La modificación de matrices globales es incorrecta de la misma manera que los valores globales son incorrectos. Además, estas matrices tienen su propósito (pasar parámetros desde el exterior) que hace que alterarlas sea una forma directa de meterse dentro del código. Pero, creo que algunos de estos arreglos pueden desinfectarse al comienzo del script, solo para no causar problemas dentro del código.
Tadeck
1
Estoy usando envoltorios de matriz de entrada OO (filtrado implícito), que imprimen un aviso adicional cuando las variables $ _GET o $ _POST se alteran. Todavía es posible, pero debería limitarse a situaciones limitadas. (Señalización de módulo cruzado, aunque solo el despachador / controlador frontal debería necesitarlo.)
Mario
@mario: Me encantaría saber más sobre cómo lograste eso si puedes echar un vistazo a esta pregunta: stackoverflow.com/questions/12954656
Wesley Murch

Respuestas:

16

Dado que PHP ya está configurando esos superglobales, no creo que sea malo modificarlos. En algunos casos, puede ser la mejor manera de resolver problemas ... particularmente cuando se trata de código de terceros que no puede modificar fácilmente. (Pueden usar $_GETdirectamente o asumir que existe alguna clave en $_SERVER, etc.)

Sin embargo, en general, creo que es una mala práctica cuando escribes tu propio código. $_REQUESTEs probable que la modificación de los datos con un filtro detrás de escena que se ejecute en cada página automáticamente introduzca efectos secundarios. (Vea todos los problemas que las "citas mágicas" causaron como prueba).

Entonces, si no va a hacer eso (filtrar automáticamente las superglobales), lo siguiente no le brinda ningún beneficio:

$_POST['foo'] = filter($_POST['foo']);

cuando puedes simplemente hacer:

$foo = filter($_POST['foo']);

Creo que es mucho más claro hacer la distinción en todo el sitio que $_POSTy siempre$_GET son datos no filtrados, no confiables, y nunca deberían usarse tal como están.

Al copiar el valor filtrado a otra variable, está afirmando que "entiendo lo que estoy haciendo ... he filtrado esta entrada y es segura de usar".

Konforce
fuente
Gracias por el aporte, mi internet ha estado fuera por casi 2 días, así que no he tenido la oportunidad de responder a nadie. En el ejemplo, modifiqué $ _POST y lo usé como una matriz de datos para pasar a una función de actualización, suponiendo que haya varias otras teclas $ _POST que estaremos leyendo en esa función. Preferiría crear una nueva matriz, pero he visto a personas hacer esto en su lugar, así que todavía no estoy seguro de si llamarlo "código incorrecto" o no, pero creo que al menos se inclina de esa manera. Creo que cada vez que sientas la necesidad de hacer esto, siempre hay una mejor manera.
Wesley Murch
1
@Wesley, la razón principal por la que es "malo" es que hace que sea mucho más probable que olvides desinfectar algunos datos de los usuarios. En su ejemplo, modifica una clave y luego pasa toda la matriz. ¿Qué sucede si algunos de esos datos contienen entradas maliciosas que no se procesan? Es mucho mejor construir esa nueva matriz a mano, copiando solo las cosas que necesita $_POST, desinfectando a medida que avanza. Y con respecto a otras personas que hacen esto ... bueno, muchas personas escriben código PHP muy malo, pero eso tampoco es excusa para que lo hagas. :)
konforce
Creo que debería haber enfatizado las otras aplicaciones del abuso de superglobales además de desinfectar los datos. Probablemente debería haberlo omitido por completo y haber escrito una pregunta más clara, a la gente le gusta particularmente abordar los aspectos de seguridad y, a menudo, ignorar el resto. Para no parecer desagradecido, realmente aprecio los comentarios. Esperaré un día y le daré a éste la marca de verificación, ya que ha abordado algunos puntos buenos, pero se perdió la fiesta de votación durante los 3 minutos cuando la pregunta era nueva :) ¡Gracias de nuevo!
Wesley Murch
9

En general, le sugiero que no modifique los superglobales predefinidos para que quede claro qué son los datos desinfectados y cuáles son los datos sin procesar / no confiables.

Otros pueden sugerir que si limpia las superglobales al comienzo del ciclo de solicitud, entonces no necesita preocuparse por ellas en otro lugar.

Siempre los emparejaría cuando los necesites con:

$id = (int)$_POST['id'];

o similar.

En cuanto a las otras variables que es una buena práctica no escribe en cualquiera de $_GET, $_POST, $_REQUEST, $_SERVERo $_COOKIE. $_SESSIONsin embargo, es diferente porque a menudo desea escribir datos en la sesión que luego persisten en diferentes solicitudes en la sesión.


fuente
2
Más razones por las que este tipo de glóbulos deberían desaparecer reemplazados por objetos / métodos que se pueden utilizar para obtenerlos cuando sea necesario. ¿Por qué setcookieexiste, pero recibimos cookies a través de $_COOKIE? Además, dado $_COOKIEque solo se establece cuando comienza la sesión actual y nunca se actualiza, requiere que modifique / configure las cookies en ambas áreas para que las áreas posteriores del código tengan información actualizada.
Kevin Peno
Gracias James, he estado fuera de línea por un tiempo, así que no pude responder. En resumen, estoy de acuerdo contigo. Siempre hay una mejor solución que escribir para publicar / obtener / etc., pero todavía no estoy seguro de si se considera una idea estrictamente mala, como en " nunca hagas esto nunca ". Entonces, si me encuentro con este tipo de código nuevamente, ¿crees que tengo derecho a "llamarlos" en código descuidado, o puede usarse esto de una manera inteligente y segura a veces?
Wesley Murch
@Wesley Si fuera "nunca hagas esto nunca", las superglobales probablemente serían de solo lectura, no lo son. Simplemente lo llamaría una mala práctica establecerlos o sobrescribirlos en el código de su aplicación, por dichos motivos.
Michel Feldheim
3

Deberías evitarlo. Tal vez en algún momento olvidó desinfectar algo, luego puede recuperar datos peligrosos. Si copia los datos en una nueva estructura mientras desinfecta

  • Solo obtienes lo que quieres / necesitas y no lo que hay $_POSTtambién
  • Probablemente obtendrá un error, si al conjunto recién creado le faltan algunas claves o si falta alguna

Otros scripts adicionales pueden suponer que la matriz está intacta y puede reaccionar con curiosidad.

KingCrunch
fuente
2

Nunca me ha gustado la idea de modificar el superglobal porque es engañoso. Es una forma rápida y hacky de hacer algo que probablemente habrá una mejor manera de hacerlo.

Si cambia el valor de $_POST, por ejemplo, está diciendo que el software recibió datos que no recibió.

EL PROBLEMA REAL

Hay una situación de la vida real en la que esto se convierte en un gran problema:

Imagina que estás trabajando en un equipo. En un mundo ideal, todos usan la misma sintaxis, pero nosotros no vivimos en un mundo ideal. A un desarrollador, John, le gusta acceder a los datos publicados usando $_POST. Él cambia algo en los post vars:

$_POST['ranking'] = 2; // John has changed ranking from 1 to 2 for whatever reason

Luego tiene otro desarrollador, Chris, que prefiere usar filter_inputpara acceder a los datos ingresados ​​(es decir, OBTENER, POSTAR, SERVIDOR, COOKIE) a medida que va a proteger el software cuando procesa datos que el usuario puede alterar. En su parte del software, necesita obtener el valor postal de ranking. Su parte del código es DESPUÉS de la de John.

$ranking = filter_input(INPUT_POST, 'ranking', FILTER_SANITIZE_NUMBER_INT);
// $ranking = 1

Del ejemplo anterior, al cambiar un superglobal, has roto PHP. John ha establecido el valor de $_POST['ranking']2 por cualquier razón, pero ahora Chris ha recibido un valor de 1

Cuando no he visto otra forma de hacerlo:

Trabajé en un proyecto que usaba WordPress como su blog detrás de un equilibrador de carga de AWS. Esto cambia el valor de $_SERVER['remote_address']. En este caso, el otro desarrollador no tuvo más remedio que hacer lo siguiente:

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $parts = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    $_SERVER['REMOTE_ADDR'] = $parts[0];
}

Conclusión

Es casi seguro que hay una mejor manera que cambiar las superglobales

Luke Madhanga
fuente
1

Creo que la verdadera pregunta aquí es "¿por qué debería modificar el tema?". No veo ninguna razón válida para hacerlo. Si necesita desinfectar una entrada, es posible que desee utilizar una variable local ...

A menos que su código sea lo suficientemente corto (digamos, menos de 50 líneas de largo), modificar esos súper globales solo haría que su código sea más difícil de mantener y entender.

Por cierto, no necesita pasar $ _POST a la función, ya que es una matriz superglobal a la que se puede acceder incluso dentro del alcance local de una función.


fuente
3
Pero debería pasarlo. De lo contrario, es muy difícil de probar y no es posible llamar a la función / método con otros valores sin ningún
truco
Bueno, depende de lo que haga su método. Si está diseñado solo para analizar lo que esté en la matriz $ _POST, no necesita pasarlo. Por supuesto, si tiene un propósito más general / abstracto, tiene razón.
2
@ Thomas, estoy de acuerdo con King aquí. Incluso si son globales, no debe usar nada global dentro de otros ámbitos porque causa un acoplamiento estrecho (por lo que la función no se puede reutilizar). Dado su ejemplo, si la función es desinfectar datos, ¿por qué solo desinfecta $_POSTdatos? Pasar $_POSThace que la función desinfecte cualquier dato.
Kevin Peno
0

Después de responder inicialmente esta pregunta diciendo que no debería haber ninguna razón para modificar las superglobales, estoy editando esta respuesta con un ejemplo de un momento en que he decidido hacerlo.

Actualmente estoy trabajando en una tabla de base de datos de reescritura de URL mediante la cual la requestcolumna dirige al usuario a su targetcolumna correspondiente .

Por ejemplo, un requestpodría ser blog/title-herey targetpodría ser blog.php?id=1.

Como blog.phpestá esperando $_GETvariables, y no quiero cambiar el header("Location:"), me queda hacer algo como esto:

$uri    = explode('?', $uri_request)[0];
$params = explode('?', $uri_request)[1];
parse_str($params, $_GET);

Esto crea una $_GETmatriz que contiene los parámetros deseados pasados ​​por la targetcolumna.

En última instancia, recomendaría encarecidamente no modificar las superglobales a menos que sea absolutamente necesario .

rybo111
fuente