Impidir ataques sql.

Iniciado por P[i], 4 Febrero 2008, 16:00 PM

0 Miembros y 1 Visitante están viendo este tema.

P[i]



  Bueno, estoy haciendo una aplicacion web para clase , un proyecto final, y el sabado estuve mirando un problema con sql y las inyecciones. Me di cuenta que cualquier inyeccion de un campo texto por ejemplo un nombre o contraseña o algo por el estilo no se puede hacer contra php porque este sustituye ' o " por \' o  \" pero claro y si los campos son numericos asi que me puse a investigar y mi aplicacion tenia un bug enorme podia hacer cualquier cosa por eso e creado dos funciones que lo primero os puedan ayudar a vosotros y segundo que me digais si despues de pasar por esta funcion aun habria alguna posibilidad de inyeccion sql. Las funciones son estas en cuestion:
<?php 

  
function sql_seguro($valor)
{
  /*Remplazamos < > para que no inserten codigo estilo <?php ...ataque... ?>
*/
$valor = str_replace("<","&lt;",$valor);
  $valor = str_replace(">","&gt;",$valor);

/*palabras que pueden generar problemas*/
$valor = str_replace('INSERT','[INSERT]',$valor);
$valor = str_replace('REPLACE','[REPLACE]',$valor);
$valor = str_replace('UPDATE','[UPDATE]',$valor);
$valor = str_replace('DELETE','[DELETE]',$valor);
$valor = str_replace('SELECT','[SELECT]',$valor);
$valor = str_replace('TRUNCATE','[TRUNCATE]',$valor);
$valor = str_replace('CREATE','[CREATE]',$valor);
$valor = str_replace('DROP','[DROP]',$valor);
$valor = str_replace('SET','[SET]',$valor);
$valor = str_replace(';','[;]',$valor);
$valor = str_replace('"','["]',$valor);
$valor = str_replace("'","[']",$valor);

return $valor;
}

function sql_noseguro($valor)
{
/*palabras que pueden generar problemas*/
$valor = str_replace('[INSERT]','INSERT',$valor);
$valor = str_replace('[REPLACE]','REPLACE',$valor);
$valor = str_replace('[UPDATE]','UPDATE',$valor);
$valor = str_replace('[DELETE]','DELETE',$valor);
$valor = str_replace('[SELECT]','SELECT',$valor);
$valor = str_replace('[TRUNCATE]','TRUNCATE',$valor);
$valor = str_replace('[CREATE]','CREATE',$valor);
$valor = str_replace('[DROP]','DROP',$valor);
$valor = str_replace('[SET]','SET',$valor);
$valor = str_replace('[;]',';',$valor);
$valor = str_replace('["]','"',$valor);
$valor = str_replace("[']","'",$valor);

return $valor;
}

?>


  Tras pasarlo por la primera funcion hay alguna posibilidad de que se pudiera hacer algun ataque sql?????. La segunda funcion  e solo para cuando lo rescatas de la bd que vuelva a estar como antes por si coincide con algo que haya metido el usuario sin malicia.

  Gracias.

Red Mx

#1
y si por ejemplo en ves de INSERT le pongo InSerT de todas formas es valido y me brinco la limpieza.


hace tiempo azielito puso una funcion muy buena para eso de SQl injection sirve  por GET o POST

Código (php) [Seleccionar]

# Funcion para limpiar caracte-
# res que pudieran comprometer
# al servidor y/o al usuario
function limpia($var){
$var = strip_tags($var);
$malo = array("\\",";","\'","'","*",";"); // Aqui poner caracteres no permitidos
$i=0;$o=count($malo);
while($i<=$o){
$var = str_replace($malo[$i],"",$var);
$i++;
}
return $var;
}

# Funcion que aplica la funcion anterior
# para no tener que preocuparnos por
# ataques de XSS o SQLi
function LimpiarTodo($datos){
if(is_array($datos)){
$datos = array_map('limpia',$datos);
}else{
die("<font color=#ff0000><b>Error:</b></font> La funcion <b>LimpiarTodo</b> debe contener un arreglo.");
}
return $datos;
}
if($_POST){
$_POST =& LimpiarTodo($_POST);
}
if($_GET){
$_GET =& LimpiarTodo($_GET);
}


podrias guardarlo como  limpia.php y luego incluirlo antes de cada web donde manejes bases de datos

ejemplo
Código (php) [Seleccionar]

