Java-escape string para prevenir a injecção de SQL
\
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.
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.
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.
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 ).
\
+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");
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.
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);
No caso, você está lidando com um sistema legado, ou você tem muitos lugares para se mudar para PreparedStatement
s 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
É 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();
}
}
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 filtroO 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;
}
}
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;
}