2015년 11월 30일 월요일

입력데이터 검증 및 표현 - 자원 삽입

1)     자원 삽입
외부 입력값을 검증하지 않고 시스템 자원(resource)에 대한 식별자로 사용하는 경우, 공격자는 입력값 조작을 통해 시스템이 보호되는 자원에 임의로 접근하거나 수정할 수 있고, 잘못된 입력값으로 인해 시스템 자원 사이에 충돌이 발생할 수 있다.

n  안전한 코딩 기법
     외부의 입력을 자원(파일) 식별자로 사용하는 경우, 적절한 검증을 거치도록 하거나 사전에 정의된 적합한 리스트에서 선택되도록 작성한다.
     경로순회(Directory Travelsal)를 수행할 수 있는 문자를 제거한다. (../, ;, \, /)
1.   // 경로순회를 수행할 있는 문자 제거
2.   private String makeSecurePath(String path) {  
3.       path = path.replaceAll("../""");  
4.       path = path.replaceAll(";""");  
5.         
6.       return path;  
7.   }  

1.   // 화이트 리스트를 통한 시스템 자원의 보호
2.   public final String[] availableIP = {  
3.       "127.0.0.1",  
4.       "192.168.0.1",  
5.       "192.168.0.2",  
6.       "192.168.0.3"  
7.   };  
8.   private void createClientSocket(String ip){  
9.       Socket socket;    
10.      int port=7777;  
11.      boolean isValid = false;  
12.        
13.      try{  
14.          for(int i=0; i<availableIP .length; i++) {  
15.              if(availableIP [i].equals(ip)) {  
16.                  isValid = true;  
17.                  break;  
18.              }  
19.          }  
20.          if(isValid) socket = new Socket(ip, port);  
21.           else socket = new Socket(availableIP[0], port);  
22.      } catch (IOException e) {  
23.          System.out.println("소켓 생성에 실패하였습니다.");  
24.      }  
25.  }  



  1. public void fileUpload(HttpServletRequest request,  
  2.             String ADDFILE_ROOT_PATH, int ADDFILE_MAXSIZE) throws Exception {  
  3.   
  4.         if (!new File(ADDFILE_ROOT_PATH).exists())  
  5.             new File(ADDFILE_ROOT_PATH).mkdir();  
  6.   
  7.         // [commons-fileupload-1-2.jar] DiskFileItemFactory, ServletFileUpload, FileItem  
  8.         DiskFileItemFactory factory = new DiskFileItemFactory();  
  9.         factory.setSizeThreshold(ADDFILE_MAXSIZE);  
  10.         factory.setRepository(new File(ADDFILE_ROOT_PATH));  
  11.   
  12.         ServletFileUpload upload = new ServletFileUpload(factory);  
  13.         upload.setSizeMax(ADDFILE_MAXSIZE);  
  14.   
  15.         String fullDir = "";  
  16.         String dir = "";  
  17.         try {  
  18.             List items = upload.parseRequest(request);  
  19.             Iterator iter = items.iterator();  
  20.   
  21.             for (int i = 0; i < items.size(); i++) {  
  22.                 FileItem item = (FileItem) items.get(i);  
  23.   
  24.                 if (item.isFormField()) {  
  25.                     if (item.getFieldName().equals("UPLOAD_DIR"))  
  26.                         dir = item.getString();  
  27.                 }  
  28.             }  
  29.   
  30.             if (dir.equals("")) {  
  31.                 fullDir = ADDFILE_ROOT_PATH + "/temp";  
  32.             } else {  
  33.                 fullDir = ADDFILE_ROOT_PATH + "/" + dir;  
  34.             }  
  35.   
  36.             if (!new File(fullDir).exists())  
  37.                 new File(fullDir).mkdir();  
  38.   
  39.             int tmpCnt = 0;  
  40.             while (iter.hasNext()) {  
  41.                 FileItem item = (FileItem) iter.next();  
  42.   
  43.                 if (!item.isFormField()) {  
  44.                     if (item.getName().length() != 0) {  
  45.                         String fieldName = item.getFieldName();  
  46.   
  47.                         String itemName = item.getName();  
  48.                         itemName = itemName.substring(itemName.lastIndexOf("/") + 1);  
  49.   
  50.                         // check available file extension  
  51.                           
  52.                         String orgFileName = itemName;  
  53.                         String sysFileName = "______"// generate random name for save                               
  54.   
  55.                         File sysFile = new File(fullDir + "/" + sysFileName);  
  56.                         item.write(sysFile);
  57.                     }  
  58.                 }  
  59.                 tmpCnt++;  
  60.             }  
  61.         } catch (IOException ex) {  
  62.             throw ex;  
  63.         } catch (Exception ex) {  
  64.             throw ex;  
  65.         }  
  66.     }  

입력데이터 검증 및 표현 - SQL 삽입 (SQL Injection)

