PreparedStatement 가 SQL Injection을 방지하는 방법

박상준·2024년 3월 6일
1

JAVA

목록 보기
2/5
post-custom-banner
  • PreparedStatement 는 SQL 인젝션 공격을 방어하는 방법들 중 하나이다.
  • 소스 코드 기반 설명
    • PreparedStatement 에서
          public void setString(int parameterIndex, String x) throws SQLException {
              synchronized (checkClosed().getConnectionMutex()) {
                  // if the passed string is null, then set this column to null
                  if (x == null) {
                      setNull(parameterIndex, Types.CHAR);
                  } else {
                      checkClosed();
      
                      int stringLength = x.length();
      
                      if (this.connection.isNoBackslashEscapesSet()) {
                          // Scan for any nasty chars
      
                          boolean needsHexEscape = isEscapeNeededForString(x, stringLength);
      • isEscapeNeededForString
        • 내부 소스
              private boolean isEscapeNeededForString(String x, int stringLength) {
                  boolean needsHexEscape = false;
          
                  for (int i = 0; i < stringLength; ++i) {
                      char c = x.charAt(i);
          
                      switch (c) {
                          case 0: /* Must be escaped for 'mysql' */
          
                              needsHexEscape = true;
                              break;
          
                          case '\n': /* Must be escaped for logs */
                              needsHexEscape = true;
          
                              break;
          
                          case '\r':
                              needsHexEscape = true;
                              break;
          
                          case '\\':
                              needsHexEscape = true;
          
                              break;
          
                          case '\'':
                              needsHexEscape = true;
          
                              break;
          
                          case '"': /* Better safe than sorry */
                              needsHexEscape = true;
          
                              break;
          
                          case '\032': /* This gives problems on Win32 */
                              needsHexEscape = true;
                              break;
                      }
          
                      if (needsHexEscape) {
                          break; // no need to scan more
                      }
                  }
                  return needsHexEscape;
              }
        • 요 부분에서 해당 x 파라미터가 이스케이프가 필요한 문자가 있는지 체크한다.
        • \n, \r, \', \\ 등이 있는지 검사함.
      • 분기
        1. 문자열에 이스케이프가 필요한 경우

          StringBuilder buf = new StringBuilder((int) (x.length() * 1.1));
          buf.append('\'');
          for (int i = 0; i < stringLength; ++i) {
              char c = x.charAt(i);
              switch (c) {
                  case 0:    buf.append('\\'); buf.append('0'); break;
                  case '\n': buf.append('\\'); buf.append('n'); break;
                  // 추가 이스케이프 처리 필요한 경우
              }
          }
          buf.append('\'');
          • 이스케이프 처리를 수행하는 로직이 수행된다.
          • 개행 문자는
            • \\n
          • 작은 따옴표는
            • \\’ 로 변환됨.
          • 인젝션 공격에 사용될 수 있는 특수 문자가 쿼리의 일부로 해석
        2. 문자열에 이스케이프가 필요없는 경우

          StringBuilder quotedString = new StringBuilder(x.length() + 2);
          quotedString.append('\'');
          quotedString.append(x);
          quotedString.append('\'');
          
          • 단순 입력 문자열 자체를 작은 따옴표로 감싸 SQL 문자열 리터럴로 처리한다.

추가점

  • 파라미터 문자열 자체를 그대로 보내는 건 아닙니다.
  • 입력받은 문자열은 주어진 문자열 인코딩(문자열 → 바이트 변환) 의 일관성을 유지해야함.
    • 바이트 배열로 변환하는 과정에서 애플리케이션의 문자열 데이터가 DB 가 이해할 수 있는 형식으로 인코딩된다.
profile
이전 블로그 : https://oth3410.tistory.com/
post-custom-banner

0개의 댓글