주요 보안 취약점

입력데이터 검증 및 표현

: 입력값 검증 누락 또는 부적절한 검증, 데이터의 잘못된 형식 지정으로 인해 발생.

  • 크로스 사이트 스크립트 공격(XSS): 검증되지 않은 외부입력데이터나 부적절한 스크립트가 포함된 동적 웹페이지가 생성,전송되고 웹페이지에 포함된 부적절한 스크립트가 실행됨
  • 사용자 정보유출, 세션도용, 악성코드 유포, 브라우저 무한반복 등의 공격
  • request.getParameter("name")하는 코드에서 <script>alert(document.cookies)</script>가 입력되면 공격자에게 피해자의 쿠키정보가 전송될 수 있음. => replaceAll()을 사용해 <,>,&,"와 같이 스크립트 생성에 사용되는 모든 문자열을 &lt, &gt 등으로 변경해야 실행하지 못하도록 해야함

sql injection

: 입력 데이터 유효성 점검하지 않아서 db 쿼리 로직이 변경되어 발생.

  • 입력 값이 바로 sql 함수의 파라미터로 전달되지 않게 해야함. 파라미터화된 쿼리를 사용해야함. 자바의 경우 preparedStatement 클래스를 사용해 setString()해서 외부의 입력이 쿼리의 구조를 바꾸는 것을 방지해야함

HTTP 응답 분할

: http 요청 파라미터에 \r\n같은 걸 넣어서 http 응답이 분리된다. 첫번째 응답은 개행문자(\r, \n)로 종료시키고 두번째 응답페이지는 공격자가 맘대로 수정 가능하다. replaceAll을 넣어 개행문자를 제거해 응답헤더가 나눠지는 것을 방지해야함

  • 버퍼 오버플로우: 프로그램이 버퍼에 저장할 수 있는 것보다 큰 데이터가 들어오지 않도록 입력값과 버퍼의 크기를 비교할 것
  • 디렉터리 경로 조작: 파일명을 입력받을 때 상대경로(\,\\ )등을 입력하지 못하도록 replaceAll()로 특수문자 제거할 것
  • os 명령어 injection: cmd.exe 명령어와 다른 명령어 삽입하지 못하도록 입력값에 따른 선택지(white list)를 미리 만들어둘것.
  • 자원 injection: service입력값을 소켓번호로 그대로 사용하는 경우 "-2920"과 같은 값이 들어오면 기존에 80 포트에서 구동되는 서비스와 충돌되어 에러 발생. 검사를 하고, 정해진 선택지 중 정해진 값을 할당하여 포트를 부여할 것.
  • 동적으로 생성되어 수행되는 명령어 injection: eval 사용할때도 입력값 그대로 쓸 것이 아니라 &amp;, &quot; 등으로 replaceAll()하고 써야함
  • 프로세스 제어: 외부 라이브러리 사용시 절대경로 사용할 것.
  • 무제한 파일 업로드: 업로드하는 파일 타입과 크기 제한. 업로드 디렉터리를 웹서버의 다큐먼트 외부에 설정. 화이트리스트 방식으로 허용된 확장자만 업로드, 확장자도 대소문자 구분없이 처리.
  • URL Redirection 시 url과 도메인의 화이트리스트를 이용하고, 사용자로부터 입력받은 url을 그대로 사용하지 말 것
  • 시스템의 상태 정보나 중요한 정보는 서버에만 저장한다. 평문으로 사용자의 유저네임, authenticated값 등을 쿠키에 저장하지 말것.대신 세션에 저장해라. 중요한 정보를 쿠키에 저장할 땐 암호화한다. 외부입력 검사가 js를 통해 브라우저에서 이루어져도 서버 측에서 재검사를 한다.

API 악용

  • 필요한 파라미터가 null인지 검사할 것
  • Java에서 동일 객체는 동일한 해시코드를 가져야한다. 따라서 한 클래스내에서 equals()hashcode()는 둘다 구현하거나 둘다 구현하지 않아야한다. ?????????????