<?php 
include('limpia.php');

// sentencias SQL


/**/



?>
Desarrollar Malware Es Causa De Cancer...

Casidiablo

#2
He visto un código muy bueno, que es el que implementan los foros SMF... la cosa va más o menos así:

Código (php) [Seleccionar]
function db_query($db_string, $file, $line)
{
global $db_cache, $db_count, $db_connection, $db_show_debug, $modSettings;

// One more query....
$db_count = !isset($db_count) ? 1 : $db_count + 1;

// Debugging.
if (isset($db_show_debug) && $db_show_debug === true)
{
// Initialize $db_cache if not already initialized.
if (!isset($db_cache))
$db_cache = array();

if (!empty($_SESSION['debug_redirect']))
{
$db_cache = array_merge($_SESSION['debug_redirect'], $db_cache);
$db_count = count($db_cache) + 1;
$_SESSION['debug_redirect'] = array();
}

$db_cache[$db_count]['q'] = $db_string;
$db_cache[$db_count]['f'] = $file;
$db_cache[$db_count]['l'] = $line;
$st = microtime();
}

// First, we clean strings out of the query, reduce whitespace, lowercase, and trim - so we can check it over.
if (empty($modSettings['disableQueryCheck']))
{
$clean = '';
$old_pos = 0;
$pos = -1;
while (true)
{
$pos = strpos($db_string, '\'', $pos + 1);
if ($pos === false)
break;
$clean .= substr($db_string, $old_pos, $pos - $old_pos);

while (true)
{
$pos1 = strpos($db_string, '\'', $pos + 1);
$pos2 = strpos($db_string, '\\', $pos + 1);
if ($pos1 === false)
break;
elseif ($pos2 == false || $pos2 > $pos1)
{
$pos = $pos1;
break;
}

$pos = $pos2 + 1;
}
$clean .= ' %s ';

$old_pos = $pos + 1;
}
$clean .= substr($db_string, $old_pos);
$clean = trim(strtolower(preg_replace(array('~\s+~s', '~/\*!40001 SQL_NO_CACHE \*/~', '~/\*!40000 USE INDEX \([A-Za-z\_]+?\) \*/~'), array(' ', '', ''), $clean)));

// We don't use UNION in SMF, at least so far.  But it's useful for injections.
if (strpos($clean, 'union') !== false && preg_match('~(^|[^a-z])union($|[^[a-z])~s', $clean) != 0)
$fail = true;
// Comments?  We don't use comments in our queries, we leave 'em outside!
elseif (strpos($clean, '/*') > 2 || strpos($clean, '--') !== false || strpos($clean, ';') !== false)
$fail = true;
// Trying to change passwords, slow us down, or something?
elseif (strpos($clean, 'sleep') !== false && preg_match('~(^|[^a-z])sleep($|[^[a-z])~s', $clean) != 0)
$fail = true;
elseif (strpos($clean, 'benchmark') !== false && preg_match('~(^|[^a-z])benchmark($|[^[a-z])~s', $clean) != 0)
$fail = true;
// Sub selects?  We don't use those either.
elseif (preg_match('~\([^)]*?select~s', $clean) != 0)
$fail = true;

if (!empty($fail))
{
log_error('Hacking attempt...' . "\n" . $db_string, $file, $line);
fatal_error('Hacking attempt...', false);
}
}

$ret = mysql_query($db_string, $db_connection);
if ($ret === false && $file !== false)
$ret = db_error($db_string, $file, $line);

// Debugging.
if (isset($db_show_debug) && $db_show_debug === true)
$db_cache[$db_count]['t'] = array_sum(explode(' ', microtime())) - array_sum(explode(' ', $st));

return $ret;
}


El modo de uso es simple, por ejemplo:

Código (php) [Seleccionar]
db_query("InsERT into TABLA values ('bla', 'Jojojo', '$variable')" , __FILE__, __LINE__)

Es muy bueno para echarle un ojo y aprender.

Un saludo!

P[i]

Gracias a los dos, me voy a poner a estudiarlos para crear la mia propia.
Saludos.

Azielito

Lo que he hecho ultimamente es conectar con usuario de solo lectura en aplicaciones de consulta, o sea, algo asi como tipo, blogs y todo eso, y ademas darle acceso (al usuario) solo a las tablas que se necesitan, generalmente la de usuarios no la ocupamos para eso, de esa forma, aun que salten el filtro que hagas no podran hacer mucho :D