Java-escape string para prevenir a injecção de SQL

Estou a tentar colocar uma injeção anti-sql em java e estou a achar muito difícil trabalhar com a função string "substitueall". 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, de modo que quando a seqüência de caracteres é avaliada pelo MySQL SQL injeções será bloqueado.

Arranjei um código com o qual estava a trabalhar e todas as funções estão a enlouquecer-Me. Se por acaso, qualquer pessoa que tenha um exemplo disso, eu apreciaria muito.

Author: Tim Pietzcker, 2009-11-28

11 answers

Os equipamentos de preparação são o caminho a seguir, porque tornam impossível a injecção de SQL. Aqui está um exemplo simples que leva a entrada do usuário como os 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
      }
   }
}

Independentemente dos caracteres em nome e E-mail, esses caracteres serão colocados directamente na base de dados. Não vão afectar a declaração de inserção de forma alguma.

Existem diferentes métodos de conjunto para diferentes tipos de dados -- o que você usa depende de quais são os campos da sua base de dados. Por exemplo, se você tem um Coluna inteira na base de Dados, deverá usar um método setInt. a documentação de Preparação lista todos os diferentes métodos disponíveis para definir e obter dados.

 228
Author: Kaleb Brasee, 2011-04-23 14:22:33

A única forma de prevenir a injecção de SQL é com SQL parametrizado. Simplesmente não é possível construir um filtro que seja mais inteligente do que as pessoas que hackeiam o SQL para viver.

Então use parâmetros para todas as entradas, atualizações e onde as cláusulas. O SQL dinâmico é simplesmente uma porta aberta para hackers, e isso inclui o SQL dinâmico em procedimentos armazenados. Parametrização, parametrização, parametrização.

 45
Author: Cylon Cat, 2009-11-28 16:14:16

Se realmente não puder usar Opção de Defesa 1: instruções preparadas (consultas parametrizadas) ou opção de Defesa 2: procedimentos armazenados, não crie a sua própria ferramenta, use a API de segurança da OWASP Enterprise. From the OWASP ESAPI hosted on Google Code:

Não escrevas os teus próprios controlos de segurança! Reinventar a roda quando se trata de desenvolver controles de segurança para cada aplicação web ou serviço web leva a tempo desperdiçado e massivo buracos de segurança. Os Toolkits da OWASP Enterprise Security API (ESAPI) ajudam os desenvolvedores de software a proteger contra Falhas de design e implementação relacionadas à segurança.

Para mais detalhes, Ver prevenção da injecção de SQL em Java e prevenção da injecção de SQL (Cheat Sheet) .

Dê uma atenção especial à opção de Defesa 3: escapar a todos os dados fornecidos pelo Utilizador que introduz o projecto OWASP ESAPI ).

 33
Author: Pascal Thivent, 2009-11-28 16:40:40
(Isto é em resposta ao comentário do OP sob a pergunta original; eu concordo completamente que a PreparedStatement é a ferramenta para este trabalho, não regexes.) Quando dizes:\+n ou uma personagem de linha? Se for \+n, a tarefa é bastante simples:
s = s.replaceAll("['\"\\\\]", "\\\\$0");

Para coincidir com uma barra invertida na entrada, coloca-se quatro delas na sequência regex. Para colocar um backslash na saída, você coloca quatro deles na substituição cadeia. Isto assumindo que você está criando as regexes e substituições na forma de literais de String Java. Se você criá-los de qualquer outra forma (por exemplo, lendo-os a partir de um arquivo), você não tem que fazer toda essa dupla fuga.

Se tiver um carácter de linha na entrada e quiser substituí-lo por uma sequência de escape, poderá fazer uma segunda passagem sobre a entrada com isto:

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

Ou talvez queiras duas recaídas (não sou muito claro nisso):

s = s.replaceAll("\n", "\\\\\\\\n");
 17
Author: Alan Moore, 2013-08-10 00:35:39
Os preparativos são o caminho a seguir na maioria dos casos, mas não em todos. Às vezes você vai se encontrar em uma situação em que uma consulta, ou uma parte dela, tem que ser construída e armazenada como uma string para uso posterior. Para mais detalhes e APIs em diferentes linguagens de programação, consulte a ficha de prevenção da injecção de SQL no Site OWASP .
 13
Author: jonnieZG, 2011-01-11 15:56:59

Usando uma expressão regular para remover o texto que poderia causar uma injecção de SQL soa como se a instrução SQL estivesse a ser enviada para a base de dados através de um Statement em vez de um PreparedStatement.

Uma das formas mais fáceis de prevenir uma injecção de SQL é, em primeiro lugar, usar um {[[1]}, que aceita dados para substituir numa declaração SQL usando espaços, que não depende de combinações de strings para criar uma declaração SQL para enviar para a base de dados.

Para mais information, Using Prepared Statements from The Java Tutorials would be a good place to start.

 9
Author: coobird, 2009-11-28 16:14:30

As declarações preparadas são a melhor solução, mas se realmente precisar de o fazer manualmente, também poderá utilizar o StringEscapeUtils classe da biblioteca Apache Commons-Lang. Tem um escapeSql(String) método que pode utilizar:

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

 8
Author: ToBe_HH, 2017-05-13 21:23:03

No caso, você está lidando com um sistema legado, ou você tem muitos lugares para se mudar para PreparedStatements em muito pouco tempo - por exemplo, se houver um obstáculo à utilização das melhores práticas sugeridas por outras respostas, você pode tentar AntiSQLFilter

 6
Author: Bozho, 2009-11-28 16:45:08

É necessário o seguinte código abaixo. Num relance, isto pode parecer qualquer código antigo que eu inventei. No entanto, o que eu fiz foi olhar o código-fonte de http://grepcode.com/file/repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.31/com/mysql/jdbc/PreparedStatement.java. Depois disso, estudei através do código de setString(int parameterIndex, String x) para encontrar os personagens que ele escapa e personalizado de presente para a minha própria classe, de modo que ele pode ser usado para o propósitos que você precisa. Afinal, se esta é a lista de personagens que a Oracle escapa, então saber isso é realmente reconfortante em termos de segurança. Talvez Oracle precise de um empurrão para adicionar um método semelhante a este para a próxima grande versão 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();
    }
}
 6
Author: Richard, 2016-01-07 08:12:58

Depois de procurar uma grande quantidade de solução de teste para evitar a injecção de sqlmap de SQL, no caso de um sistema antigo que não pode aplicar estatamentos preparados em todos os locais.

Java-security-cross-site-scripting-xss-and-sql-injection topic A SOLUÇÃO FOI

Tentei a solução de @ Richard, mas não funcionou no meu caso. eu usei um filtro
O objectivo deste filtro é transformar o pedido num código próprio. embalagem MyHttpRequestWrapper que se transforma:

Os parâmetros HTTP com caracteres especiais ( ,',...) no HTML codes via the org.quadro de primavera.site.util.HtmlUtils.htmlEscape(...) metodo. Nota: Há classe semelhante no Apache Commons : organizacao.Apache.comuns.idioma.StringEscapeUtils.escapeHtml (...) o SQL personagens de injeção ( ' ,",...) através do classe Apache Commons organizacao.Apache.comuns.idioma.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;
    }
}
 0
Author: shareef, 2016-09-11 20:28:46

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;

}

 0
Author: Billcountry Mwaniki, 2017-05-17 12:48:21