Pergunta

Eu estou tentando colocar um pouco de injeção anti sql no lugar em java e estou achando muito difícil trabalhar com a função a string "replaceAll". Em última análise, eu preciso de uma função que irá converter qualquer \ existente para \\, qualquer " para \", qualquer ' para \' e qualquer \n para \\n modo que quando a string é avaliada por injeções MySQL SQL será bloqueado.

Eu tenho levantado algum código eu estava trabalhando com e todo o \\\\\\\\\\\ na função estão fazendo meus olhos ficam loucos. Se alguém por acaso tem um exemplo disso eu gostaria muito aprecio isso.

Foi útil?

Solução

PreparedStatements são o caminho a percorrer, porque eles fazem a injeção de SQL impossível. Aqui está um exemplo simples de tomar a entrada do usuário como parâmetros:

public insertUser(String name, String email) {
   Connection conn = null;
   PreparedStatement stmt = null;
   try {
      conn = setupTheDatabaseConnectionSomehow();
      stmt = conn.prepareStatement("INSERT INTO person (name, email) values (?, ?)");
      stmt.setString(1, name);
      stmt.setString(2, email);
      stmt.executeUpdate();
   }
   finally {
      try {
         if (stmt != null) { stmt.close(); }
      }
      catch (Exception e) {
         // log this error
      }
      try {
         if (conn != null) { conn.close(); }
      }
      catch (Exception e) {
         // log this error
      }
   }
}

Não importa o que personagens estão em nome e e-mail, esses caracteres serão colocados diretamente no banco de dados. Eles não afetará a instrução INSERT de qualquer forma.

Existem diferentes métodos set para diferentes tipos de dados - qual deles você usar depende do que seus campos de banco de dados são. Por exemplo, se você tiver uma coluna INTEGER no banco de dados, você deve usar um método setInt. a documentação PreparedStatement lista todos os diferentes métodos disponíveis para a definição e obtenção de dados.

Outras dicas

A única maneira de evitar a injeção SQL é com SQL parametrizado. Simplesmente não é possível construir um filtro que é mais inteligente do que as pessoas que hackear SQL para ganhar a vida.

parâmetros usar assim para todas as entradas, atualizações e onde cláusulas. SQL dinâmico é simplesmente uma porta aberta para hackers, e que inclui SQL dinâmica em procedimentos armazenados. Parametrização, parameterize, parameterize.

Se realmente você não pode usar Defesa Opção 1: Instruções preparadas (consultas parametrizadas) ou Defesa opção 2: Procedimentos armazenados , não construir sua própria ferramenta, use o OWASP Enterprise Security API. Do OWASP ESAPI hospedada no Google Code:

Não escreva seus próprios controles de segurança! Reinventando a roda quando se trata de desenvolver controles de segurança para cada aplicação web ou leads de serviços web para falhas de segurança enormes desperdício de tempo e. A API OWASP Enterprise Security (ESAPI) Toolkits ajuda desenvolvedores de software proteger contra falhas de projeto e implementação de segurança relacionadas.

Para mais detalhes, consulte Impedindo SQL Injection em Java e SQL Injection Prevenção cheat Sheet .

pagar uma atenção especial para Defesa Opção 3: Escaping todos fornecidos usuário Input , que introduz o OWASP ESAPI projeto).

(Isto é em resposta ao comentário do OP sob a pergunta original;. Concordo completamente que PreparedStatement é a ferramenta para este trabalho, não Regexes)

Quando você diz \n, você quer dizer a seqüência \ + n ou um caráter real de avanço de linha? Se é \ + n, a tarefa é bastante simples:

s = s.replaceAll("['\"\\\\]", "\\\\$0");

Para corresponder a uma barra invertida na entrada, você coloca quatro deles na seqüência de regex. Para colocar uma barra invertida na saída, você coloca quatro deles no texto de substituição. Isso supõe que você está criando as expressões regulares e substituições na forma de literais Java String. Se você criá-los de outra maneira (por exemplo, lendo-as a partir de um arquivo), você não tem que fazer tudo o que double-escapar.

