Alternativa para mysql_real_escape_string sem conectar ao DB

91

Gostaria de ter uma função comportando-se como mysql_real_escape_string sem conectar ao banco de dados, pois às vezes preciso fazer um teste seco sem conexão de banco de dados. mysql_escape_string está obsoleto e, portanto, não é desejável. Algumas das minhas descobertas:

http://www.gamedev.net/community/forums/topic.asp?topic_id=448909

http://w3schools.invisionzone.com/index.php?showtopic=20064

Viet
fonte
1
1 Estou escrevendo a classe MySQL sozinho e uso mysql_real_escape_string () para fins de ligação de parâmetro. Eu evito usar o mysqli, pois nem todos os hosts o suportam. Eu também evito a biblioteca de vários arquivos e classes. O que eu preciso é apenas de uma única classe arrumada e limpa. Obrigado!
Viet
1 para mim também. Meu caso de uso é um SugarCRM APi, onde preciso enviar fragmentos de SQL para a instância remota do SugarCRM por meio da API. Por mais desagradável que seja, é o que eu tenho que trabalhar (vá juntar algumas cabeças de desenvolvimento do SugarCRM). Eu preciso escapar strings em SQL no aplicativo que usa a API e que é totalmente separado do banco de dados por trás da instância SugarCRM.
Jason

Respostas:

75

É impossível escapar com segurança de uma string sem uma conexão DB. mysql_real_escape_string()e as instruções preparadas precisam de uma conexão com o banco de dados para que possam escapar da string usando o conjunto de caracteres apropriado - caso contrário, os ataques de injeção SQL ainda são possíveis usando caracteres multibyte.

Se você está apenas testando , então você também pode usar mysql_escape_string(), não é 100% garantido contra ataques de injeção de SQL, mas é impossível construir algo mais seguro sem uma conexão de banco de dados.

muito php
fonte
1
+1 Obrigado pela nota. Não tenho muita certeza de como testar contra ataques de injeção de SQL usando caracteres multibyte.
Viet
2
Recebi um código antigo para atualizar. Ele usa mysql_escape_stringsem uma conexão (ainda tentando descobrir o porquê). Como essa função está obsoleta, estou pensando em como posso substituí-la. Certamente parece razoável que se possa especificar o "conjunto de caracteres apropriado" em qualquer função que o substitua sem abrir uma conexão.
JohnK
3
Impossível? O que mysql_real_escape_string obtém da conexão de banco de dados que não são dados de configuração que podem ser passados ​​manualmente para uma função equivalente? Editar: basta ler abaixo, ele chama uma função de biblioteca dentro do MySQL, então há algum processamento que acontece fora do PHP. Ainda pode ser portátil, mas mantê-lo atualizado seria um projeto em si.
Jason
2
E se o conjunto de caracteres DB for conhecido com antecedência?
jchook
7
Sim, se você conhece o conjunto de caracteres, o que impede de fazer o escape sem uma conexão?
Johan,
66

Bem, de acordo com a página de referência da função mysql_real_escape_string : "mysql_real_escape_string () chama a função de biblioteca do MySQL mysql_real_escape_string, que escapa dos seguintes caracteres: \ x00, \ n, \ r, \, '," e \ x1a. "

Com isso em mente, a função fornecida no segundo link que você postou deve fazer exatamente o que você precisa:

function mres($value)
{
    $search = array("\\",  "\x00", "\n",  "\r",  "'",  '"', "\x1a");
    $replace = array("\\\\","\\0","\\n", "\\r", "\'", '\"', "\\Z");

    return str_replace($search, $replace, $value);
}
zumbat
fonte
6
Obrigado. Sugiro outra coisa: escape de função ($ aQuery) {return strtr ($ aQuery, array ("\ x00" => '\ x00', "\ n" => '\ n', "\ r" => '\ r', '\\' => '\\\\', "'" => "\'", '"' => '\"', "\ x1a" => '\ x1a')) ; }
Viet
1
por que \ x1a é substituído por \\\ x1a em vez de \\ x1a? Isso é um erro de digitação?
Michael Z,
16
-1 Isso é extremamente perigoso. Se a conexão do banco de dados estiver usando um conjunto de caracteres multibyte, substituições simples de bytes como essa podem levar à corrupção de dados (incluindo caracteres de escape / citações) - isso pode ser explorado deliberadamente por um invasor mal-intencionado para injetar SQL arbitrário.
Eggyal
Se você errar os conjuntos de caracteres, pode ser perigoso. Para conjuntos de caracteres multibyte, se mysql estiver usando isso, alguém pode simplesmente inserir um byte para cancelar o \\. Conjuntos de caracteres multiebyte podem freqüentemente receber qualquer coisa como o segundo byte, incluindo \\ para mysql não o verá como um \\ autônomo, mas como parte do caractere multibyte. Não tenho ideia do que acontece com UTF8. Eu espero que com [0xB0, '\\'] que ao atingir um byte inválido \\ que é apenas pare e comece novamente com aquele byte ao invés de engoli-lo.
jgmjgm
1
Se eu souber que o conjunto de caracteres é utf8, é seguro usar mb_strpos()(e mb_substr()criar um comportamento semelhante a substr_replace()) para fazer isso?
SOFe
28

