차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

양쪽 이전 판이전 판
다음 판
이전 판
guide:java_개발_보안_가이드 [2013/12/24 02:32] 121.140.124.172guide:java_개발_보안_가이드 [2024/04/04 05:12] (현재) – 바깥 편집 127.0.0.1
줄 2609: 줄 2609:
 \\ \\
 [2] OWASP Top 10 2010 - (OWASP 2010) A7 Insecure Cryptographic Storage [2] OWASP Top 10 2010 - (OWASP 2010) A7 Insecure Cryptographic Storage
 +==== 12. 민감한 데이터의 암호화 실패(Missing Encryption of Sensitive Data) ====
  
 +=== 가. 정의 ===
 +중요한 민감한 데이터를 디스크에 저장하거나 외부 전송시, SW가 해당 데이터를 암호화하지 않을 경우 민감한 데이터가 노출될 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +계좌번호, 신용카드번호, 패스워드 정보가 디스크에 출력 시 단반향 암호화 알고리즘을 사용하고, 해쉬 알고리즘은 SHA-256을 사용한다.
 +\\
 +SW 설계 시 민감한 데이터와 일반 데이터를 가능한 분리하도록 한다.
 +\\
 +민감한 데이터가 네트워크를 통해 전송될 때, SSL 또는 HTTPS 등과 같은 Secure Channel을 사용한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: String username = request.getParameter("username");
 +2: String password = request.getParameter("password");
 +3: PreparedStatement p=null;
 +4: try {
 +5: ......
 +6: if (username==nill || password==null
 +7: || !isAuthenticatedUser(usename, password)) {
 +8: throw new MyException("인증 에러");
 +9: }
 +10: p = conn.prepareStatement(" INSERT INTO employees VALUES(?,?)" );
 +11: p.setString(1,username);
 +12: p.setString(2,password);
 +13: p.execute();
 +14: ......
 +15: }
 +</code>
 +인증을 통과한 사용자의 패스워드 정보가 평문으로 DB에 저장된다.
 +<code | 안전한 코드 예제>
 +1: String username = request.getParameter("username");
 +2: String password = request.getParameter("password");
 +3: PreparedStatement p=null;
 +4: try {
 +5: ......
 +6: if (username==nill || password==null
 +7: || !isAuthenticatedUser(usename, password)) {
 +8: throw new MyException("인증 에러");
 +9: }
 +10: MessageDigest md = MessageDigest.getInstance("SHA-256");
 +11: md.reset();
 +12: ......
 +13: // 패스워드는 해쉬 함수를 이용하여 DB에 저장한다.
 +14: password =md.digest(password.getBytes());
 +15: p = conn.preparedStatement(" INSERT INTO employees VALUES(?,?)" );
 +16: p.setString(1,username);
 +17: p.setString(2,password);
 +18: p.execute();
 +19: ......
 +20: }
 +</code>
 +패스워드 등 중요 데이터를 해쉬값으로 변환하여 저장한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-311 민감한 데이터의 암호화 실패 - http://cwe.mitre.org/data/definitions/311.html
 +\\
 +CWE-312 민감한 정보 평문저장 - http://cwe.mitre.org/data/definitions/312.html
 +\\
 +CWE-319 민감한 정보 평문전송 - http://cwe.mitre.org/data/definitions/319.html
 +\\
 +CWE-614 HTTPS 세션내에 보안속성없는 민감한 쿠키 - http://cwe.mitre.org/data/definitions/614.html
 +\\
 +[2] CWE/SANS Top 25 Most Dangerous Software Errors, http://cwe.mitre.org/top25/
 +==== 13. 기밀 정보의 단순한 텍스트 전송(Cleartext Transmission of Sensitive Information) ====
 +
 +=== 가. 정의 ===
 +SW가 보안과 관련된 민감한 데이터를 명백한 텍스트의 형태로 통신 채널을 통해서 보내는 경우, 인증받지 않은 주체에 의해서 스니핑이 일어날 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +민감한 정보를 통신 채널을 통하여 내보낼 때는 반드시 암호화 과정을 거쳐야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: String getPassword() {
 +3: return "secret";
 +4: }
 +5:
 +6: void foo() {
 +7: try {
 +8: Socket socket = new Socket("taranis", 4444);
 +9: PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
 +10: String password = getPassword();
 +11: out.write(password);
 +12: } catch (FileNotFoundException e) {
 +13: ……
 +14: }
 +</code>
 +속성 파일에서 읽어들인 패스워드(Plain text)를 네트워크를 통하여 서버에 전송하고 있다.
 +\\
 +이 경우 패킷 스니핑을 통하여 패스워드가 노출될 수 있다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: String getPassword() {
 +3: return "secret_password";
 +4: }
 +5:
 +6: void foo() {
 +7: try {
 +8: Socket socket = new Socket("taranis", 4444);
 +9: PrintStream out = new PrintStream(socket.getOutputStream(), true);
 +10: Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding" );
 +11: String password = getPassword();
 +12: byte[] encryptedStr = c.update(password.getBytes());
 +13: out.write(encryptedStr, 0, encryptedStr.length);
 +14: } catch (FileNotFoundException e) {
 +15: ……
 +16: }
 +</code>
 +패스워드를 네트워크를 통하여 서버에 전송하기 전에 최소한 128비트 길이의 키를 이용하여 암호화하는 것이 바람직하다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-319 민감한 정보의 단순한 텍스트 전송 - http://cwe.mitre.org/data/definitions/319.html
 +\\
 +CWE-311 민감한 데이터의 암호화 실패 - http://cwe.mitre.org/data/definitions/311.html
 +\\
 +[2] OWASP Top 10 2007 - (OWASP 2007) A9 Insecure Communications
 +==== 14. 하드코드된 암호화키 사용(Use of Hard-coded Cryptographic Key) ====
 +
 +=== 가. 정의 ===
 +코드 내부에 하드코드된 암호화키를 사용하여 암호화를 수행하면 암호화된 정보가 유출될 가능성이 높아진다. 많은 SW 개발자들이 코드 내부의 고정된 패스워드의 해쉬를 계산하여 저장하는 것이 패스워드를 악의적인 공격자로부터 보호할 수 있다고 믿고 있다. 그러나 많은 해쉬 함수들이 역계산이 가능하며, 적어도 brute-force 공격에는 취약하다는 것을 고려해야만 한다.
 +=== 나. 안전한 코딩기법 ===
 +암호화되었더라도 패스워드를 상수의 형태로 프로그램 내부에 저장하여 사용하면 안된다.
 +\\
 +대칭형 알고리즘으로 AES, ARIA, SEED, 3DES 등의 사용이 권고되며, 비대칭형 알고리즘으로 RSA 사용시 키는 1024이상을 사용한다. 해쉬 함수로 MD4, MD5, SHA1은 사용하지 말아야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: private Connection con;
 +3:
 +4: public String encryptString (String usr) {
 +5: Stringc seed = "68af404b513073584c4b6f22b6c63e6b" ;
 +6:
 +7: try {
 +8: // 상수로 정의된 암호화키를 이용하여 encrypt를 수행한다.
 +9: SecretKeySpec skeySpec = new SecretKeySpec(seed.getBytes(), "AES");
 +10:
 +11: // 해당 암호화키 기반의 암호화 또는 복호화 업무 수행
 +12: ..
 +13: } catch (SQLException e) {
 +14: ……
 +15: }
 +16: return con;
 +17: }
 +18: }
 +</code>
 +암호화에 사용되는 키를 상수의 형태로 코드 내부에서 사용하는 것은 프로그램 소스가 노출되는 경우 암호화 키도 동시에 노출되는 취약점을 가지게 된다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: private Connection con;
 +3:
 +4: public String encryptString (String usr) {
 +5: Stringc seed = null;
 +6:
 +7: try {
 +8: // 암호화 키를 외부환경에서 읽음.
 +9: seed = getPassword("./password.ini");
 +10: // 암호화된 암호화 키를 복호화함.
 +11: seed = decrypt(seed);
 +12: // 상수로 정의된 암호화키를 이용하여 encrypt를 수행한다.
 +13: // use key coss2
 +14: SecretKeySpec skeySpec = new SecretKeySpec(seed.getBytes(), "AES");
 +15:
 +16: // 해당 암호화키 기반의 암호화 또는 복호화 업무 수행
 +17: ..
 +18: } catch (SQLException e) {
 +19: ……
 +20: }
 +21: return con;
 +22: }
 +23: }
 +24:
 +</code>
 +암호화된 패스워드를 복호화하기 위하여 사용되는 암호화 키도 코드 내부에 상수형태로 정의해서 사용하면 안된다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-321 하드코드된 암호화키 사용 - http://cwe.mitre.org/data/definitions/321.html
 +==== 15. 취약한 암호화: 적절하지 못한 RSA 패딩(Weak Encryption: Inadequate RSA Padding) ====
 +
 +=== 가. 정의 ===
 +OAEP 패딩을 사용하지 않고 RSA 알고리즘을 이용하는 것은 위험하다. RSA 알고리즘은 실제 사용시 패딩 기법과 함께 사용하는 것이 일반적이다. 패딩 기법을 사용함으로써 패딩이 없는 RSA 알고리즘의 취약점을 이용하는 공격을 막을 수 있게 된다.
 +=== 나. 안전한 코딩기법 ===
 +RSA 알고리즘 사용시 패딩없이 사용("RSA/NONE/NoPadding")하지 말고, 암호화 알고리즘에 적합한 패딩과 함께 사용해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public Cipher getCipher() {
 +3: Cipher rsa = null;
 +4:
 +5: try {
 +6: // RSA 사용시 NoPadding 사용
 +7: rsa = javax.crypto.Cipher.getInstance("RSA/NONE/NoPadding");
 +8: } catch (java.security.NoSuchAlgorithmException e) { …… }
 +9: return rsa;
 +10: }
 +</code>
 +위 예제는 충분한 패딩없이 RSA 알고리즘을 사용하여 프로그램에 취약점하게 만드는 경우이다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public Cipher getCipher() {
 +3: Cipher rsa = null;
 +4:
 +5: try {
 +6: /* 이 프로그램은 충분한 padding의 사용없이 RSA를 사용한다. */
 +7: rsa = javax.crypto.Cipher.getInstance("RSA/CBC/PKCS5Padding");
 +8: } catch (java.security.NoSuchAlgorithmException e) { …… }
 +9: return rsa;
 +10: }
 +</code>
 +사용하는 알고리즘에 따라 알려져 있는 적절한 패딩방식을 사용해야 한다. 예를 들어 RSA알고리즘을 사용하는 경우에는 PKCS1 Padding 방식이나 PKCS5 Padding 방식을 사용하는 것이 바람직하다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-325 필수 암호화 단계 누락 - http://cwe.mitre.org/data/definitions/325.html
 +\\
 +[2] OWASP Top 10 2010 - (OWASP 2010) A7 Insecure Cryptographic Storage
 +==== 16. 취약한 암호화 해쉬함수: 하드코드된 솔트(Weak Cryptographic Hash: Hardcoded Salt) ====
 +
 +=== 가. 정의 ===
 +코드에 고정된 솔트값을 사용하는 것은 프로젝트의 모든 개발자가 그 값을 볼 수 있으며,추후 수정이 매우 어렵다는 점에서 시스템의 취약점으로 작용할 수 있다. 만약 공격자가 솔트값을 알게 된다면, 해당 응용프로그램의 rainbow 테이블을 작성하여 해쉬 결과값을 역으로 계산할 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +Salt(혹은 nonce)값으로는 예측하기 어려운 난수를 사용하며, 특정한 값의 재사용은 금지해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public byte[] encrypt(byte[] msg) {
 +3: // 소스가 노출되었을 때 사용자가 값을 알수 있다.
 +4: final byte badsalt = (byte) 100;
 +5: byte[] rslt = null;
 +6:
 +7: try {
 +8: MessageDigest md = MessageDigest.getInstance("SHA-256");
 +9: // Salt 값을 상수로 받는다.
 +10: md.update(badsalt);
 +11: rslt = md.digest(msg);
 +12: } catch (NoSuchAlgorithmException e) {
 +13: System.out.println("Exception: " + e);
 +14: }
 +15: return rslt;
 +16: }
 +</code>
 +위 예제는 암호화된 해쉬함수를 사용할 때, 상수로 정의된 salt를 사용함으로써 취약점을 야기하는 경우이다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public byte[] encrypt(byte[] msg) {
 +3: byte[] rslt = null;
 +4:
 +5: try {
 +6: SecureRandom prng = SecureRandom.getInstance("SHA256PRNG");
 +7: String randomNum = new Integer( prng.nextInt() ).toString();
 +8: MessageDigest md = MessageDigest.getInstance("SHA-256");
 +9:
 +10: // 랜덤 함수 등을 사용하여 임의의 숫자를 생성해야 한다.
 +11: md.update(randomNum.getBytes());
 +12: rslt = md.digest(msg);
 +13: } catch (NoSuchAlgorithmException e) {
 +14: System.out.println("Exception: " + e);
 +15: }
 +16: return rslt;
 +17: }
 +18: }
 +</code>
 +Salt(혹은 nonce)값으로는 예측하기 어려운 난수를 사용해야 하므로, 예측이 어려운 salt 값을 생성하는 로직을 별도로 구현하여 사용하여야 한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-326 부적당한 암호화 길이 - http://cwe.mitre.org/data/definitions/326.html
 +\\
 +[2] OWASP Top 10 2010 - (OWASP 2010) A7 Insecure Cryptographic Storage
 +==== 17. 취약한 암호화 알고리즘의 사용(Use of a Broken or Riscky Cryptographic Algorithm) ====
 +
 +=== 가. 정의 ===
 +보안적으로 취약하거나 위험한 암호화 알고리즘을 사용해서는 안된다. 표준화되지 암호화 알고리즘을 사용하는 것은 공격자가 알고리즘을 분석하여 무력화시킬 수 있는 가능성을 높일 수도 있다. 몇몇 오래된 암호화 알고리즘의 경우는 컴퓨터의 성능이 향상됨에 따라 취약해지기도 해서, 예전에는 해독하는데 몇 십억년이 걸리던 알고리즘이 며칠이나 몇 시간내에 해독되기도 한다. RC2, RC4, RC5, RC6, MD4, MD5, SHA1, DES 알고리즘이 여기에 해당된다.
 +=== 나. 안전한 코딩기법 ===
 +AES처럼 보다 강력한 암호화 알고리즘을 사용하는 것이 바람직하다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public byte[] encrypt(byte[] msg, Key k) {
 +3: byte[] rslt = null;
 +4:
 +5: try {
 +6: // DES등의 낮은 보안수준의 알고리즘을 사용하는 것은 안전하지 않다.
 +7: Cipher c = Cipher.getInstance("DES");
 +8: c.init(Cipher.ENCRYPT_MODE, k);
 +9: rslt = c.update(msg);
 +10: } catch (InvalidKeyException e) {
 +11: ……
 +12: }
 +13: return rslt;
 +14: }
 +15: }
 +</code>
 +암호화 알고리즘 중에서 DES 알고리즘을 사용하는 것은 안전하지 않다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public byte[] encrypt(byte[] msg, Key k) {
 +3: byte[] rslt = null;
 +4:
 +5: try {
 +6: // 낮은 보안수준의 DES 알고리즘을 높은 보안수준의 AES 알고리즘으로 대체한다.
 +7: Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
 +8: c.init(Cipher.ENCRYPT_MODE, k);
 +9: rslt = c.update(msg);
 +10: } catch (InvalidKeyException e) {
 +11: ……
 +12: }
 +13: return rslt;
 +14: }
 +15: }
 +</code>
 +취약하다고 알려진 알고리즘 대신 AES 알고리즘을 최소한 128비트 길이의 키를 이용하여 사용하는 것이 바람직하다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-327 취약한 암호화 알고리즘의 사용 - http://cwe.mitre.org/data/definitions/327.html
 +\\
 +[2] OWASP Top 10 2010 - (OWASP 2010) A7 Insecure Cryptographic Storage
 +\\
 +[3] SANS Top 25 2010 - (SANS 2010) Porus Defense - CWE ID 327 Use of a Broken or Risky Cryptographic Algorithm
 +\\
 +[4] Bruce Schneier. "Applied Cryptography". John Wiley &Sons. 1996
 +==== 18. 적절하지 않은 난수값의 사용(Use of Insufficiently Random Values) ====
 +
 +=== 가. 정의 ===
 +예측 가능한 난수를 사용하는 것은 시스템에 취약점을 야기시킨다. 예측 불가능한 숫자가 필요한 상황에서 예측 가능한 난수를 사용한다면, 공격자는 SW에서 생성되는 다음 숫자를 예상하여 시스템을 공격하는 것이 가능하다.
 +=== 나. 안전한 코딩기법 ===
 +난수발생기에서 seed를 사용하는 경우에는 예측하기 어려운 방법으로 변경하여 사용하는 것이 바람직하다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public double roledice() {
 +3: return Math.random();
 +4: }
 +5: }
 +</code>
 +java.lang.Math 클래스의 random() 메소드는 seed를 재설정할 수 없기 때문에 위험하다.
 +<code | 안전한 코드 예제>
 +1: import java.util.Random;
 +2: import java.util.Date;
 +3: ……
 +4: public int roledice() {
 +5: Random r = new Random();
 +6: // setSeed() 메소드를 사용해서 r을 예측 불가능한 long타입으로 설정한다.
 +7: r.setSeed(new Date().getTime());
 +8: // 난수 생성
 +9: return (r.nextInt()%6) + 1;
 +10: }
 +11: }
 +</code>
 +java.util.Random 클래스는 seed를 재설정하지 않아도 매번 다른 난수를 생성한다. 따라서 Random 클래스를 사용하는 것이 보다 안전하다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-330 적절하지 않은 난수값의 사용 - http://cwe.mitre.org/data/definitions/330.html
 +\\
 +[2] SANS Top 25 2009 - (SANS 2009) Porus Defense - CWE ID 330 Use of Insufficiently Random Values
 +\\
 +[3] J. Viega andG. McGraw. "Building Secure Software: HowtoAvoid Security Problems the RightWay". 2002
 +==== 19. 패스워드 관리: 리다이렉트시 패스워드(Password Management: Password in Redirect) ====
 +
 +=== 가. 정의 ===
 +HTTP 리다이렉트는 웹브라우저를 통해 HTTP GET 명령어를 발생시킨다. 이 경우 주소창에 매개변수의 형태로 전송내용이 노출되므로, 패스워드를 이 방법을 통해서 보내는 것은 위험하다. 이와 함께 웹서버가 이 행위를 주소와 함께 로그에 남기고, 웹프록시는 이 페이지를 캐쉬하므로, 사용자가 전송한 패스워드가 시스템의 많은 부분에 남게 된다.
 +=== 나. 안전한 코딩기법 ===
 +자바 Servelet에서 sendRedirect 메소드를 통해서는 패스워드 등 보안에 민감한 보내서는 안된다. 다른 페이지로 보안에 민감한 정보를 보낼 때는 GET 방식이 아닌 POST 방식으로 파라미터를 전달해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public void redirect(ServletRequest r, HttpServletResponse response)
 +3: throws IOException {
 +4: String usr = r.getParameter("username");
 +5: String pass = r.getParameter("password");
 +6:
 +7: // HTTP 리다이렉트는 웹브라우저는 통해 HTTP GET request를 발생시킨다.
 +8: response.sendRedirect("j_security_check?j_username=" + usr + "&j_password=" + pass);
 +9: }
 +</code>
 +위 예제는 HTTP 요청(Request)을 GET 방식으로 재전송함으로써 프로그램울 취약하게 만드는 경우이다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public void redirect(HttpServletRequest request, HttpServletResponse response)
 +3: throws IOException {
 +4: request.getSession().invalidate();
 +5: String usr = request.getParameter("username");
 +6: String pass = request.getParameter("password");
 +7:
 +8: // 패스워드의 유효성을 점검한다.
 +9: if ( usr == null || "".equals(usr) || pass == null || "".equals(pass) ) return;
 +10: if ( !pass.matches("") && pass.indexOf("@!#") > 4 && pass.length() > 8 ) {
 +11: ……
 +12: }
 +13: // POST 방식으로 페이지를 넘겨야 한다.
 +14: String send = "j_security_check?j_username=" + usr + "&j_password=" + pass;
 +15: response.encodeRedirectURL(send);
 +16: }
 +</code>
 +다른 페이지로 보안에 민감한 정보를 보낼 때는 GET 방식이 아닌 POST 방식으로 파라미터를 전달해야 한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-359 개인정보 침해 - http://cwe.mitre.org/data/definitions/359.html
 +\\
 +[2] OWASP Top 10 2010 - (OWASP 2010) A7 Insecure Cryptographic Storage
 +==== 20. 취약한 패스워드 요구조건(Weak Password Requirements) ====
 +
 +=== 가. 정의 ===
 +사용자에게 강한 패스워드를 요구하지 않으면, 결국 공격자가 사용자 계정을 뚫기 쉽게 만
 +들며, 사용자 계정을 보호하기 힘들다.
 +
 +=== 나. 안전한 코딩기법 ===
 +패스워드에 대한 검증을 통해 보안성이 높은 문자열을 입력하도록 유도한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: public void doPost(HttpServletRequest request, HttpServletResponse response)
 +2: throws IOException, ServletException {
 +3:
 +4: try {
 +5: String url = "DBServer";
 +6: String usr = "Scott";
 +7:
 +8: // passwd에 대한 검증이 없음
 +9: String passwd = request.getParameter("passwd" );
 +10: Connection con = DriverManager.getConnection(url, usr, passwd);
 +11:
 +12: con.close();
 +13: } catch (SQLException e) {
 +14: System.err.println("...");
 +15: }
 +16: }
 +</code>
 +신뢰할 수 없는 외부입력으로부터 할당된 변수(passwd)가 검증 과정없이 패스워드로 사용되는 문장이다.
 +<code | 안전한 코드 예제>
 +1: private static final String CONNECT_STRING = "jdbc:ocl:orcl";
 +2:
 +3: public void doPost(HttpServletRequest request, HttpServletResponse response)
 +4: throws IOException, ServletException {
 +5: try {
 +6: request.getSession().invalidate();
 +7: String passwd = request.getParameter("passwd" );
 +8:
 +9: // passwd에 대한 검증
 +10: if (passwd == null || " " .equals(passwd)) return;
 +11:
 +12: // 패스워드 조합 규칙을 검사한 후, 위배될 경우 재입력을 요구
 +13: if (Password.validate(passwd) == false) return;
 +14:
 +15: InitialContext ctx = new InitialContext();
 +16: DataSource datasource = (DataSource) ctx.lookup(CONNECT_STRING);
 +17: Connection con = datasource.getConnection();
 +18:
 +19: con.close();
 +20: } catch (SQLException e) {
 +21: System.err.println("...");
 +22: } catch (NamingException e) {
 +23: System.err.println("...");
 +24: }
 +25: }
 +</code>
 +패스워드(passwd) 조합 규칙(예: 세가지 종류 이상의 문자구성으로 8자리 이상의 길이로 구성된 문자열)을 검사한 후, 위배될 경우 다른 패스워드를 사용하도록 유도한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-521 취약한 패스워드 요구조건 - http://cwe.mitre.org/data/definitions/521.html
 +\\
 +[2] OWASP Top 10 2010 A3 Broken Authentication Session Management
 +\\
 +http://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project
 +==== 21. 쿠키보안: 영속적인 쿠키(Cookie Security: Persistent Cookie) ====
 +
 +=== 가. 정의 ===
 +보안상 민감한 데이터를 영속적인 쿠키에 저장하는 것은 시스템 보안을 취약하게 만든다.
 +\\
 +대부분의 웹 응용프로그램에서 쿠키는 메모리에 상주하며, 브라우저의 실행이 종료되면 사라진다. 프로그래머가 원하는 경우, 브라우저 세션에 관계없이 계속적으로 지속되도록 설정할 수 있으며, 이것은 디스크에 기록되고 다음 브라우저 세션이 시작되었을 때 메모리에 로드된다. 만약 개인 정보 등의 이런 형태의 영속적인 쿠키에 저장된다면, 공격자는 쿠키에 접근할 수 있는 보다 많은 기회를 가지게 되며, 이는 시스템을 취약하게 만든다.
 +=== 나. 안전한 코딩기법 ===
 +쿠키의 만료시간은 세션이 지속되는 시간과 관련하여 최소한으로 설정해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public void makeCookie(ServletRequest request) {
 +3: String maxAge = request.getParameter("maxAge");
 +4: if (maxAge.matches("[0-9]+")) {
 +5: String sessionID = request.getParameter("sesionID");
 +6: if (sessionID.matches("[A-Z=0-9a-z]+")) {
 +7: Cookie c = new Cookie("sessionID", sessionID);
 +8: // 외부 입력이 쿠키 유효시한 설정에 그대로 사용 되었다.
 +9: c.setMaxAge(Integer.parseInt(maxAge));
 +10: }
 +11: ……
 +12: }
 +</code>
 +javax.servlet.http.Cookie.setMaxAge 메소드 호출에 외부의 입력이 쿠키의 유효시한 설정에 그대로 사용되어 프로그램의 취약점을 야기하는 경우이다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public void makeCookie(ServletRequest request) {
 +3: String maxAge = request.getParameter("maxAge");
 +4:
 +5: if (maxAge == null || "".equals(maxAge)) return;
 +6: if (maxAge.matches("[0-9]+")) {
 +7: String sessionID = request.getParameter("sesionID");
 +8: if (sessionID == null || "".equals(sessionID)) return;
 +9: if (sessionID.matches("[A-Z=0-9a-z]+")) {
 +10: Cookie c = new Cookie("sessionID", sessionID);
 +11: // 쿠키 유효시한의 최대값을 설정해서, 그 아래 값으로 조정한다.
 +12: int t = Integer.parseInt(maxAge);
 +13: if (t > 3600) {
 +14: t = 3600;
 +15: }
 +16: c.setMaxAge(t);
 +17: }
 +18: ……
 +19: }
 +</code>
 +사용자가 요청한 값으로 쿠키의 유효시한을 설정하기 전에 사용자 요청을 검증하는 로직을 별도로 작성하여, 메소드 호출 전에 호출한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-539 지속성 쿠키를 통한 정보 누출 - http://cwe.mitre.org/data/definitions/539.html
 +\\
 +[2] OWASP Top 10 2010 - (OWASP 2010) A7 Insecure Cryptographic Storage
 +==== 22. 같은 포트번호로의 다중 연결(Multiple Binds to the Same Port) ====
 +
 +=== 가. 정의 ===
 +하나의 포트에 다수의 소켓이 연결되는 것을 허용하는 경우, 주어진 포트에서 수행되는 서비스로 전달되는 패킷이 도난당하거나 혹은 공격자가 서비스를 도용할 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +패킷 스니핑 공격에 노출될 수 있으므로 UDP 프로토콜에 하나의 포트번호에 여러 개의 서버측 소켓을 바인딩해서는 안된다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: final int INPORT = 1711;
 +3: void foo () {
 +4: try {
 +5: java.net.DatagramSocket socket = new java.net.DatagramSocket(INPORT);
 +6: socket.setReuseAddress(true);
 +7: } catch (SocketException e) { …… }
 +8: }
 +9: }
 +</code>
 +하나의 포트 번호에 여러 개의 소켓이 바인딩되는 것을 허용함으로써 패킷 스니핑 공격에 노출될 수 있다
 +<code | 안전한 코드 예제>
 +1: ……
 +2: final int INPORT = 1711;
 +3: void foo () {
 +4: try {
 +5: java.net.DatagramSocket socket = new java.net.DatagramSocket(INPORT);
 +6: socket.setReuseAddress(false);
 +7: } catch (SocketException e) { …… }
 +8: }
 +</code>
 +프로토콜에 상관없이 포트의 재사용 옵션을 설정하지 않아야 한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-605 같은 포트번호로의 다중 연결 - http://cwe.mitre.org/data/definitions/605.html
 +==== 23. HTTPS 세션내에 보안속성없는 민감한 쿠키(Sensitive Cookie in HTTPS Session without Secure Attribute) ====
 +
 +=== 가. 정의 ===
 +HTTPS로만 서비스하는 경우 모든 정보가 암호화 되어 안전하게 전송된다고 생각한다. 그러나 보안에 민감한 데이터를 브라우저 쿠키에 저장할 때 보안 속성을 세팅하지 않으면 공격자에게 단순한 텍스트의 형태로 노출될 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +HTTPS로만 서비스하는 경우 브라우저 쿠키에 데이터를 저장할 때 반드시 Cookie 객체의 setSecure(true) 메소드를 호출하여야 한다.
 +\\
 +주의 : 한 사이트(도메인)에서 HTTP나 HTTP와 HTTPS를 함께 사용하는 경우 setSecure 메소드를 호출하면 브라우저 쿠키의 데이터가 서버에 전송되지 않아 장애가 발생할 수 있다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: private final String ACCOUNT_ID = "account";
 +3:
 +4: public void setupCookies(ServletRequest r, HttpServletResponse response) {
 +5: String acctID = r.getParameter("accountID");
 +6: // 보안속성 설정되지 않은 쿠키
 +7: Cookie c = new Cookie(ACCOUNT_ID, acctID);
 +8: response.addCookie(c);
 +9: }
 +</code>
 +HTTPS로만 서비스하는 경우 민감한 정보를 가진 쿠키를 전송하는 과정에서, 보안 속성을 설정하지 않으면 공격자에게 정보가 노출될 수 있다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: private final String ACCOUNT_ID = "account";
 +3:
 +4: public void setupCookies(ServletRequest r, HttpServletResponse response) {
 +5: String acctID = r.getParameter("accountID");
 +6: // 계정 유효성 점검
 +7: if (acctID == null || "".equals(acctID)) return;
 +8: String filtered_ID = acctID.replaceAll("\r", "");
 +9:
 +10: Cookie c = new Cookie(ACCOUNT_ID, filtered_ID);
 +11: // 민감한 정보를 가진 쿠키를 전송할때에는 보안 속성을 설정하여야 한다.
 +12: c.setSecure(true);
 +13: response.addCookie(c);
 +14: }
 +</code>
 +HTTPS로만 서비스하는 경우 민감한 정보를 가진 쿠키를 사용할 경우에는 반드시 Cookie 객체의 setSecure(true)를 호출하여야 한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-614 HTTPS 세션내에 보안속성없는 민감한 쿠키 - http://cwe.mitre.org/data/definitions/614.html
 +\\
 +[2] OWASP Top 10 2010 - (OWASP 2010) A9 Insufficient Transport Layer Protection
 +==== 24. 주석문 안에 포함된 패스워드(Password in Comment) ====
 +
 +=== 가. 정의 ===
 +패스워드를 주석문에 넣어두면 시스템 보안이 훼손될 수 있다. SW 개발자가 편의를 위해서 주석문에 패스워드를 적어둔 경우, SW가 완성된 후에는 그것을 제거하는 것이 매우 어렵게 된다. 또한 공격자가 소스코드에 접근할 수 있거나, 혹은 역어셈블러를 사용하여 주석문의 내용을 볼 수 있다면 아주 쉽게 시스템에 침입할 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +개발시에 주석 부분에 남겨놓은 패스워드 및 보안에 관련된 내용은 개발이 끝난 후에는 반드시 제거해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: //Password for administrator is " tiger."<-주석에 패스워드가 적혀있다.
 +3: public boolean DBConnect() {
 +4: String url = "DBServer";
 +5: String password = "tiger";
 +6: Connection con = null;
 +7:
 +8: try {
 +9: con = DriverManager.getConnection(url, "scott", password);
 +10: } catch (SQLException e) {
 +11: ……
 +12: }
 +</code>
 +위 예제는 디버깅 등의 목적으로 사용자 이름과 패스워드를 주석문 안에 서술하고 제대로 지우지 않아서 취약점이 발생한 경우이다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: //디버깅 등의 용도로 소스 주석에 적어놓은 패스워드는 삭제해야 한다.
 +3: public Connection DBConnect(String id, String password) {
 +4: String url = "DBServer";
 +5: Connection conn = null;
 +6:
 +7: try {
 +8: String CONNECT_STRING = url + ":" + id + ":" + password;
 +9: InitialContext ctx = new InitialContext();
 +10: DataSource datasource = (DataSource) ctx.lookup(CONNECT_STRING);
 +11: conn = datasource.getConnection();
 +12: } catch (SQLException e) { …… }
 +13: return conn;
 +14: }
 +</code>
 +프로그램 개발시에 주석문 등에 남겨놓은 사용자 계정이나 패스워드 등의 정보는 개발 완료시에 확실하게 삭제하여야 한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-615 주석을 통한 정보 누출 - http://cwe.mitre.org/data/definitions/615.html
 +\\
 +[2] OWASP Top 10 2010 - (OWASP 2010) A7 Insecure Cryptographic Storage
 +\\
 +[3] Web Application Security Consortium 24 + 2 - (WASC 24 + 2) Information Leakage
 +==== 25. 중요한 자원에 대한 잘못된 권한허용(Incorrect Permission Assignment for Critical Resource) ====
 +
 +=== 가. 정의 ===
 +SW가 중요한 보안관련 자원에 대하여 읽기 또는 수정하기 권한을 의도하지 않게 허가할 경우, 권한을 갖지 않은 사용자가 해당자원을 사용하게 된다.
 +=== 나. 안전한 코딩기법 ===
 +설정파일, 실행파일, 라이브러리 등은 SW 관리자에 의해서만 읽고 쓰기가 가능하도록 설정한다.
 +\\
 +설정파일과 같이 중요한 자원을 사용하는 경우, 허가받지 않은 사용자가 중요한 자원에 접근 가능한지 검사한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: // 파일 권한 : rw-rw-rw-, 디렉터리 권한 : rwxrwxrwx
 +2: String cmd = "umask 0" ;
 +3: File file = new File("/home/report/report.txt");
 +4: ...
 +5: Runtime.getRuntime().exec(cmd);
 +</code>
 +JAVA 런타임 API를 이용하여 파일을 생성할 때 가장 많은 권한을 허가하는 형태로 umask를 사용하고 있어, 모든 사용자가 읽기/쓰기 권한을 갖게 된다.
 +<code | 안전한 코드 예제>
 +1: // 파일 권한 : rw-------, 디렉터리 권한 : rwx------
 +2: String cmd = "umask 77" ;
 +3: File file = new File("/home/report/report.txt");
 +4: ...
 +5: Runtime.getRuntime().exec(cmd);
 +</code>
 +파일에 대한 설정을 가장 제한이 많도록, 즉 사용자를 제외하고는 읽기/쓰기가 가능하지 않도록 umask를 설정하는 것이 필요하다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-732 중요한 자원에 대한 잘못된 권한허용 - http://cwe.mitre.org/data/definitions/732.html
 +\\
 +CWE-276 부정확한 초기설정 허가 - http://cwe.mitre.org/data/definitions/276.html
 +\\
 +CWE-277 불안전한 계승된 허가 - http://cwe.mitre.org/data/definitions/277.html
 +\\
 +CWE-278 불안전한 보존 계승된 허가 - http://cwe.mitre.org/data/definitions/278.html
 +\\
 +CWE-279 불안전한 실행-할당 허가 - http://cwe.mitre.org/data/definitions/279.html
 +\\
 +CWE-281 부적절한 허가보존 - http://cwe.mitre.org/data/definitions/281.html
 +\\
 +CWE-285 부적절한 인가 - http://cwe.mitre.org/data/definitions/281.html
 +\\
 +[2] CWE/SANS Top 25 Most Dangerous Software Errors, http://cwe.mitre.org/top25/
 +
 +===== 4절. 시간 및 상태 =====
 +
 +==== 1. 경쟁 조건: 정적 데이터베이스 연결(Race Condition: Static Database Connection(dbconn)) ====
 +
 +=== 가. 정의 ===
 +정적 필드에 저장된 DB 연결은 스레드 사이에 공유되지만, 트랜잭션 리소스 객체는 동시에 하나의 트랜잭션에만 연결될 수 있어서 오류가 발생할 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +정적 필드에 저장된 DB 연결은 스레드 사이에 공유되어 경쟁 조건(race condition)을 유발할 수 있으므로 DB 연결을 정적 필드에 저장하면 안 된다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: // DB 연결 객체가 정적 필드에 저장되어 에러를 유발할 수 있다.
 +3: private static Connection conn;
 +4: private static final String CONNECT_STRING = "jdbc:ocl:orcl";
 +5:
 +6: public Connection dbConnection(String url, String user, String pw) {
 +7: InitialContext ctx;
 +8: try {
 +9: ctx = new InitialContext();
 +10: DataSource datasource = (DataSource) ctx.lookup(CONNECT_STRING);
 +11: conn = datasource.getConnection();
 +12: } catch (NamingException e) { …… }
 +13: return conn;
 +14: }
 +15
 +</code>
 +위 예제와 같이 DB 연결 객체를 정적 필드에 저장하면 경쟁 조건(race condition)을 유발할 수 있다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: // DB 연결 객체는 정적 필드에 저장하지 않는다.
 +3: private Connection conn;
 +4: private static final String CONNECT_STRING = "jdbc:ocl:orcl";
 +5:
 +6: public Connection dbConnection() {
 +7: InitialContext ctx;
 +8: try {
 +9: ctx = new InitialContext();
 +10: DataSource datasource = (DataSource) ctx.lookup(CONNECT_STRING);
 +11: conn = datasource.getConnection();
 +12: } catch (NamingException e) { …… }
 +13: return conn;
 +14: }
 +15: ……
 +</code>
 +경쟁 조건(Race condition)을 예방하기 위해 DB 연결 객체는 동적 필드에 저장한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-362 경쟁 상태 - http://cwe.mitre.org/data/definitions/362.html
 +\\
 +[2] SANS Top 25 2010 - (SANS 2010) Insecure Interaction - CWE ID 362 Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')
 +\\
 +[3] Java 2 Platform Enterprise Edition Specification, v1.4, Sun Microsystems
 +==== 2. 경쟁 조건: 싱글톤 멤버 필드(Race Condition: Singleton Member Field) ====
 +
 +=== 가. 정의 ===
 +서블릿(Servlet)의 멤버 필드는 다른 스레드와 공유될 수 있기 때문에, 서블릿 멤버 필드에 저장된 값은 다른 사용자에게 노출될 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +사용자 데이터를 서블릿의 필드에 저장하면 데이터에 대한 경쟁 조건(race condition)을 야기하여, 사용자가 다른 사용자의 데이터를 볼 수 있다. 따라서, 사용자 입력 데이터를 서블릿의 필드에 저장하지 말아야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: public class U9404 extends javax.servlet.http.HttpServlet {
 +2: // 파라미터의 매개변수값이 전역변수로 할당되어서 다른 사용자의 정보를 볼 수 있다.
 +3: private String name;
 +4:
 +5: protected void doPost(HttpServletRequest req, HttpServletResponse res)
 +6: throws ServletException, IOException {
 +7: name = req.getParameter("name");
 +8: ……
 +</code>
 +위의 예제는 요청 매개변수의 값을 필드에 저장한 후, 출력 스트림으로 보낸다. 이것은 단일 사용자 환경에서는 올바르게 동작하지만, 2명의 사용자가 거의 동시에 서블릿에 접근하면 다른 사용자의 정보를 볼 수 있다.
 +<code | 안전한 코드 예제>
 +1: public class S9404 extends javax.servlet.http.HttpServlet {
 +2: // private String name; <- 멤버 필드를 사용하지 않는다.
 +3: protected void doPost(HttpServletRequest req, HttpServletResponse res)
 +9: throws ServletException, IOException {
 +4: // 파라미터의 매개변수를 지역 변수에 할당한다.
 +5: String name = req.getParameter("name" );
 +6: if (name == null || "".equals(name)) return; //name = "user";
 +7: ……
 +</code>
 +요청 매개변수의 값을 필드 대신에 지역변수에 저장한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-362 경쟁 상태 - http://cwe.mitre.org/data/definitions/362.html
 +\\
 +[2] SANS Top 25 2010 - (SANS 2010) Insecure Interaction - CWE ID 362 Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')
 +\\
 +[3] The Java Servlet Specification, Sun Microsystems
 +==== 3. 경쟁 조건: 검사시점과 사용시점(Time-of-check Time-of-use (TOCTOU) Race Condition) ====
 +
 +=== 가. 정의 ===
 +병렬 실행 환경의 응용프로그램에서는 자원을 사용하기 전에 자원의 상태를 검사한다. 그러나 자원을 사용하는 시점에 자원의 상태가 변하는 경우가 있다. 이것으로 인해 프로그램에 여러 가지 문제, 즉 교착 상태, 경쟁 조건 및 기타 동기화 오류 등이 발생할 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +공유자원(예: 파일)을 여러 스레드가 접근하여 사용할 경우, 동기화 구문(synchronized)을 이용하여 한 번에 하나의 스레드만 접근 가능하도록 프로그램을 작성하여야 한다.
 +\\
 +성능에 미치는 영향을 최소화하기 위해 임계코드 주변만을 동기화 구문으로 감싼다.
 +\\
 +※ 다중쓰레드와 공유변수를 사용할 때는 thread safe 함수만을 사용한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: class FileMgmtThread extends Thread {
 +2:
 +3: private String manageType = "";
 +4:
 +5: public FileMgmtThread (String type) {
 +6: manageType = type;
 +7: }
 +8:
 +9: public void run() {
 +10: try {
 +11: if ( manageType.equals("READ") ) {
 +12: File f = new File("Test_367.txt");
 +13: if (f.exists()) { // 만약 파일이 존재하면 파일내용을 읽음
 +14: BufferedReader br = new BufferedReader(new FileReader(f));
 +15: br.close();
 +16: }
 +17: } else if ( manageType.equals("DELETE") ) {
 +18: File f = new File("Test_367.txt");
 +19: if (f.exists()) { // 만약 파일이 존재하면 파일을 삭제함
 +20: f.delete();
 +21: } else {
 +22: ;
 +23: }
 +24: }
 +25: } catch (IOException e) {
 +26: }
 +27: }
 +28: }
 +29:
 +30: public class CWE367 {
 +31: public static void main(String[] args) {
 +32: // 파일의 읽기와 파일을 삭제하는 것을 동시에 수행한다.
 +33: FileMgmtThread fileAccessThread = new FileMgmtThread("READ");
 +34: FileMgmtThread fileDeleteThread = new FileMgmtThread("DELETE");
 +35: fileAccessThread.start();
 +36: fileDeleteThread.start();
 +37: }
 +38: }
 +</code>
 +위 예제는 파일의 존재를 확인하는 부분과 실제로 파일을 사용하는 부분을 실행하는 과정에서 시간차가 발생하는 경우, 파일에 대한 삭제가 발생하여 프로그램이 예상하지 못하는 태로 수행될 수 있다. 또한 위 예제는 시간차를 이용하여 파일을 변경하는 등의 공격에 취약할 수 있다.
 +<code | 안전한 코드 예제>
 +1: class FileMgmtThread extends Thread {
 +2:
 +3: private static final String SYNC = "SYNC" ;
 +4:
 +5: private String manageType = "";
 +6:
 +7: public FileMgmtThread (String type) {
 +8: manageType = type;
 +9: }
 +10:
 +11: public void run() {
 +12: // synchronized 를 사용함으로써 지정된 객체에 lock이 걸려서
 +13: // 블록을 수행하는 동안 다른 Thread가 접근할 수 없다.
 +14: synchronized(SYNC) {
 +15: try {
 +16: if ( manageType.equals("READ") ) {
 +17: File f = new File("Test_367.txt");
 +18: if (f.exists()) { // 만약 파일이 존재하면 파일내용을 읽음
 +19: BufferedReader br = new BufferedReader(new FileReader(f));
 +20: br.close();
 +21: }
 +22: } else if ( manageType.equals("DELETE") ) {
 +23: File f = new File("Test_367.txt");
 +24: if (f.exists()) { // 만약 파일이 존재하면 파일을 삭제함
 +25: f.delete();
 +26: } else {
 +27: ;
 +28: }
 +29: }
 +30: } catch (IOException e) {
 +31: }
 +32: }
 +33: }
 +34: }
 +35:
 +36: public class CWE367 {
 +37: public static void main(String[] args) {
 +38: // 파일의 읽기와 파일을 삭제하는 것을 동시에 수행한다.
 +39: FileMgmtThread fileAccessThread = new FileMgmtThread("READ");
 +40: FileMgmtThread fileDeleteThread = new FileMgmtThread("DELETE");
 +41: fileAccessThread.start();
 +42: fileDeleteThread.start();
 +43: }
 +44: }
 +</code>
 +공유자원(예를 들어, 파일)을 여러 스레드가 접근하여 사용할 경우, 동기화 구문을 이용하여 한 번에 하나의 스레드만 접근 가능하도록 변경한다.
 +<code | 안전하지 않는 코드 예제>
 +1: public class MyServlet extends HttpServlet {
 +2: String name;
 +3: public void doPost ( HttpRequestRequest hreq, HttpResponceServlet hres ) {
 +4: name = hreq.getParameter("name");
 +5: …….
 +6: }
 +</code>
 +HttpServet을 상속받은 MyServlet이 멤버필드로 name을 사용하고 있다. name은 MyServlet을 동시에 사용하는 모든 사용자에게 정보가 노출된다.
 +<code | 안전한 코드 예제>
 +1: public class MyServlet extends HttpServlet {
 +2: public void doPost ( HttpRequestRequest hreq, HttpResponceServlet hres ) {
 +3: // 서블릿 프로그램의 멤버 변수는 공용으로 사용하기 때문에 로컬로 정의해서 사용한다.
 +4: String name = hreq.getParameter("name");
 +5: ...
 +6: }
 +</code>
 +name을 doPost 메소드에만 사용할 수 있도록 로컬로 정의하여 경쟁상태를 제거한다.
 +<code | 안전한 코드 예제>
 +1: public class MyClass {
 +2: String name;
 +3: public void doProcess (HttpRequestRequest hreq ) {
 +4: // 멤버변수 공유 시 동기화시킨다.
 +5: synchronized {
 +6: name = hreq.getParameter("name");
 +7: ...
 +8: }
 +9: ...
 +10: }
 +</code>
 +업무상 name을 여러 쓰레드 사이에서 공유해야 한다면, synchronized 문장을 사용하여,임계코드가 쓰레드들 간 동기화할 필요가 있다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-367 경쟁 조건: 검사시점과 사용시점 - http://cwe.mitre.org/data/definitions/367.html
 +\\
 +[2] SANS Top 25 Most Dangerous Software Errors
 +\\
 +[3] Michael Howard, David LeBlanc and John Viega. "24 Deadly Sins of Software Security"."Sin 13: Race Conditions." Page 205. McGraw-Hill. 2010
 +\\
 +[4] Andrei Alexandrescu. "volatile - Multithreaded Programmer's Best Friend". Dr. Dobb's. 2008-02-01
 +\\
 +[5] Steven Devijver. "Thread-safe webapps using Spring" David Wheeler. "Prevent race conditions". 2007-10-04
 +\\
 +[6] Matt Bishop. "RaceConditions, Files, andSecurityFlaws; or the Tortoise andtheHareRedux". September 1995
 +\\
 +[7] Johannes Ullrich. "Top 25 Series - Rank 25 - Race Conditions". SANS Software Security Institute. 2010-03-26
 +==== 4. J2EE 잘못된 습관: 스레드의 직접 사용(J2EE Bad Practices: Direct Use of Threads) ====
 +
 +=== 가. 정의 ===
 +J2EE 표준은 웹 응용프로그램에서 스레드 사용을 금지하고 있다. 따라서 스레드를 직접 사용하는 것 대신에 해당 플랫폼에서 제공하는 병렬 실행을 위한 프레임워크를 사용해야 한다. 그렇지 않을 경우, 교착 상태, 경쟁 조건, 및 기타 동기화 오류 등이 발생한다.
 +=== 나. 안전한 코딩기법 ===
 +J2EE에서는 스레드를 사용하는 것 대신에 병렬 실행을 위한 프레임워크를 사용해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: public class U383 extends HttpServlet {
 +2: protected void doGet(HttpServletRequest request, HttpServletResponse response)
 +throws ServletException, IOException {
 +3: // Thread를 만들고 background에서 작업을 수행한다.
 +4: Runnable r = new Runnable() {
 +5: public void run() {
 +6: System.err.println("do something");
 +7: }
 +8: };
 +9: new Thread(r).start();
 +10: }
 +11: }
 +</code>
 +J2EE 프로그램에서 스레드를 직접 생성하여 사용하면, 교착 상태, 경쟁 조건, 및 기타 동기화 오류 등이 발생할 수 있다.
 +<code | 안전한 코드 예제>
 +1: public class S383 extends HttpServlet {
 +2: protected void doGet(HttpServletRequest request, HttpServletResponse response)
 +throws ServletException, IOException {
 +3: // 수행할 Thread에 대해서 일반 자바 클래스를 만든다.
 +4: // New MyClass().main();
 +5:
 +6: // 만약 async로 병렬작업을 하기 위해서는 JAVA Runtime을
 +7: // 사용하여 async로 통신하는 게 좋다.
 +8: Runtime.getRuntime().exec("java AsyncClass" );
 +9: }
 +10: }
 +11:
 +12: class AsyncClass {
 +13: public static void main(String args[]) {
 +14: // Process and store request statistics.
 +15: // ……
 +16: System.err.println("do something");
 +17: }
 +18: }
 +</code>
 +스레드를 직접 사용하는 것 대신에 해당 플랫폼에서 제공하는 병렬 실행을 위한 프레임워크를 사용한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-383 J2EE 잘못된 습관: 스레드의 직접 사용 - http://cwe.mitre.org/data/definitions/383.html
 +\\
 +[2] Java 2 Platform Enterprise Edition Specification, v1.4, Sun Microsystems
 +==== 5. 심볼릭명이 정확한 대상에 매핑되어 있지 않음(Symbolic Name not Mapping to Correct Object) ====
 +
 +=== 가. 정의 ===
 +심볼릭명을 사용하여 특정 대상을 지정하는 경우 공격자는 심볼릭명이 가리키는 대상을 작하여 프로그램이 원래 의도했던 동작을 못하게 할 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +클래스 객체가 필요할 때에는 클래스 생성자를 표준적인 방법으로만 호출해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public void f() throws ClassNotFoundException, InstantiationException,
 +IllegalAccessException {
 +3: // Class.forName으로 클래스를 생성하고 있다.
 +4: Class c = Class.forName("testbed.unsafe.U386.Add");
 +5: Object obj = (Add)c.newInstance();
 +6: Add add = (Add) obj;
 +7: System.out.println(add.add(3, 5)); // 34
 +8:
 +9: Object obj2 = (Add)Class.forName(" testbed.unsafe.Add" ).newInstance();
 +10: Add add2 = (Add) obj2;
 +11: System.out.println(add2.add(3, 5)); // 8
 +12: }
 +13:
 +14: class Add {
 +15: int add(int x, int y) {
 +16: return x + y;
 +17: }
 +18: }
 +19: }
 +20:
 +21: class Add {
 +22: int add(int x, int y) { return (x*x + y*y); }
 +23: }
 +</code>
 +java.lang.Class.forName()은 인수 문자열을 기반으로 해당 클래스를 반환(return)하지만, 문자열이 "이름"으로서 지시하는 클래스가 언제나 동일한 메소드를 구현하고 있음을 보장하지 못한다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public void f() throws ClassNotFoundException,
 +3: InstantiationException, IllegalAccessException {
 +4: // 객체의 생성은 직접 생성자를 호출하여 생성한다.
 +5: testbed.safe.S386.Add add = new testbed.safe.S386.Add();
 +6: System.out.println(add.add(3, 5));
 +7: testbed.safe.Add add2 = new testbed.safe.Add();
 +8: System.out.println(add2.add(3, 5));
 +9: }
 +10:
 +11: class Add {
 +12: private int add(int x, int y) {
 +13: return x + y;
 +14: }
 +15: }
 +16: }
 +17:
 +18: class Add {
 +19: int add(int x, int y) { return (x*x + y*y); }
 +20: }
 +</code>
 +java.lang.Class.forName 대신, 각 클래스의 생성자를 제대로 호출하여 객체를 생성한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-386 심볼릭명이 정확한 대상에 매핑되어 있지 않음 - http://cwe.mitre.org/data/definitions/386.html
 +==== 6. 중복 검사된 잠금(Double-Checked Locking) ====
 +
 +=== 가. 정의 ===
 +중복 검사된 잠금(double-checked locking)은 프로그램의 효율성을 높이기 위해 사용하지만, 의도한 대로 동작하지 않는다.
 +\\
 +동기화 비용을 줄이기 위해, 프로그래머는 하나의 객체만 할당될 수 있도록 코드를 작성하지만, 자바에서는 객체 참조 주소를 할당하고 생성자를 호출하므로 의도한 객체가 완전하게 초기화되지 않은 상태에서 사용되는 경우가 발생할 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +특정 리소스가 (비)할당되었을 경우만 작업을 수행하도록 두 번에 걸쳐 검사를 시도해도 원하는 자원이 (비)할당되었는지 보장이 불가능하다.
 +\\
 +중복 검사된 잠금에 대한 완벽한 보장을 원할 경우 메소드를 동기화해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: Helper helper;
 +3:
 +4: public Helper MakeHelper() {
 +5: // helper 객체의 null 체크에 대해서는 동기화가 되지 않는다.
 +6: if (helper == null) {
 +7: synchronized (this) {
 +8: if (helper == null) {
 +9: helper = new Helper();
 +10: }
 +11: }
 +12: }
 +13: return helper;
 +14: }
 +15:
 +16: class Helper {
 +17: ……
 +18: }
 +19: }
 +</code>
 +위 예제는 하나의 helper 객체만 할당될 수 있도록 코드가 작성되었다. 이는 불필요한 동기화를 피하면서 스레드 안전성을 보장하는 것처럼 보인다. 그러나 자바에서는 객체 참조주소를 할당하고 생성자를 호출하므로, helper 객체가 완전하게 초기화되지 않은 상태에서 사용되는 경우가 발생할 수 있다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: Helper helper;
 +3:
 +4: // 메소드 전체에 대해 동기화를 하도록 설정함.
 +5: public synchronized Helper MakeHelper() {
 +6: if (helper == null) {
 +7: helper = new Helper();
 +8: }
 +9: return helper;
 +10: }
 +11: }
 +12:
 +13: class Helper {
 +14: ……
 +15: }
 +</code>
 +중복 검사된 잠금에 대한 완벽한 보장을 원할 경우, 메소드 전체에 대해 동기화를 하도록 설정한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-609 중복 검사된 잠금 - http://cwe.mitre.org/data/definitions/609.html
 +\\
 +[2] David Bacon et al.. "The "Double-Checked Locking is Broken" Declaration".
 +\\
 +http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
 +==== 7. 제대로 제어되지 않은 재귀(Uncontrolled Recursion) ====
 +
 +=== 가. 정의 ===
 +재귀의 순환횟수를 제어하지 못하여 할당된 메모리나 프로그램 스택 등의 자원을 과다하게 사용하면 위험하다. 대부분의 경우, 귀납 조건(base case)이 없는 재귀는 무한 재귀에 빠진다.
 +=== 나. 안전한 코딩기법 ===
 +무한 재귀를 방지하기 위하여 모든 재귀 호출을 조건문 블럭이나 반복문 블럭 안에서만 수행해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public int factorial(int n) {
 +3: // 재귀 호출이 조건문/반복문 블럭 외부에서 일어나면 대부분 무한 재귀를 유발한다.
 +4: return n * factorial(n - 1);
 +5: }
 +</code>
 +재귀적으로 정의되는 함수의 경우, 재귀 호출이 조건문/반복문 블럭 외부에서 일어나면 대부분 무한 재귀를 유발한다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public int factorial(int n) {
 +3: int i;
 +4: // 모든 재귀 호출은 조건문이나 반복문 블럭 안에서 이루어져야한다.
 +5: if (n == 1) {
 +6: i = 1;
 +7: } else {
 +8: i = n * factorial(n - 1);
 +9: }
 +10: return i;
 +11: }
 +</code>
 +모든 재귀 호출은 조건문이나 반복문 블럭 안에서 이루어져야한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-674 제대로 제어되지 않은 재귀 - http://cwe.mitre.org/data/definitions/674.html
 +
 +===== 5절. 에러 처리 =====
 +정상적인 에러는 사전에 정의된 예외사항이 특정 조건에서 발생하는 에러이며, 비정상적인 에러는 사전에 정의되지 않은 상황에서 발생하는 에러이다. 개발자는 정상적인 에러 및 비정상적인 에러 발생에 대비한 안전한 에러처리 루틴을 사전에 정의하고 프로그래밍함으로써 에러처리 과정 중에 발생 할 수 있는 보안 위협을 미연에 방지 할 수 있다. 에러를 불충하게 처리(혹은 전혀 처리) 하지 않을 때 혹은 에러 정보에 과도하게 많은 정보를 포함하여 이를 공격자가 악용 할 수 있을 때 보약취약점이 발생할 수 있다.
 +==== 1. 취약한 패스워드 요구조건(Weak Password Requirements) ====
 +
 +=== 가. 정의 ===
 +사용자에게 강한 패스워드를 요구하지 않으면 사용자 계정을 보호하기 힘들다.
 +=== 나. 안전한 코딩기법 ===
 +패스워드 관련해서 강한 조건이 필요하다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public void doPost(HttpServletRequest request, HttpServletResponse response)
 +3: throws IOException, ServletException {
 +4: try {
 +5: String id = request.getParameter("id");
 +6: String passwd = request.getParameter("passwd" );
 +7: // 패스워드 복잡도 검증 없이 가입 승인 처리
 +8: ....
 +9: } catch (SQLException e) { …… }
 +10: }
 +</code>
 +위 예제와 같이 가입자가 입력한 패스워드에 대한 복잡도 검증 없이 가입 승인 처리를 수행하게 되면 사용자 계정을 보호하기 힘들게 된다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: private static final String CONNECT_STRING = "jdbc:ocl:orcl";
 +3:
 +4: public void doPost(HttpServletRequest request, HttpServletResponse response)
 +5: throws IOException, ServletException {
 +6: try {
 +7: String id = request.getParameter("id");
 +8: String passwd = request.getParameter("passwd");
 +9:
 +10: // passwd에 대한 복잡도 검증
 +11: if (passwd == null || " " .equals(passwd)) return;
 +12: if (!passwd.matches(" ") && passwd.indexOf("@!#") > 4 && passwd.length() > 8) {
 +13: // passwd 복잡도 검증 후, 가입 승인 처리
 +14: }
 +15: } catch (SQLException e) { …… }
 +16: catch (NamingException e) { …… }
 +17: }
 +</code>
 +사용자 계정을 보호하기 위해 가입 시 패스워드 복잡도 검증 후 가입 승인처리를 수행한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-521 취약한 패스워드 요구조건 - http://cwe.mitre.org/data/definitions/521.html
 +\\
 +[2] OWASP Top Ten 2004 Category A3 - Broken Authentication and Session Management
 +==== 2. 오류 메시지 통한 정보 노출(Information exposure through an error message) ====
 +
 +=== 가. 정의 ===
 +SW는 오류 메시지를 통해 환경, 사용자, 관련 데이터 등의 프로그램 내부 정보를 유출될수 있다. 예를 들어 예외 발생 시 예외 이름이나 스택 트레이스를 출력하면 프로그램 내부 구조를 쉽게 파악할 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +최종 사용자에게 배포되는 SW에서는 내부 구조나 공격자에 활용될 수 있는 민감한 정보를 오류 메시지로 출력하지 말아야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public static void main(String[] args) {
 +3: String urlString = args[0];
 +4: try{
 +5: URL url = new URL(urlString);
 +6: URLConnection cmx = url.openConnection();
 +7: cmx.connect();
 +8: }
 +9: catch (Exception e) { e.printStackTrace(); }
 +10: }
 +</code>
 +예외 이름이나 스택 트레이스를 출력하면 프로그램 내부 정보가 유출된다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public static void main(String[] args) {
 +3: String urlString = args[0];
 +4: try{
 +5: URL url = new URL(urlString);
 +6: URLConnection cmx = url.openConnection();
 +7: cmx.connect();
 +8: }
 +9: catch (Exception e) { System.out.println("연결 예외 발생" ); }
 +10:
 +</code>
 +예외 이름이나 스택 트레이스를 출력하지 않는다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-209 오류 메시지 통한 정보 노출 - http://cwe.mitre.org/data/definitions/209.html
 +==== 3. 오류 상황에 대한 처리 부재(Detection of Error Condition Without Action) ====
 +
 +=== 가. 정의 ===
 +오류는 포착했으나 그 오류에 대해서 아무 조치도 하지 않으면, 그 상태에서 계속 프로그램이 실행되므로 개발자가 의도하지 않은 결과를 초래한다.
 +=== 나. 안전한 코딩기법 ===
 +예외 또는 오류를 포착(catch)한 경우 그것에 대한 적절한 처리를 해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: private Connection conn;
 +3:
 +4: public Connection DBConnect(String url, String id, String password) {
 +5: try {
 +6: String CONNECT_STRING = url + ":" + id + ":" + password;
 +7: InitialContext ctx = new InitialContext();
 +8: DataSource datasource = (DataSource) ctx.lookup(CONNECT_STRING);
 +9: conn = datasource.getConnection();
 +10: } catch (SQLException e) {
 +11: //catch 블록이 비어있음
 +12: } catch (NamingException e) {
 +13: //catch 블록이 비어있음
 +14: }
 +15: return conn;
 +16: }
 +</code>
 +위 예제는 try 블록에서 발생하는 오류를 포착(catch)하고 있지만 그 오류에 대해서 아무조치를 하고 있지 않다. 따라서 프로그램이 계속 실행되기 때문에 프로그램에서 어떤 일이 일어났는지 전혀 알 수 없게 된다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: private Connection conn;
 +3:
 +4: public Connection DBConnect(String url, String id, String password) {
 +5: try {
 +6: String CONNECT_STRING = url + ":" + id + ":" + password;
 +7: InitialContext ctx = new InitialContext();
 +8: DataSource datasource = (DataSource) ctx.lookup(CONNECT_STRING);
 +9: conn = datasource.getConnection();
 +10: } catch (SQLException e) {
 +11: //Exception catch이후 Exception에 대한 적절한 처리를 해야 한다.
 +12: if ( conn != null ) {
 +13: try {
 +14: conn.close();
 +15: } catch (SQLException e1) {
 +16: conn = null;
 +17: }
 +18: }
 +19: } catch (NamingException e) {
 +20: //Exception catch이후 Exception에 대한 적절한 처리를 해야 한다.
 +21: if ( conn != null ) {
 +22: try {
 +23: conn.close();
 +24: } catch (SQLException e1) {
 +25: conn = null;
 +26: }
 +27: }
 +28: }
 +29: return conn;
 +30: }
 +</code>
 +예외를 포착(catch)한 후, 각각의 예외 사항(Exception)에 대하여 적절하게 처리해야 한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-390 오류 상황에 대한 처리 부재 - http://cwe.mitre.org/data/definitions/390.html
 +\\
 +[2] OWASP Top Ten 2004 Category A7 - Improper Error Handling
 +==== 4. 비정상적 혹은 예외적 조건의 부적절한 검사(Improper Check for Unusual or Exceptional Conditions) ====
 +
 +=== 가. 정의 ===
 +프로그램 수행 중에 함수의 결과 값에 대한 적절한 처리 또는 예외상황에 대한 조건을 적절하게 검사하지 않을 경우, 예기치 않은 문제를 야기할 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +값을 반환하는 모든 함수의 결과 값을 검사하여, 그 값이 기대한 값인지 검사하고, 예외처리를 사용하는 경우에 광범위한 예외처리 대신 구체적인 예외처리를 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: public void readFromFile(String fileName) {
 +2: try {
 +3: ...
 +4: File myFile = new File(fileName);
 +5: FileReader fr = new FileReader(myFile);
 +6: ...
 +7: } catch (Exception ex) {...}
 +8: }
 +</code>
 +함수의 인자로 fileName에 대한 Null 체크없이 File 객체를 생성하였으며, 광범위한 예외 클래스인 Exception을 사용하여 예외처리를 했다.
 +<code | 안전한 코드 예제>
 +1: public void readFromFile(String fileName) throws FileNotFoundException,
 +2: IOException,MyException {
 +3: try {
 +4: ...
 +5: // filename에 대한 널을 조사
 +6: if ( fileName == NULL ) throw new MyException("에러“);
 +7: File myFile = new File(fileName);
 +8: FileReader fr = new FileReader(myFile);
 +9: ...
 +10: // 함수 루틴에서 모든 가능한 예외에 대해서 처리한다.
 +11: } catch (FileNotFoundException fe) {...}
 +12: } catch (IOException ie) {...}
 +13: }
 +</code>
 +fileName이 Null 값인지 검사하고 Null이면 에러 메시지를 출력과 예외를 발생시킨다.
 +\\
 +또한 발생 가능한 모든 예외에 대한 구체적인 예외처리를 한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-754 부적절한 혹은 예외적 조건의 부적절한 검사 - http://cwe.mitre.org/data/definitions/754.html
 +\\
 +CWE-252 미점검 리턴 값 - http://cwe.mitre.org/data/definitions/252.html
 +\\
 +CWE-253 부정확한 함수 리턴 값 점검 - http://cwe.mitre.org/data/definitions/253.html
 +\\
 +CWE-273 부적절한 하락된 특권점검 - http://cwe.mitre.org/data/definitions/273.html
 +\\
 +CWE-296 부적절한 증명서 검증 신뢰체인 후속 - http://cwe.mitre.org/data/definitions/296.html
 +\\
 +CWE-297 부적절한 호스트-특정 증명서 데이터검증 - http://cwe.mitre.org/data/definitions/297.html
 +\\
 +CWE-298 부적절한 증명서 만료검증 - http://cwe.mitre.org/data/definitions/298.html
 +\\
 +CWE-299 부적절한 증명서 파기점검 - http://cwe.mitre.org/data/definitions/299.html
 +\\
 +[2] SANS Top 25 Most Dangerous Software Errors, http://www.sans.org/top25-software-errors/
 +\\
 +[3] M. Howard, D. LeBlanc, Writing Secure Code, Second Edition, Microsoft Press
 +===== 6절. 코드 품질 =====
 +작성 완료된 프로그램은 기능성, 신뢰성, 사용성, 유지보수성, 효율성, 이식성 등을 충족하기 위하여 일정 수준에 코드품질을 유지하여야 한다. 프로그램 코드가 너무 복잡하면 관리성,유지보수성, 가독성이 떨어질 뿐 아니라 다른 시스템에 이식하기도 힘들며, 프로그램에는 안전성을 위협할 취약점들이 코드 안에 숨겨져 있을 가능성이 있다.
 +==== 1. 코드 정확성: notify() 호출(Code Correctness: Call to notify()) ====
 +
 +=== 가. 정의 ===
 +스레드의 notify()를 직접 호출하면 살아 있는 스레드 중에서 어떤 스레드를 깨울지 불명확하다. 따라서 직접 호출하지 않는 것이 좋다.
 +=== 나. 안전한 코딩기법 ===
 +notify()를 직접 호출하면 어떤 스레드를 깨울지 불명확하므로 사용하지 않는 것이 좋다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public synchronized void notifyJob() {
 +3: boolean flag = true;
 +4: notify();
 +5: }
 +</code>
 +notify()를 직접 호출하면 어떤 스레드를 깨울지 불명확하다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public synchronized void notifyJob() {
 +3: boolean flag = true;
 +4: //notify() 메소드를 사용하지 않는다.
 +5: }
 +</code>
 +notify() 메소드를 사용하지 않는다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-362 경쟁 상태 - http://cwe.mitre.org/data/definitions/362.html
 +\\
 +CWE-662 부적절한 동기화 - http://cwe.mitre.org/data/definitions/662.html
 +\\
 +[2] Sun Microsystems, Inc. Java Sun Tutorial - Concurrency
 +==== 2. 자원의 부적절한 반환(Improper Resource Shutdown or Release) ====
 +
 +=== 가. 정의 ===
 +프로그램의 자원, 예를 들면 열린 파일 기술자(open file descriptor), 힙 메모리(heap memory),소켓(socket) 등은 유한한 자원이다. 이러한 자원을 할당받아 사용한 후, 더 이상 사용하지 않는 경우에는 적절히 반환하여야 한다.
 +=== 나. 안전한 코딩기법 ===
 +자원을 획득하여 사용한 다음에는 finally 블록에서 반드시 자원을 해제하여야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public void processFile() throws SQLException {
 +3: Connection conn = null;
 +4: final String url = "jdbc:mysql://127.0.0.1/example?user=root&password=1234";
 +5: try {
 +6: Class.forName("com.mysql.jdbc.Driver");
 +7: conn = DriverManager.getConnection(url);
 +8: ……
 +9: // 예외발생시 할당 받은 자원이 반환되지 않는다.
 +10: conn.close();
 +11: } catch (ClassNotFoundException e) {
 +12: System.err.println("ClassNotFoundException occured");
 +13: } catch (SQLException e) {
 +14: System.err.println("SQLException occured");
 +15: } finally {
 +16:
 +17: ……
 +</code>
 +위의 예제는 데이터베이스에 연결된 후에 사용 중 예외가 발생하면 할당된 데이터베이스 컨넥션 및 JDBC 자원이 반환되지 않는다. 이와 같은 상황이 반복될 경우 시스템에서 사용 가능한 자원이 소진될 수 있다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public void processFile() throws SQLException {
 +3: Connection conn = null;
 +4: String url = "jdbc:mysql://127.0.0.1/example?user=root&password=1234";
 +5: try {
 +6: Class.forName("com.mysql.jdbc.Driver");
 +7: conn = DriverManager.getConnection(url);
 +8: ……
 +9: } catch (ClassNotFoundException e) {
 +10: System.err.print("error");
 +11: } catch (SQLException e) {
 +12: System.err.print("error");
 +13: } finally {
 +14: ……
 +15: // 더 이상 사용하지 않으면 즉시 close()를 해줘야 한다.
 +16: conn.close();
 +17: ……
 +</code>
 +예외상황이 발생하여 함수가 종료될 때 예외의 발생 여부와 상관없이 finally 블록에서 할당받은 자원을 반환한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-404 자원의 부적절한 반환 - http://cwe.mitre.org/data/definitions/404.html
 +\\
 +[2] SANS Top 25 2009 - (SANS 2009) Risky Resource Management - CWE ID 404 Improper Resource Shutdown or Release
 +==== 3. 널포인터 역참조(NULL Pointer Dereference) ====
 +
 +=== 가. 정의 ===
 +널 포인터 역참조는 '일반적으로 그 객체가 NULL이 될 수 없다'라고 하는 가정을 위반했을 때 발생한다. 공격자가 의도적으로 NULL 포인터 역참조를 실행하는 경우, 그 결과 발생하는 예외 사항을 이용하여 추후의 공격을 계획하는 데 사용될 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +널이 될 수 있는 레퍼런스(reference)는 참조하기 전에 널 값인지를 검사하여 안전한 경우에만 사용해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public void f() {
 +3: String cmd = System.getProperty("cmd");
 +4: // cmd가 null인지 체크하지 않았다.
 +5: cmd = cmd.trim();
 +6: System.out.println(cmd);
 +7: ……
 +</code>
 +위 예제는 "cmd" 프로퍼티가 항상 정의되어 있다고 가정하고 있지만, 만약 공격자가 프로그램의 환경을 제어해 "cmd" 프로퍼티가 정의되지 않게 하면, cmd는 널이 되어 trim() 메소드를 호출 할 때 널 포인터 예외가 발생하게 된다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public void f() {
 +3: String cmd = System.getProperty("cmd");
 +4: // cmd가 null인지 체크하여야 한다.
 +5: if (cmd != null) {
 +6: cmd = cmd.trim();
 +7: System.out.println(cmd);
 +8: } else System.out.println("null command");
 +9: ……
 +</code>
 +먼저 cmd가 널인지 검사한 후에 사용한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-476 널포인터 역참조 - http://cwe.mitre.org/data/definitions/476.html
 +==== 4. 코드 정확성: 부정확한 serialPersistentFields 조정자(Code Correctness: Incorrect serialPersistentFields Modifier) ====
 +
 +=== 가. 정의 ===
 +serialPersistentFields를 정확하게 사용하기 위해서는 ‘private static final’로 선언해야 한다. public으로 선언하여 공유하면 정확성을 해칠 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +serialPersistentFields를 정확하게 사용하려면 private, static, final로 선언해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: class List implements Serializable {
 +2: public ObjectStreamField[] serialPersistentFields =
 +{ new ObjectStreamField("myField", List.class) };
 +3: ……
 +4: }
 +</code>
 +serialPersistentFields를 정확하게 사용하기 위해서는 private, static, final로 선언해야 한다.
 +<code | 안전한 코드 예제>
 +1: class List implements Serializable {
 +2: private static final ObjectStreamField[] serialPersistentFields =
 +{ new ObjectStreamField("myField", List.class) };
 +3: ……
 +4: }
 +</code>
 +serialPersistentFields를 정확하게 사용하기 위해서는 private, static, final로 선언해야 한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-485 불충분한 캡슐화 - http://cwe.mitre.org/data/definitions/485.html
 +\\
 +[2] Sun Microsystems, Inc. Java Sun Tutorial
 +==== 5. 코드 정확성: Thread.run() 호출(Code Correctness: Call to Thread.run()) ====
 +
 +=== 가. 정의 ===
 +프로그램에서 스레드의 start() 대신에 run()을 호출하면 스레드가 생성되지 않고, 해당 un() 함수를 직접 호출하여 해당 run() 함수의 종료를 대기하게 된다. 즉, 프로그래머는 새로운 스레드를 시작시키려고 했지만, start() 대신에 run()을 호출함으로써 호출자의 스레드에서 run() 메소드를 실행하게 된다.
 +=== 나. 안전한 코딩기법 ===
 +스레드의 run() 대신에 start()를 수행하도록 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: protected void cwe_572() {
 +3: Thread thr = new PrintThread();
 +4: // 스레드 객체의 run() 메소드를 직접 호출하는 것은 대부분 버그이다.
 +5: thr.run();
 +6: } ……
 +7: }
 +8: class PrintThread extends Thread {
 +9: public void run() { System.out.println("CWE 572 TEST"); }
 +10: }
 +</code>
 +start() 대신에 run() 메소드를 사용하고 있다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: protected void cwe_572() {
 +3: Thread thr = new PrintThread();
 +4: // 새로운 스레드를 시작시킨다.
 +5: thr.start();
 +6: } ……
 +7: }
 +8: class PrintThread extends Thread {
 +9: public void run() { System.out.println("CWE 572 TEST"); }
 +10: }
 +</code>
 +스레드의 start() 메소드를 사용한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-572 코드 정확성: Thread.run() 호출 - http://cwe.mitre.org/data/definitions/572.html
 +==== 6. 코드 정확성: 동기화된 메소드를 비동기화된 메소드로 재정의 (Code Correctness: Non-Synchronized Method Overrides Synchronized Method) ====
 +
 +=== 가. 정의 ===
 +클래스를 상속받아 사용하는 경우, 상위 클래스에서 동기화된(synchronized) 메소드는 하위 클래스에서 재정의(override)를 하지 않거나, 재정의해야 하는 경우 기존과 동일하게 동기화된(synchronized) 메소드로 정의해야 한다.
 +=== 나. 안전한 코딩기법 ===
 +하위 클래스에서 동기화된(synchronized) 메소드를 재정의해야 하는 경우, 상위 클래스와 동일하게 synchronized 메소드로 재정의해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: public class U9627 {
 +2: public synchronized void synchronizedMethod() {
 +3: for (int i=0; i<10; i++) System.out.print(i);
 +4: }
 +5: ……
 +6: }
 +7:
 +8: public class Foo extends U9627 {
 +9: //동기화된 메소드로 정의하지 않았다.
 +10: public void synchronizedMethod() {
 +11: for (int i=0; i<20; i++) System.out.print(i);
 +12: }
 +13: }
 +</code>
 +상위 클래스에서 동기화된(synchronized) 메소드를 하위 클래스에서 비동기화된 메소드로
 +재정의(override)하면 안 된다
 +<code | 안전한 코드 예제>
 +1: public class S9627 {
 +2: public synchronized void synchronizedMethod() {
 +3: for (int i=0; i<10; i++) System.out.print(i);
 +4: }
 +5: ……
 +6: }
 +7:
 +8: public class Foo extends S9627 {
 +9: public synchronized void synchronizedMethod() {
 +10: for (int i=0; i<20; i++) System.out.print(i);
 +11: }
 +12: }
 +</code>
 +동기화된(synchronized) 메소드는 재정의하지 않거나 재정의하면 동기화된(synchronized) 메소드로 제정의해야 한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-665 부적절한 초기화 - http://cwe.mitre.org/data/definitions/665.html
 +\\
 +[2] Sun Microsystems, Inc. Bug ID: 4294756 Javac should warn if synchronized method is overridden with a non synchronized
 +==== 7. 무한 자원 할당(Allocation of Resources Without Limits or Throttling) ====
 +
 +=== 가. 정의 ===
 +프로그램이 자원을 사용 후 해제하지 않거나, 한 사용자당 서비스할 수 있는 자원의 양을 제한하지 않고, 서비스 요청마다 요구하는 자원을 할당한다.
 +=== 나. 안전한 코딩기법 ===
 +프로그램에서 자원을 오픈하여 사용하고 난 후, 반드시 자원을 해제한다.
 +\\
 +사용자가 사용할 수 있는 자원의 사이즈를 제한한다.
 +\\
 +※ 사용자가 접근할 수 있는 자원의 양을 제한한다. 특히 제한된 자원을 효율적으로 사용하기 위해서 Pool(Thread Pool, Connection Pool 등)을 사용한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: Connection conn = null;
 +2: PreparedStatement pstmt = null;
 +3: try {
 +4: conn=getConnection();
 +5: ...
 +6: pstmt = conn.prepareStatement("SELECT * FROM employees
 +7: where name=?");
 +8: ...
 +9: conn.close();
 +10: pstmt.close();
 +11: }catch (SQLException ex) {...}
 +</code>
 +close()문을 만나기 전에 예외가 일어나면, open된 자원은 dangling resource로 메모리에 존재한다. 즉 참조를 잃어버렸기 때문에 재사용은 불가하다.
 +<code | 안전한 코드 예제>
 +1: Connection conn = null;
 +2: PreparedStatement pstmt = null;
 +3: try {
 +4: conn=getConnection();
 +5: ...
 +6: pstmt = conn.prepareStatement("SELECT * FROM employees
 +7: where name=?");
 +8: ...
 +9: }catch (SQLException ex) {...}
 +10: // 자원을 사용하고 해제 시 항상 finally문에서 한다.
 +11: finally {
 +12: if ( conn!= null ) try { conn.close(); } catch (SQLException e){...}
 +13: if ( pstmt!= null ) try { pstmt.close(); } catch (SQLException e){...}
 +14: }
 +</code>
 +중간에 예외상황이 발생하더라도 함수가 종료되기 직전에 항상 finally문을 수행하므로, 자원을 해제할 경우 항상 finally문에서 해제한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-400 무제한 자원 소비 - http://cwe.mitre.org/data/definitions/400.html
 +\\
 +CWE-774 제한이나 조절 없이 파일 디스크립터나 핸들할당 - http://cwe.mitre.org/data/definitions/774.html
 +\\
 +CWE-789 무제어 메모리 할당 - http://cwe.mitre.org/data/definitions/789.html
 +\\
 +CWE-770 제한이나 조절 없이 자원할당 - http://cwe.mitre.org/data/definitions/770.html
 +\\
 +[2] M. Howard and D. LeBlanc. "Writing Secure Code". Chapter 17, "Protecting Against Denial of Service Attacks" Page 517. 2nd Edition. Microsoft. 2002
 +\\
 +[3] J. Antunes, N. Ferreira Neves and P. Verissimo. "Detection and Prediction of Resource-Exhaustion Vulnerabilities". Proceedings of the IEEE International
 +
 +===== 7절. 캡슐화 =====
 +소프트웨어가 중요한 데이터나 기능성을 불충분하게 캡슐화 하는 경우, 인가된 데이터와 인가되지 않은 데이터를 구분하지 못하게 되어 허용되지 않는 사용자들 간의 데이터 누출이 가능해진다. 캡슐화는 단순히 일반 소프트웨어 개발 방법상의 상세한 구현 내용을 감추는 일뿐 아니라 소프트웨어 보안 측면의 좀 더 넓은 의미로 사용된다.
 +==== 1. 세션 간에 데이터 누출(Data Leak Between Sessions) ====
 +
 +=== 가. 정의 ===
 +다중 스레드 환경에서는 싱글톤(singleton) 객체 필드에 경쟁 조건(race condition)이 발생할 수 있다. 따라서 다중 스레드 환경에서 서블릿(servlet)에 정보를 저장하는 필드가 포함되지 않도록 하여 세션에서 데이터를 접근할 수 없도록 해야 한다.
 +=== 나. 안전한 코딩기법 ===
 +HttpServlet 클래스의 하위클래스에서 멤버 필드를 선언하면 안된다. 필요한 경우 지역 변수를 선언하여 사용한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: public class U488 extends HttpServlet {
 +2: private String name;
 +3: protected void doPost(HttpServletRequest request, HttpServletResponse response)
 +4: throws ServletException, IOException {
 +5: name = request.getParameter("name");
 +6: ……
 +7: out.println(name + ", thanks for visiting!");
 +8: }
 +9: }
 +</code>
 +두 사용자가 거의 동시에 접속할 시, 첫번째 사용자를 위한 스레드가 out.println(...)을 수행하기 전에 두번째 사용자의 스레드가 name = ... 을 수행하면 첫번째 사용자는 두번째 사용자의 정보(name)를 보게 된다.
 +<code | 안전한 코드 예제>
 +1: public class S488 extends HttpServlet {
 +2: protected void doPost(HttpServletRequest request, HttpServletResponse response)
 +3: throws ServletException, IOException {
 +4: // 지역변수로 변경한다.
 +5: String name = request.getParameter("name");
 +6: if (name == null || "".equals(name)) return;
 +7: out.println(name + ", thanks for visiting!");
 +8: }
 +9: }
 +</code>
 +필요한 경우 지역변수를 선언하여 사용한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-488 세션 간에 데이터 누출 - http://cwe.mitre.org/data/definitions/488.html
 +==== 2. 제거되지 않고 남은 디버거 코드(Leftover Debug Code) ====
 +
 +=== 가. 정의 ===
 +디버깅 목적으로 삽입된 코드는 개발이 완료되면 제거해야 한다. 만일, 남겨진 채로 배포될 경우 공격자가 식별 과정을 우회하거나 의도하지 않은 정보와 제어 정보가 누출될 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +J2EE와 같은 응용프로그램에서 main() 메소드를 정의하면 안된다. 이것은 보통 디버깅을 위해서 만드는 경우가 있는데, 디버깅이 끝나면 main() 메소드를 삭제해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: public class U489 extends HttpServlet {
 +2: protected void doGet(HttpServletRequest request, … ) throws …… { …… }
 +3: protected void doPost(HttpServletRequest request, … ) throws …… { …… }
 +4: // 테스트를 위한 main()함수나 디버깅용 로그 출력문 등이 남아 있다.
 +5: public static void main(String args[]) {
 +6: System.err.printf("Print debug code");
 +7: }
 +8: ……
 +</code>
 +J2EE와 같은 응용프로그램에서 디버깅용으로 사용되는 main() 메소드는 삭제되어야 한다.
 +<code | 안전한 코드 예제>
 +1: public class S489 extends HttpServlet {
 +2: protected void doGet(HttpServletRequest request, … ) throws …… { …… }
 +3: protected void doPost(HttpServletRequest request, … ) throws …… { …… }
 +4: //테스트용 코드는 제거해준다.
 +</code>
 +J2EE와 같은 응용프로그램에서 디버깅용 main() 메소드는 삭제한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-489 제거되지 않고 남은 디버거 코드 - http://cwe.mitre.org/data/definitions/489.html
 +==== 3. 민감한 데이터를 가진 내부 클래스 사용(Use of Inner Class Containing Sensitive Data) ====
 +
 +=== 가. 정의 ===
 +내부 클래스는 컴파일 과정에서 패키지 수준의 접근성으로 바뀌기 때문에 의도하지 않은 정보 공개가 발생할 수 있다. 이를 피하기 위해서는 정적(static) 내부 클래스, 지역적(local) 내부 클래스 또는 익명(anonymous) 내부 클래스를 사용하는 것을 고려해야 한다.
 +=== 나. 안전한 코딩기법 ===
 +내부클래스 사용 시 외부클래스의 private 필드를 접근하지 않도록 한다. 가급적이면 내부 클래스를 사용하지 않도록하며, 불가피하게 내부클래스를 사용할 경우, 정적(static) 또는 지역적(local) 또는 익명(anonymous) 내부 클래스를 사용해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: public final class U492 extends Applet {
 +2: // 외부 클래스에서 내부 클래스로 가면서 보안 수준을 낮추어서는 않된다.
 +3: public class urlHelper { String openData = secret; }
 +4: String secret;
 +5: urlHelper helper = new urlHelper();
 +6: }
 +</code>
 +내부 클래스는 바이트코드에서는 패키지 수준 접근제어로 바뀌기 때문에, 내부 클래스가 둘러싸고 있는 클래스의 민감한 정보에 접근시, 이 내부 클래스를 통해 정보가 유출될 수 있다.
 +<code | 안전한 코드 예제>
 +1: public class S492 extends Applet {
 +2: // 내부 클래스를 정적(static) 선언하여 외부클래스의 private 필드에 접근 못하게 한다.
 +3: public static class urlHelper { ... }
 +4: String secret;
 +5: urlHelper helper = new urlHelper(secret);
 +6: }
 +7:
 +</code>
 +내부클래스의 사용에 주의해서 내부클래스에서 외부클래스의 private 필드를 접근하지 않도록 한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-492 민감한 데이터를 가진 내부 클래스 사용 - http://cwe.mitre.org/data/definitions/492.html
 +==== 4. Final 변경자 없는 주요 공용 변수(Critical Public Variable Without Final Modifier) ====
 +
 +=== 가. 정의 ===
 +public으로 선언된 멤버 변수를 final로 선언하지 않으면, 그 변수의 값을 외부에서 변경할수 있다. 일반적으로 객체의 상태 변경은 허용된 인터페이스만 사용하도록 해야 한다.
 +=== 나. 안전한 코딩기법 ===
 +변경되면 안되는 public 멤버 변수는 반드시 final로 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: public final class U493 extends Applet {
 +2: // price 필드가 final이 아니기 때문에, 외부에서 price를 수정할 수 있다.
 +3: public static float price = 500;
 +4:
 +5: public float getTotal(int count) {
 +6: return price * count;
 +7: }
 +8: ……
 +</code>
 +price 필드가 final이 아니기 때문에, 외부에서 변경이 가능하며, getTotal()의 값이 변조될수 있다.
 +<code | 안전한 코드 예제>
 +1: public final class S493 extends Applet {
 +2: // 수정되면 안되는 변수는 final 키워드로 선언한다.
 +3: public static final float price = 500;
 +4:
 +5: public float getTotal(int count) {
 +6: return price * count; // price 수정 불가
 +7: }
 +8: }
 +</code>
 +변경되면 안되는 public 멤버 변수는 final 키워드로 선언한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-493 Final 변경자 없는 주요 공용 변수 - http://cwe.mitre.org/data/definitions/493.html
 +==== 5. 공용 메소드로부터 리턴된 private 배열-유형 필드(Private Array-Typed Field Returned From A Public Method) ====
 +
 +=== 가. 정의 ===
 +private로 선언된 배열을 public으로 선언된 메소드를 통해 반환(return)하면, 그 배열의 레퍼런스가 외부에 공개되어 외부에서 배열의 수정할 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +private로 선언된 배열을 public으로 선언된 메소드를 통해 반환하지 않도록 해야 한다.
 +\\
 +필요한 경우 배열의 복제본을 반환하거나, 수정을 제어하는 public 메소드를 별도로 선언하여 사용한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: // private 인 배열을 public인 메소드가 return한다
 +2: private String[] colors;
 +3: public String[] getColors() { return colors; }
 +</code>
 +멤버 변수 colors는 private로 선언되었지만 public으로 선언된 getColors() 메소드를 통해 reference를 얻을 수 있다. 이를 통해 의도하지 않은 수정이 발생할 수 있다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: private String[] colors;
 +3: // 메소드를 private으로 하거나, 복제본을 반환하거나, 수정을 제어하는 public 메소드를 별도로 만든다.
 +4: public String[] getColors() {
 +5: String[] ret = null;
 +6: if ( this.colors != null ) {
 +7: ret = new String[colors.length];
 +8: for (int i = 0; i < colors.length; i++) { ret[i] = this.colors[i]; }
 +9: }
 +10: return ret;
 +11: }
 +12: ……
 +</code>
 +private 배열의 복제본을 만들어서, 그것을 반환하도록 작성하면 private 선언된 배열에 대한 의도하지 않은 수정을 방지할 수 있다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-495 공용 메소드로부터 리턴된 private 배열-유형 필드 - http://cwe.mitre.org/data/definitions/495.html
 +==== 6. private 배열-유형 필드에 공용 데이터 할당 (Public Data Assigned to Private Array-Typed Field) ====
 +
 +=== 가. 정의 ===
 +public으로 선언된 데이터 또는 메소드의 인자가 private 선언된 배열에 저장되면, private 배열을 외부에서 접근할 수 있다.
 +=== 나. 안전한 코딩기법 ===
 +public으로 선언된 데이터가 private 선언된 배열에 저장되지 않도록 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: // userRoles 필드는 private이지만, public인 setUserRoles()를 통해 외부의 배열이 할당되면,사실상 public 필드가 된다.
 +3: private String[] userRoles;
 +4:
 +5: public void setUserRoles(String[] userRoles) {
 +6: this.userRoles = userRoles;
 +7: }
 +8: ……
 +</code>
 +userRoles 필드는 private이지만, public인 setUserRoles()를 통해 외부의 배열이 할당되면,사실상 public 필드가 된다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: // 객체가 클래스의 private member를 수정하지 않도록 한다.
 +3: private String[] userRoles;
 +4:
 +5: public void setUserRoles(String[] userRoles) {
 +6: this.userRoles = new String[userRoles.length];
 +7: for (int i = 0; i < userRoles.length; ++i)
 +8: this.userRoles[i] = userRoles[i];
 +9: }
 +10: ……
 +</code>
 +입력된 배열의 reference가 아닌, 배열의 "값"을 private 배열의 할당함으로써 private 멤버로서의 접근권한을 유지 시켜준다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-496 private 배열-유형 필드에 공용 데이터 할당 - http://cwe.mitre.org/data/definitions/496.html
 +==== 7. 시스템 데이터 정보 누출(Information Leak of System Data) ====
 +
 +=== 가. 정의 ===
 +시스템의 내부 데이터나 디버깅 관련 정보가 공개되면, 이를 통해 공격자에게 아이디어를 제공하는 등 공격의 빌미가 된다.
 +=== 나. 안전한 코딩기법 ===
 +디버깅을 위해 작성한 시스템 정보 출력 코드를 모두 삭제해야 한다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public void f() {
 +3: try { g(); }
 +4: catch (IOException e) {
 +5: // 예외 발생시 printf(e.getMessage())를 통해 오류 메시지 정보가 유출된다.
 +6: System.err.printf(e.getMessage());
 +7: }
 +8: }
 +9: private void g() throws IOException { …… }
 +10: …
 +</code>
 +예외 발생시 getMessage()를 통해 오류와 관련된 시스템 에러정보 등 민감한 정보가 유출될 수 있다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public void f() {
 +3: try { g(); }
 +4: catch (IOException e) {
 +5: // end user가 볼 수 있는 오류 메시지 정보를 생성하지 않아야 한다.
 +6: System.err.println(" IOException Occured" );
 +7: }
 +8: }
 +9: private void g() throws IOException { …… }
 +10: ……
 +</code>
 +가급적이면 공격의 빌미가 될 수 있는 오류와 관련된 상세한 정보는 최종 사용자에게 노출하지 않는다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-497 시스템 데이터 정보 누출 - http://cwe.mitre.org/data/definitions/497.html
 +==== 8. 동적 클래스 로딩 사용(Use of Dynamic Class Loading) ====
 +
 +=== 가. 정의 ===
 +동적으로 클래스를 로드하면 그 클래스가 악성 코드일 가능성이 있다. 동적으로 클래스를 로드하지 말아야 한다.
 +=== 나. 안전한 코딩기법 ===
 +동적 로딩은 사용하지 않는다.
 +=== 다. 예제 ===
 +<code | 안전하지 않는 코드 예제>
 +1: ……
 +2: public void f() {
 +3: // 외부 입력으로 동적 클래스 로딩
 +4: String classname = System.getProperty("customClassName" );
 +5: try {
 +6: Class clazz = Class.forName(classname);
 +7: System.out.println(clazz);
 +8: } catch (ClassNotFoundException e) { …… }
 +9: ……
 +</code>
 +동적으로 로드되는 클래스는 악성 코드일 수 있다.
 +<code | 안전한 코드 예제>
 +1: ……
 +2: public void f() {
 +3: //외부 입력으로 동적 클래스 로딩하지 않도록 한다.
 +4: TestClass tc = new TestClass();
 +5: System.out.println(tc);
 +6: …
 +</code>
 +가급적이면 동적 로딩을 사용하지 않는다. 사용해야 하는 경우 로드가 가능한 모든 클래스를 미리 정의하여 사용한다.
 +=== 라. 참고 문헌 ===
 +[1] CWE-545 동적 클래스 로딩 사용 - http://cwe.mitre.org/data/definitions/545.html