문제

나는 Java에 안티 SQL 주입을 제자리에 놓으려고 노력하고 있으며 "replaceall"문자열 함수와 함께 작업하기가 매우 어렵다는 것을 알게되었습니다. 궁극적으로 기존의 모든 변환 기능이 필요합니다. \ 에게 \\, 어느 " 에게 \", 어느 ' 에게 \', 그리고 어떤 것도 \n 에게 \\n 따라서 문자열이 MySQL SQL 주입에 의해 평가 될 때 차단됩니다.

나는 내가 함께 일하고 있던 몇 가지 코드를 훔쳤다. \\\\\\\\\\\ 기능에서 내 눈을 견과하게 만들고 있습니다. 누군가가 이것의 예를 가지고 있다면 나는 그것을 크게 감사하겠습니다.

도움이 되었습니까?

해결책

준비된 상태는 SQL 주입이 불가능하기 때문에 갈 길입니다. 다음은 사용자의 입력을 매개 변수로 취하는 간단한 예입니다.

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
      }
   }
}

이름과 이메일의 문자에 관계없이 해당 문자는 데이터베이스에 직접 배치됩니다. 어떤 식 으로든 삽입 문에 영향을 미치지 않습니다.

다른 데이터 유형에 대한 다른 세트 방법이 있습니다. 사용하는 방법은 데이터베이스 필드의 내용에 따라 다릅니다. 예를 들어, 데이터베이스에 정수 열이있는 경우 setInt 방법. 준비된 상태 문서 데이터를 설정하고 가져 오는 데 사용할 수있는 모든 다른 방법을 나열합니다.

다른 팁

SQL 주입을 방지하는 유일한 방법은 매개 변수화 된 SQL입니다. 생계를 위해 SQL을 해킹하는 사람들보다 더 똑똑한 필터를 만들 수는 없습니다.

따라서 모든 입력, 업데이트 및 조항에 매개 변수를 사용하십시오. Dynamic SQL은 단순히 해커를위한 열린 도어이며 여기에는 저장 프로 시저에서 동적 SQL이 포함됩니다. 매개 변수화, 매개 변수화, 매개 변수입니다.

실제로 사용할 수 없다면 방어 옵션 1 : 준비된 진술 (매개 변수화 쿼리) 또는 방어 옵션 2 : 저장 절차, 자신의 도구를 구축하지 말고 사용하십시오 OWASP 엔터프라이즈 보안 API. 로부터 Owasp esapi Google 코드에서 호스팅 :

자신의 보안 컨트롤을 작성하지 마십시오! 모든 웹 애플리케이션 또는 웹 서비스에 대한 보안 컨트롤을 개발할 때 휠을 재창조하면 시간이 낭비되고 대규모 보안 구멍이 발생합니다. OWASP Enterprise Security API (ESAPI) 툴킷은 소프트웨어 개발자가 보안 관련 설계 및 구현 결함을 방지 할 수 있도록 도와줍니다.

자세한 내용은 참조하십시오 Java에서 SQL 주입 방지 그리고 SQL 주입 방지 치트 시트.

특별한주의를 기울이십시오 방어 옵션 3 : 모든 사용자가 제공 한 입력 탈출 그것은 그것을 소개합니다 Owasp esapi 프로젝트).

(이것은 원래의 질문에 따라 OP의 의견에 대한 답변입니다. 나는 준비된 상태가 정규식이 아닌이 작업의 도구라는 데 전적으로 동의합니다.)

당신이 말할 때 \n, 당신은 시퀀스를 의미합니까? \+n 아니면 실제 라인 피드 캐릭터? 그렇다면 \+n, 작업은 매우 간단합니다.

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

입력에 하나의 백 슬래시와 일치하려면 4 개를 Regex 문자열에 넣습니다. 출력에 하나의 백 슬래시를 넣으려면 그 중 4 개를 교체 문자열에 넣습니다. 이것은 Java 문자 리터럴 형태로 Regexes 및 교체품을 생성한다고 가정합니다. 다른 방법 (예 : 파일에서 읽어서 읽음)을 만들면 이중 에스케이프를 모두 수행 할 필요는 없습니다.