보안특성

  • 하드코드된 패스워드
  • 사이트간 요청 위조: CSRF(Cross-site Request Forgery) / 교차접속 요청 위조: 공격자가 웹서버에 CSRF 공격 코드를 등록, 사용자가 웹 서버에 CSRF script 포함된 페이지를 요청, 웹 서버는 CSRF script를 포함하여 사용자에게 응답, 사용자는 CSRF에 사용자 권한으로 사용가능한 서비스를 요청. get을 쓰면 form 전달값이 노출되므로 CSRF 공격에 쉽게 노출될 수 있다. 인풋 폼 작성시 post 사용할 것. 또는 폼과 입력을 처리하는 프로그램 사이에 토큰을 사용해 공격자의 직접적인 url 사용을 막을 것
  • 부적절한 세션 만료: 세션이 영원히 끝나지않거나 다른 사용자가 세션을 가로챌 수도 있음. 일정시간이 흐르면 세션이 종료되도록 session.setMaxInactivaInterval(12000)등 양의 정수값 설정.
  • 취약한 암호화 알고리즘 사용
  • 예측 가능한 난수 사용. Java에서 Math.random()은 seed를 재설정할 수 없어 위험하다. java.util.RandomsetSeed(new Date().getTime())을 사용해 r을 예측 불가능한 long타입으로 설정해라.
  • 기밀정보의 단순한 텍스트 전송
  • https로만 서비스하는 경우 브라우저 쿠키에 데이터를 저장할때 반드시 Cookie 객체의 setSecure(true) 메서드를 호출해야함. 보안 속성 설정하지 않으면 단순한 텍스트의 형태로 노출될 수 있다.

시간 및 상태

: 프로그램 동작과정에서 시간적 개념을 포함한 개념(프로세스 등)이나 시스템 상태에 대한 정보와 관련된 취약점

  • 파일 등의 공유 자원을 여러 스레드가 접근해 사용할 경우, 동기화를 사용해 한번에 하나의 스레드만 접근가능하도록 할 것. 다중 스레드와 공유 변수 사용시 thread safe 함수만 사용, java의 경우 synchronized 사용
  • 재귀 종료 잘 되도록 할 것

에러 처리

  • 패스워드는 강하게 요구할 것. 패스워드 복잡도를 검증할 것
  • 오류 메시지를 통한 정보 노출. e.printStackStrace()를 출력하지 말것. 에러 메시지는 정해진 사용자에게 유용한 최소한의 정보만 포함하도록 할 것.

코드 품질: 코드가 복잡하면 안전성을 위협할 취약점들이 있을 수도 있다

  • signed int를 unsigned int로 변환하면 음수가 큰 양수가 되는데 이 값이 배열의 인덱스로 사용되면 정수 오버플로우가 일어나 프로그램이 오동작할 수도 있음. e.g) C의 len() 함수에서 문자열이 null일 경우 -1를 반환하는데 이걸 unsigned int로 변환하면 10억단위가 된다. 버퍼 오버플로우 취약점을 가질수도 있다. null이면 -1대신 0을 반환하게 한다.
  • int를 char로 변환할 때 4바이트->1바이트니 크기 확인하고 변환
  • database connection 중 예외가 발생되어도 finally를 사용해 할당받은 자원(Jdbc 커넥션)을 반환(close)할 것

캡슐화

  • 제거되지 않고 남은 디버거 코드. System.err.print("디버그코드")
  • 민감한 데이터를 가진 내부클래스 사용: 내부 클래스는 컴파일 과정에서 패키지 수준의 접근성으로 바뀐다. 내부클래스를 static 선언해 외부클래스의 private 필드에 접근하지 못하게 한다.
  • 변경하면 안되는 public 멤버 변수는 반드시 final 키워드로 선언한다.
  • private으로 선언된 배열을 public 메서드로 반환하면 외부에서 배열의 reference를 알 수 있다. public 메서드 안에서 private 배열의 카피를 만들어서 그것을 반환하도록 작성하면 private 배열의 수정을 막을 수 있음
  • 시스템 데이터 정보 누출: 예외 발생시 e.getMessage()같은 것 출력하지말고 IOE exception occured 와 같은 대략적인 정보만 제공.

그 외 사용 가능한 방법들

  • 동적 SQL: 조건에 따라 쿼리가 다를 경우 프로그램 실행시 전체 쿼리가 만들여서 db에 요청하는 sql
  • 상호배제(mutex): 동시 프로그래밍에서 공유 불가능한 자원의 동시 사용을 막기위해 사용되는 알고리즘
  • DAP(Lightweight Directory Access Protocol): TCP/IP 위에서 디렉터리 서비스를 조회하고 수정하는 응용 프로토콜