Se você tem um personagem de avanço de linha na entrada e você deseja substituí-lo com uma seqüência de escape, você pode fazer uma segunda passagem sobre a entrada com este:

s = s.replaceAll("\n", "\\\\n");

Ou talvez você quer duas barras invertidas (eu não sou muito claro sobre isso):

s = s.replaceAll("\n", "\\\\\\\\n");

PreparedStatements são o caminho a percorrer para a maioria, mas não todos os casos. Às vezes você vai encontrar-se em uma situação onde uma consulta, ou uma parte dela, tem que ser construído e armazenado como uma string para uso posterior. Confira o SQL Injection Prevenção Cheat Sheet na OWASP site para mais detalhes e APIs em diferentes linguagens de programação.

Usando uma expressão regular para remover texto que poderia causar um sons de injeção de SQL como a instrução SQL está sendo enviado para o banco de dados através de um Statement em vez de um PreparedStatement .

Uma das maneiras mais fáceis de evitar uma injeção SQL em primeiro lugar é usar um PreparedStatement, que aceita dados de substituir em uma instrução SQL usando espaços reservados, que não depende de concatenações seqüência de caracteres para criar uma instrução SQL para enviar para o banco de dados.

Para mais informações, Usando instruções preparadas de os tutoriais Java seria um bom lugar para começar.

As declarações preparadas são a melhor solução, mas se você realmente precisa fazê-lo manualmente, você também pode usar o StringEscapeUtils classe da biblioteca Apache Commons-Lang. Tem uma escapeSql(String) método, que você pode usar:

import org.apache.commons.lang.StringEscapeUtils; … String escapedSQL = StringEscapeUtils.escapeSql(unescapedSQL);

No caso você está lidando com um sistema legado, ou você tem muitos lugares para mudar para PreparedStatements em muito pouco tempo - ou seja, se houver um obstáculo ao uso da melhor prática sugerida por outras respostas, você pode tentar AntiSQLFilter

Você precisa o seguinte código abaixo. Num relance, este pode ser parecido com qualquer código antigo que eu inventei. No entanto, o que eu fiz foi olhar para o código-fonte para http://grepcode.com/file/repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.31/com/mysql/jdbc/PreparedStatement .java . Então, depois disso, eu cuidadosamente olhou através do código de setString (int parameterIndex, String x) para encontrar os personagens que ele escapa e personalizadas isso para minha própria classe para que ele possa ser utilizado para os fins que você precisa. Afinal, se esta é a lista de caracteres que a Oracle escapa, em seguida, sabendo que isso é realmente reconfortante em termos de segurança. Talvez a Oracle precisa de um empurrãozinho para adicionar um método semelhante a este para o próximo grande lançamento Java.

public class SQLInjectionEscaper {

    public static String escapeString(String x, boolean escapeDoubleQuotes) {
        StringBuilder sBuilder = new StringBuilder(x.length() * 11/10);

        int stringLength = x.length();

        for (int i = 0; i < stringLength; ++i) {
            char c = x.charAt(i);

            switch (c) {
            case 0: /* Must be escaped for 'mysql' */
                sBuilder.append('\\');
                sBuilder.append('0');

                break;

            case '\n': /* Must be escaped for logs */
                sBuilder.append('\\');
                sBuilder.append('n');

                break;

            case '\r':
                sBuilder.append('\\');
                sBuilder.append('r');

                break;

            case '\\':
                sBuilder.append('\\');
                sBuilder.append('\\');

                break;

            case '\'':
                sBuilder.append('\\');
                sBuilder.append('\'');

                break;

            case '"': /* Better safe than sorry */
                if (escapeDoubleQuotes) {
                    sBuilder.append('\\');
                }

                sBuilder.append('"');

                break;

            case '\032': /* This gives problems on Win32 */
                sBuilder.append('\\');
                sBuilder.append('Z');

                break;

            case '\u00a5':
            case '\u20a9':
                // escape characters interpreted as backslash by mysql
                // fall through

            default:
                sBuilder.append(c);
            }
        }

        return sBuilder.toString();
    }
}

