복붙노트

[SQL] 어떻게 내가 준비된 문을 사용하지 않고 SQL을 소독

SQL

어떻게 내가 준비된 문을 사용하지 않고 SQL을 소독

일부 SQL 문을 위해 나는 예를 들어 준비된 문을 사용할 수 없습니다 :

SELECT MAX(AGE) FROM ?

예를 들어 나는 테이블을 변경하고자 할 때. 소독하라고 자바에서 SQL하는 유틸리티가 있습니까? 루비에서 하나가있다.

해결법

  1. ==============================

    1.오른쪽, 준비된 명령문 쿼리 매개 변수는 단일 문자 값을 사용하는 것이 경우에만 사용할 수 있습니다. 당신은 테이블 이름, 열 이름, 값 목록, 또는 다른 SQL 구문에 대한 매개 변수를 사용할 수 없습니다.

    오른쪽, 준비된 명령문 쿼리 매개 변수는 단일 문자 값을 사용하는 것이 경우에만 사용할 수 있습니다. 당신은 테이블 이름, 열 이름, 값 목록, 또는 다른 SQL 구문에 대한 매개 변수를 사용할 수 없습니다.

    당신은 SQL 문자열로 응용 프로그램 변수를 보간 적절하게 문자열을 인용 할 필요가 그래서. 테이블 이름 식별자를 구분하고, 그것을 배로 인용 문자열을 탈출 인용 사용을 수행합니다

    java.sql.DatabaseMetaData md = conn.getMetaData();
    String q = md.getIdentifierQuoteString();
    String sql = "SELECT MAX(AGE) FROM %s%s%s";
    sql = String.format(sql, q, tablename.replaceAll(q, q+q), q);
    

    테이블 이름 그대로 테이블 "이름 및 RDBMS 식별자 인용 문자는"인 경우 예를 들어, SQL 문자열을 같이 포함해야한다 :

    SELECT MAX(AGE) FROM "table""name"
    

    또한 ChssPly76의 의견 @ 동의 - 사용자 입력이 실제로 문자 테이블 이름이 아니라 기표 코드가있는 당신이 다음 보간에 SQL 쿼리, 테이블 이름에 매핑하는 것이 경우가 가장 좋습니다. 이것은 당신에게 어떤 SQL 주입이 발생하지 않도록 더 확신을 제공합니다.

    HashMap h = new HashMap<String,String>();
    /* user-friendly table name maps to actual, ugly table name */
    h.put("accounts", "tbl_accounts123");
    
    userTablename = ... /* user input */
    if (h.containsKey(userTablename)) {
      tablename = h.get(userTablename);
    } else {
      throw ... /* Exception that user input is invalid */
    }
    String sql = "SELECT MAX(AGE) FROM %s";
    /* we know the table names are safe because we wrote them */
    sql = String.format(sql, tablename); 
    
  2. ==============================

    2.가능하지 않습니다. 최고의 당신이 할 수있는 것은 문자열 # 형식을 사용하는 것입니다 ().

    가능하지 않습니다. 최고의 당신이 할 수있는 것은 문자열 # 형식을 사용하는 것입니다 ().

    String sql = "SELECT MAX(AGE) FROM %s";
    sql = String.format(sql, tablename);
    

    이 SQL 주입 위험을 피하지 않습니다. TABLENAME 사용자 / 클라이언트 제어 값 인 경우) (문자열 # 완전히 대체를 사용하여 소독해야 할 것입니다.

    tablename = tablename.replaceAll("[^\\w]", "");
    

    도움이 되었기를 바랍니다.

    [편집] 나는 추가해야합니다 : 당신이 된 PreparedStatement를 사용하여 열 값이 사용하지 마십시오. 그냥 모든 열 값에 대해 그것을 일반적인 방법을 사용하여 계속합니다.

    [Edit2가]는 최상의 사용자 / 클라이언트가 TABLENAME 그것을 원하는 방식으로 입력 할 수 못하게하는 것이나, 그래서 UI에서 (당신이 DatabaseMetaData의 # getCatalogs ()에 의해 얻을 수있는) 모든 유효한 테이블 이름이 포함 된 드롭 다운 더 나은 존재하는 사용자 / 클라이언트를 선택할 수 있습니다. 하나는 요청 매개 변수를 스푸핑 수 있기 때문에 선택이 유효한 경우 서버 측에 확인하는 것을 잊지 마십시오.

  3. ==============================

    3.이 경우 당신은 DatabaseMetaData의에서 나열하는 표를 얻어서 사용 가능한 테이블 목록에 테이블 이름을 확인할 수 있습니다. 실제로 아마 공간, 아마도 일부 SQL 예약어를 제거하는 정규식을 사용하기가 더 쉬울 수있다 ";"등의 문자열의 사전 완전한 SQL 문을 구축 및 String.format liek 것을 사용합니다.

    이 경우 당신은 DatabaseMetaData의에서 나열하는 표를 얻어서 사용 가능한 테이블 목록에 테이블 이름을 확인할 수 있습니다. 실제로 아마 공간, 아마도 일부 SQL 예약어를 제거하는 정규식을 사용하기가 더 쉬울 수있다 ";"등의 문자열의 사전 완전한 SQL 문을 구축 및 String.format liek 것을 사용합니다.

    아마의 '테이블 이름을 감싸는 및 문자열처럼 탈출되어 있기 때문에 당신의 PreparedStatement를 사용할 수없는 이유입니다.

  4. from https://stackoverflow.com/questions/1677465/how-do-i-sanitize-sql-without-using-prepared-statements by cc-by-sa and MIT license