1.  입력데이터 검증 및 표현
프로그램 입력 값에 대한 검증 누락 또는 부적절한 검증, 데이터의 잘못된 형식지정, 일관되지 않은 언어셋 사용 등으로 인해 발생하는 보안약점으로 SQL 삽입, 크로스사이트 스크립트(XSS) 등의 공격을 유발할 수 있다.

1)     SQL 삽입(SQL Injection)
데이터베이스(DB)와 연동된 웹 어플리케이션에서 입력된 데이터에 대한 유효성 검증을 하지 않을 경우, 공격자가 입력 폼 및 URL 입력란에 SQL 문을 삽입하여 DB로부터 정보를 열람하거나 조작할 수 있는 보안약점을 말한다.

n  안전한 코딩 기법
     PreparedStatement 클래스와 하위 메소드 excuteQuery(), execute(), excuteUpdate()를 사용한다.
     PreparedStatement 클래스를 사용할 수 없는 환경이라면, 입력 값을 필터링 처리한 후 사용한다.
     Mybatis Data Map 파일의 인자를 받는 질의 명령어 정의시에 문자열 삽입 인자($..$)를 사용하지 않고, 질의 구조에 영향을 주지 않는 #<인자이름># 형태의 질의문을 사용한다. 부득이하게 삽입인자($..$)를 사용할 경우에는 입력 값을 필터링 처리하여 사용한다.


  1. import java.io.IOException;  
  2. import java.sql.Connection;  
  3. import java.sql.DriverManager;  
  4. import java.sql.ResultSet;  
  5. import java.sql.SQLException;  
  6. import java.sql.Statement;  
  7. import java.util.regex.Matcher;  
  8. import java.util.regex.Pattern;  
  9.   
  10. import javax.servlet.ServletConfig;  
  11. import javax.servlet.ServletException;  
  12. import javax.servlet.http.HttpServlet;  
  13. import javax.servlet.http.HttpServletRequest;  
  14. import javax.servlet.http.HttpServletResponse;  
  15.   
  16. public class SQLInjectionSample extends HttpServlet {  
  17.     private static final long serialVersionUID = 1L;  
  18.     private Connection conn;  
  19.       
  20.     private final static int MAX_USER_ID_LENGTH = 14;  
  21.     private final static int MAX_PASSWORD_LENGTH = 16;  
  22.     private final static String UNSECURED_CHAR_REGULAR_EXPRESSION = "[^\\p{Alnum}]|select|delete|update|insert|create|alter|drop";  
  23.     private static Pattern unsecuredCharPattern = Pattern.compile(UNSECURED_CHAR_REGULAR_EXPRESSION, Pattern.CASE_INSENSITIVE);  
  24.       
  25.     public void init(ServletConfig config) throws ServletException {  
  26.         unsecuredCharPattern = Pattern.compile(UNSECURED_CHAR_REGULAR_EXPRESSION, Pattern.CASE_INSENSITIVE);  
  27.     }  
  28.       
  29.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  30.         Statement stmt = null;  
  31.         ResultSet rs = null;  
  32.         String action = request.getParameter("action");  
  33.         if(action == null || "".equals(action)) { action = "default"; }  
  34.         if(action.equals("login")) {  
  35.             try {  
  36.                 conn = DriverManager.getConnection("url""user""password");  
  37.                 stmt = conn.createStatement();  
  38.                 String userId = request.getParameter("user_id");  
  39.                 String password = request.getParameter("password");  
  40.                   
  41.                 if(userId == null || "".equals(userId) || password == null || "".equals(password)) {  
  42.                     throw new Exception("check login info");  
  43.                 } else {  
  44.                 }  
  45.                   
  46.                 userId = makeSecureString(userId, MAX_USER_ID_LENGTH);  
  47.                 password = makeSecureString(password, MAX_PASSWORD_LENGTH);  
  48.                   
  49.                 String query = "SELECT * FROM MEMBERS WHERE userid=" + userId + " AND password=" + password;  
  50.                 rs = stmt.executeQuery(query);  
  51.                   
  52.             } catch (SQLException e) {  
  53.                 System.out.println(e.getMessage());  
  54.                 e.printStackTrace();  
  55.             } catch (Exception e) {  
  56.                 System.out.println(e.getMessage());  
  57.             } finally {  
  58.                 try {  
  59.                     if(rs != null) { rs.close(); }  
  60.                     if(stmt != null) { stmt.close(); }  
  61.                     if(conn != null) { conn.close(); }  
  62.                 } catch (SQLException e) {  
  63.                     System.out.println(e.getMessage());  
  64.                 }  
  65.             }  
  66.         }  
  67.     }  
  68.       
  69.     private String makeSecureString(final String str, int maxLength) {  
  70.         String secureStr = str.substring(0, maxLength);  
  71.         Matcher matcher = unsecuredCharPattern.matcher(secureStr);  
  72.           
  73.         return matcher.replaceAll("");  
  74.     }  
  75. }