△/SecureCoding

SQL 삽입

KkingKkang 2022. 11. 11. 13:42
728x90

 

데이터베이스와 연동된 웹 어플리케이션에서 입력된 데이터에 대한 유효성 검증을 하지 않을 경우,

공격자가 입력 폼 및 URL 입력란에 SQL 문을 삽입하여 DB로부터 정보를 열람하거나 조작할 수 있는 보안약점을 말한다. 

1) preparedStatement 클래스와 하위 메소드 executeQuery(), execute(), executeUpdate()를 사용하는 것이 바람직하다.

안전하지 않은 코드▼

    String query = " SELECT * FROM " + tableName + " WHERE Name = " + name;

외부로부터 tableName 과 name 의 값을 받아서 SQL 쿼리를 생성하고 있다.

안전한 코드 ▼

String query = "SELECT * FROM ? WHERE Name = ? ";
stmt = con.prepareStatement(query);
stmt.setString(1, tableName);
stmt.setString(2, name);

인자 부분을 set메소드로 설정하여 외부의 입력이 쿼리문의 구조를 바꾸는 것을 방지한다.

 

2) preparedStatement 클래스를 사용할 수 없는 환경이라면, 입력값을 필터링 처리한 후 사용한다.

(SQL 구문 제한, 특수문자 제한, 길이제한을 복합적으로 사용)

makeSecureString 함수 

- 문자열의 길이 제한을 낮춘다.

- 정규식에 포함되는 단어의 개수를 높인다. (악용 가능성이 있는 SQL procedure명이나 SQL 명령어들을 필터링할 정규식에 포함)

안전한 코드 ▼

public class SqlInjectionSample extends HttpServlet 
{
	//작업의 type을 지정한다
    private final String GET_USER_INFO_CMD = "get_user_info";
    private Connection con;
    
    //id 와 password의 최대 길이제헌을 8character와 16character로 제한한다.
    private final static int MAX_USER_ID_LENGTH = 8;
    private final static int MAX_PASSWORD_LENGTH = 16;
    
    //select delete update insert 등 기본 명령어의 알파벳,
    //숫자를 제외한 다른 문자들(인젝션에 사용되는 특수문자 포함)을 검출하는 정규식 설정
    private final static String UNSECURED_CHAR_REGULAR_EXPRESSION = 
    	"[^\\p[Alnum]]|select|delete|update|insert|create|after|drop";
        
    private Pattern unsecuredCharPattern;
    
    //정규식을 초기화한다.
    public void initialize()
    {
    	unsecuredCharPattern.compile(UNSECURED_CHAR_REGULAR_EXPRESSION,Pattern.CASE_INSENSITIVE);
	}
    
    //입력값을 정규식을 이용해 필터링한 후 의심되는 부분을 없앤다.
    private String makeSecureString(final String str, int maxLength)
    {
    	String secureStr = str.substring(0, maxxLength);
        Matcheer matcher = unsecuredCharPattern.matcher(secureStr);
        return matcher.replaceAll("");
    }
    
    //입력값을 받아 필터링한 후 쿼리로 만들어 처리한다.
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
    	String command = request.getParameter("command");
        if (command.equals(GET_USER_INFO_CMD))
        {
        	Statement stmt = conn.createStatement();
            String userId = request.getParameter("user_id");
            String password = request.getParameter("new_password");
            String query = "SELECT * FROM members WHERE username= '" + makeSecureString(userId, MAX_USER_ID_LENGTH) 
            				+ "' AND password = '" + makeSecureString(password, MAX_PASSWORD_LENGTH) + "'";
   			
            stmt.executeUpdate(query);
          }
       }
       
    }

 

 

728x90