입력에 라인 피드 문자가 있고 이스케이프 시퀀스로 교체하려면 다음과 같이 입력을 두 번째 패스 할 수 있습니다.

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

아니면 두 개의 백 슬래시를 원할 수도 있습니다 (나는 그것에 대해 너무 명확하지 않습니다) :

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

준비된 상태는 대부분의 경우가 아니라 모든 경우가 아닙니다. 때로는 쿼리 또는 그 일부를 나중에 사용하기 위해 문자열로 구축하고 저장 해야하는 상황에 처하게됩니다. 확인하십시오 SQL 주입 방지 치트 시트OWASP 사이트 다른 프로그래밍 언어의 자세한 내용과 API.

정규 표현식을 사용하여 텍스트를 제거하여 SQL 주입을 유발할 수있는 SQL 문이 데이터베이스로 전송되는 것처럼 Statement a보다는 PreparedStatement.

처음에 SQL 주입을 방지하는 가장 쉬운 방법 중 하나는 PreparedStatement, 자리 표시자를 사용하여 SQL 명령문으로 대체 할 데이터를 수락하는데, 이는 문자열 연결에 의존하여 데이터베이스에 보내기 위해 SQL 문을 작성하지 않습니다.

자세한 내용은, 준비된 진술을 사용합니다 ~에서 Java 튜토리얼 시작하기에 좋은 곳이 될 것입니다.

준비된 진술은 최상의 솔루션이지만 실제로는 수동으로해야한다면 사용할 수도 있습니다. StringEscapeUtils Apache Commons-Lang Library의 클래스. 그것은 있습니다 escapeSql(String) 사용할 수있는 방법 :

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

레거시 시스템을 다루거나 전환 할 장소가 너무 많으면 PreparedStatement너무 적은 시간에 - 즉 다른 답변에서 제안한 모범 사례를 사용하는 데 장애가 있다면 시도 할 수 있습니다. AntisqlFilter

아래 코드가 필요합니다. 한눈에, 이것은 내가 만든 오래된 코드처럼 보일 수 있습니다. 그러나 내가 한 것은 소스 코드를 보는 것이 었습니다. http://grepcode.com/file/repo1.maven.org/maven2/mysql/mysql-java/5.1.31/com/mysql/jdbc/preparedstatement.java. 그런 다음 SetString 코드 (int paramerIndex, String X)를 신중하게 살펴보고이를 피하고 내 자신의 클래스로 사용자 정의하여 필요한 목적으로 사용될 수 있도록 내 자신의 클래스로 사용자 정의했습니다. 결국, 이것이 Oracle이 탈출하는 캐릭터 목록이라면, 이것이 보안에 위안이되는 것을 아는 것입니다. 아마도 Oracle은 다음 주요 Java 릴리스를 위해 이것과 유사한 방법을 추가하기 위해 Nudge가 필요할 것입니다.

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();
    }
}

테스트를 검색 한 후 SQL 주입에서 SQLMAP를 방지하기위한 많은 솔루션을 검색 한 후, 어디에서나 준비된 법적을 적용 할 수없는 레거시 시스템의 경우.

Java-Security-Cross-Site-Scripting-XSS 및 SQL 주제 주제해결책이었습니다

@Richard 솔루션을 시도했지만 제 경우에는 작동하지 않았습니다. 필터를 사용했습니다

이 필터의 목표는 요청을 자체 코딩 된 래퍼 MyhttprequestWrapper로 래퍼하는 것입니다.

org.springframework.web.util.htmlutils.htmlescape (…) 메소드를 통해 HTML 코드에 특수 문자 (<,>, ',…)가있는 HTTP 매개 변수. 참고 : Apache Commons에는 비슷한 classe가 있습니다 : org.apache.commons.lang.stringescapeutils.escapehtml (…) Apache Commons Classe org.apache.commons.lang.stringescapeutils를 통해 SQL 주입 문자 ( ',“,…). 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;
    }
}

에서 : [출처

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;

}

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top