Depois de pesquisar um teste de um monte de solução para Prevenir SqlMap de injecção SQL, no caso do sistema legado que não podem aplicar statments preparados em todos os lugares.

java-security-cruzada Site-scripting-XSS-and-sql-injeção tópico Era a solução

i tentou solução @ Richard s, mas não funcionou no meu caso. eu usei um filtro

O objetivo deste filtro é a Wrapper a solicitação em um própria codificados envoltório MyHttpRequestWrapper que transforma:

os parâmetros HTTP com caracteres especiais (<,>, ‘, ...) em HTML códigos através do org.springframework.web.util.HtmlUtils.htmlEscape (...) método. Nota: Não há classe semelhante no Apache Commons: org.apache.commons.lang.StringEscapeUtils.escapeHtml (...) o SQL caracteres de injeção ( ‘“, ...), através da classe Apache Commons org.apache.commons.lang.StringEscapeUtils.escapeSql (...)

<filter>
<filter-name>RequestWrappingFilter</filter-name>
<filter-class>com.huo.filter.RequestWrappingFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>RequestWrappingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>




package com.huo.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletReponse;
import javax.servlet.http.HttpServletRequest;

public class RequestWrappingFilter implements Filter{

    public void doFilter(ServletRequest req, ServletReponse res, FilterChain chain) throws IOException, ServletException{
        chain.doFilter(new MyHttpRequestWrapper(req), res);
    }

    public void init(FilterConfig config) throws ServletException{
    }

    public void destroy() throws ServletException{
    }
}




package com.huo.filter;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.lang.StringEscapeUtils;

public class MyHttpRequestWrapper extends HttpServletRequestWrapper{
    private Map<String, String[]> escapedParametersValuesMap = new HashMap<String, String[]>();

    public MyHttpRequestWrapper(HttpServletRequest req){
        super(req);
    }

    @Override
    public String getParameter(String name){
        String[] escapedParameterValues = escapedParametersValuesMap.get(name);
        String escapedParameterValue = null; 
        if(escapedParameterValues!=null){
            escapedParameterValue = escapedParameterValues[0];
        }else{
            String parameterValue = super.getParameter(name);

            // HTML transformation characters
            escapedParameterValue = org.springframework.web.util.HtmlUtils.htmlEscape(parameterValue);

            // SQL injection characters
            escapedParameterValue = StringEscapeUtils.escapeSql(escapedParameterValue);

            escapedParametersValuesMap.put(name, new String[]{escapedParameterValue});
        }//end-else

        return escapedParameterValue;
    }

    @Override
    public String[] getParameterValues(String name){
        String[] escapedParameterValues = escapedParametersValuesMap.get(name);
        if(escapedParameterValues==null){
            String[] parametersValues = super.getParameterValues(name);
            escapedParameterValue = new String[parametersValues.length];

            // 
            for(int i=0; i<parametersValues.length; i++){
                String parameterValue = parametersValues[i];
                String escapedParameterValue = parameterValue;

                // HTML transformation characters
                escapedParameterValue = org.springframework.web.util.HtmlUtils.htmlEscape(parameterValue);

                // SQL injection characters
                escapedParameterValue = StringEscapeUtils.escapeSql(escapedParameterValue);

                escapedParameterValues[i] = escapedParameterValue;
            }//end-for

            escapedParametersValuesMap.put(name, escapedParameterValues);
        }//end-else

        return escapedParameterValues;
    }
}

De: [Fonte]

public String MysqlRealScapeString(String str){
  String data = null;
  if (str != null && str.length() > 0) {
    str = str.replace("\\", "\\\\");
    str = str.replace("'", "\\'");
    str = str.replace("\0", "\\0");
    str = str.replace("\n", "\\n");
    str = str.replace("\r", "\\r");
    str = str.replace("\"", "\\\"");
    str = str.replace("\\x1a", "\\Z");
    data = str;
  }
return data;

}

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top