Em oposição direta à minha outra resposta, esta função a seguir é provavelmente segura, mesmo com caracteres multibyte.

// replace any non-ascii character with its hex code.
function escape($value) {
    $return = '';
    for($i = 0; $i < strlen($value); ++$i) {
        $char = $value[$i];
        $ord = ord($char);
        if($char !== "'" && $char !== "\"" && $char !== '\\' && $ord >= 32 && $ord <= 126)
            $return .= $char;
        else
            $return .= '\\x' . dechex($ord);
    }
    return $return;
}

Espero que alguém com mais conhecimento do que eu possa me dizer por que o código acima não funciona ...

muito php
fonte
+1 Obrigado pelo esforço extra. Vou descobrir mais sobre injeções de SQL relacionadas a vários bytes.
Viet
Eu acho que deveria ser $ return. = '\ X'. dechex ($ ord); em vez disso
Viet
1
Como regra geral, prefiro usar '\\' mesmo em strings entre aspas simples, só porque um único '\' pode afetar o próximo caractere se você não tomar cuidado. Provavelmente estou apenas sendo TOC de novo.
muito php
1
Esta função não segue as regras de escape do mysql e resultará na perda da integridade dos dados. "O MySQL reconhece as sequências de escape mostradas na Tabela 9.1,“ Sequências de escape de caracteres especiais ”. Para todas as outras sequências de escape, a barra invertida é ignorada. Ou seja, o caractere de escape é interpretado como se não tivesse escapado. Por exemplo,“ \ x ” é apenas “x”. " - dev.mysql.com/doc/refman/5.6/en/…
velcrow
2
\ XAA realmente significa algo mais do que o texto "xAA" em uma string literal do MySQL? A documentação parece dizer que \ x não tem nenhum significado especial, então o \ será ignorado. dev.mysql.com/doc/refman/5.0/en/string-literals.html
Jason
6

De pesquisas adicionais, descobri:

http://dev.mysql.com/doc/refman/5.1/en/news-5-1-11.html

Correção de segurança:

Uma brecha de segurança de injeção de SQL foi encontrada no processamento de codificação multibyte. O bug estava no servidor, interpretando incorretamente a string de escape com a função da API C mysql_real_escape_string ().

Esta vulnerabilidade foi descoberta e relatada por Josh Berkus e Tom Lane como parte da colaboração de segurança entre projetos do consórcio OSDB. Para obter mais informações sobre injeção de SQL, consulte o texto a seguir.

Discussão. Uma falha de segurança de injeção SQL foi encontrada no processamento de codificação multibyte. Uma brecha de segurança de injeção de SQL pode incluir uma situação em que, quando um usuário forneceu dados a serem inseridos em um banco de dados, o usuário pode injetar instruções SQL nos dados que o servidor executará. Com relação a esta vulnerabilidade, quando o escape sem conhecimento do conjunto de caracteres é usado (por exemplo, addslashes () em PHP), é possível contornar o escape em alguns conjuntos de caracteres multibyte (por exemplo, SJIS, BIG5 e GBK). Como resultado, uma função como addslashes () não é capaz de prevenir ataques de injeção de SQL. É impossível consertar isso no lado do servidor. A melhor solução é para os aplicativos usarem o escape ciente de conjunto de caracteres oferecido por uma função como mysql_real_escape_string ().

No entanto, um bug foi detectado em como o servidor MySQL analisa a saída de mysql_real_escape_string (). Como resultado, mesmo quando a função com reconhecimento de conjunto de caracteres mysql_real_escape_string () foi usada, a injeção de SQL foi possível. Este bug foi corrigido.

Soluções alternativas. Se você não conseguir atualizar o MySQL para uma versão que inclua a correção do bug na análise mysql_real_escape_string (), mas execute o MySQL 5.0.1 ou superior, você pode usar o modo SQL NO_BACKSLASH_ESCAPES como uma solução alternativa. (Este modo foi introduzido no MySQL 5.0.1.) NO_BACKSLASH_ESCAPES habilita um modo de compatibilidade padrão SQL, onde a barra invertida não é considerada um caractere especial. O resultado será que as consultas falharão.

Para definir este modo para a conexão atual, insira a seguinte instrução SQL:

SET sql_mode='NO_BACKSLASH_ESCAPES';

Você também pode definir o modo globalmente para todos os clientes:

SET GLOBAL sql_mode='NO_BACKSLASH_ESCAPES';

Este modo SQL também pode ser ativado automaticamente quando o servidor é iniciado usando a opção de linha de comando --sql-mode = NO_BACKSLASH_ESCAPES ou definindo sql-mode = NO_BACKSLASH_ESCAPES no arquivo de opções do servidor (por exemplo, my.cnf ou my.ini , dependendo do seu sistema). (Bug # 8378, CVE-2006-2753)

Veja também Bug # 8303.

Viet
fonte
1
Isso foi consertado há muito tempo.
Seu senso comum
2
Também tome cuidado, pois isso NO_BACKSLASH_ESCAPES introduz outras vulnerabilidades .
Eggyal
2
Corrigido em 5.1.11 - O link estava quebrado, aqui está o arquivo: web.archive.org/web/20120501203047/http://dev.mysql.com:80/doc/…
Bastião