자바

JAVA 보안 개발 가이드 3

 

4. 적절하지 못한 세션 만료(Insufficient Session Expiration)

가. 정의

웹사이트에서 공격자가 인증에 사용된 기존 세션 인증 정보 또는 세션 아이디의 재사용을 허용하는 경우 발생한다.

나. 안전한 코딩기법

세션의 만료시간을 정해줄 때에는 적당한 양수를 사용하여 일정 시간이 흐르면 세션이 종료되도록 하여야 한다.

다. 예제

안전하지 않는 코드 예제


1: public class U613 extends HttpServlet {
2: public void noExpiration(HttpSession session) {
3: if (session.isNew()) {
4: // 만료시간이 -1으로 세팅되어 세션이 절대로 끝나지 않는다.
5: session.setMaxInactiveInterval(-1);
6: }
7: }
8: }

세션의 만료시간을 -1로 세팅하여, 세션이 절대로 끝나지 않도록 설정했다. 이와 같은 경우는 프로그램에 취약점을 야기할 수 있다..

안전한 코드 예제


1: public class S613 extends HttpServlet {
2: public void noExpiration(HttpSession session) {
3: if (session.isNew()) {
4: // 세션이 끝날 수 있도록 적절한 양의 정수값으로 설정한다.
5: session.setMaxInactiveInterval(12000);
6: }
7: }
8: }

애플리케이션의 특성에 따라 일정 시간이 흐르면 세션이 종료될 수 있도록 적당한 양의 정수값을 설정하여야 한다.

라. 참고 문헌

[1] CWE-613 적절하지 못한 세션 만료 - http://cwe.mitre.org/data/definitions/613.html

5. 패스워드 관리: 힙메모리 조사(Password Management: Heap Inspection)

가. 정의

보안상 중요한 데이터를 String 객체에 저장하면 보안상 위험하다. 자바의 String 객체는 수정불가능(immutable)하기 때문에, JVM의 가비지콜렉터가 동작하기 전까지 항상 메모리에 상주해 있으며, 프로그램에서 이 메모리를 해제할 수 없다. 따라서 애플리케이션의 실행이 비정상적으로 중단되어, 메모리 덤프가 일어나는 경우에 애플리케이션의 보안관련 데이터가 외부에 노출될 수 있다.

나. 안전한 코딩기법

패스워드를 String 객체에 저장하는 것은 위험하므로, 변경이 가능한 객체에 저장해야 한다. 또한 사용 후에는 내용을 메모리에서 소거해야 한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: // private static final long serialVersionUID = 1L;
3: protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
4: ……
5: }
6:
7: protected void doPost(HttpServletRequest request, HttpServletResponse response) {
8: String pass = request.getParameter("pass");
9:
10: if (pass != null) {
11: if (-1 != pass.indexOf("<"))
12: System.out.println("bad input");
13: else {
14: // 패스워드를 힙 메모리에 저장하면 취약하다.
15: String str = new String(pass);
16: }
17: } else { System.out.println("bad input"); }
18: }
19: ……

위 예제는 패스워드를 문자형 배열에서 String 타입으로 변형하여 저장함으로써 취약점이 발생한 경우이다.

안전한 코드 예제


1: ……
2: // private static final long serialVersionUID = 1L;
3: protected void doGet(HttpServletRequest request,
4: HttpServletResponse response) throws ServletException, IOException {
5: ……
6: }
7:
8: protected void doPost(HttpServletRequest request, HttpServletResponse response) {
9: // 외부로 부터 입력을 받는다.
10: String pass = request.getParameter("psw");
11: // 입력값을 체크한다.
12: if (pass != null) {
13: if (-1 != pass.indexOf("<"))
14: System.out.println("bad input");
15: else {
16: // password를 힙 메모리에 저장하지 않아야 한다..
17: //String str = new String(pass);
18: }
19: } else { System.out.println("bad input"); }
20: }
21: ……

보안상 중요한 데이터(예: 패스워드)는 ‘변경이 가능한 객체’에 저장하여 사용해야 하며, 메모리에서 소거하는 로직을 구현해야 한다. 더 이상 사용되지 않는다면 즉시 메모리에서 소거해야 한다.

라. 참고 문헌

[1] CWE-226 해제 전에 삭제되지 않은 민감한 정보 - http://cwe.mitre.org/data/definitions/226.html 
[2] OWASP Top 10 2010 - (OWASP 2010) A7 Insecure Cryptographic Storage

6. 하드코드된 사용자 계정(Hard-coded Username)

가. 정의

SW가 코드 내부에 고정된 사용자 계정 이름을 포함하고, 이를 이용하여 내부 인증에 사용하거나 외부 컴포넌트와 통신을 하는 것은 위험하다. 코드 내부에 하드코드된 사용자 계정이 인증 실패를 야기하게 되면, 시스템 관리자가 그 실패의 원인을 찾아내기가 매우 어렵다. 원인이 파악이 되더라도 하드코드된 패스워드를 수정해야 하기 때문에, 시스템 관리자는 SW 시스템 전체를 중지시켜 해결해야 하는 경우가 발생할 수 있다.

나. 안전한 코딩기법

패스워드는 암호화하여 사용하는 것이 바람직하다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: private Connection conn;
3:
4: // 계정과 비밀번호를 상수로 정의하면 취약하다.
5: public Connection DBConnect() {
6: String url = "DBServer";
7: String id = "scott" ;
8: String password = " tiger";
9:
10: try {
11: conn = DriverManager.getConnection(url, id, password);
12: } catch (SQLException e) { …… }
13: return conn;
14: }

위 예제는 코드 내부에 사용자 이름과 패스워드를 상수로 설정하여, 별도의 인증 과정없이 로그인이 가능하도록 작성되었다. 이는 프로그램에 취약점을 야기시킨다.

안전한 코드 예제


1: ……
2: private Connection conn;
3:
4: // 계정과 비밀번호는 인자로 입력 받는다.
5: public Connection DBConnect(String id, String password) {
6: String url = "DBServer";
7: try {
8: String CONNECT_STRING = url + ":" + id + ":" + password;
9: InitialContext ctx = new InitialContext();
10: DataSource datasource = (DataSource) ctx.lookup(CONNECT_STRING);
11:
12: // 입력 받은 인자로 connection을 연결한다.
13: conn = datasource.getConnection();
14: } catch (SQLException e) { …… }
15: return conn;
16: }

데이터베이스를 사용하는 프로그램 작성시 “빈 문자열”을 패스워드로 사용하는 계정이 존재하지 않도록 데이터베이스 계정을 관리한다. 또한, 사용자 계정 및 패스워드는 암․복호화하여 사용하거나 가능한 경우 필요시 사용자로부터 직접 입력 받아 사용한다.

라. 참고 문헌

[1] CWE-255 증명 관리 - http://cwe.mitre.org/data/definitions/255.html 
[2] OWASP Top 10 2010 - (OWASP 2010) A7 Insecure Cryptographic Storage 
[3] Security Technical Implementation Guide Version 3 - (STIG 3) APP3210.1 CAT II

7. 패스워드 평문 저장(Plaintext Storage of Password)

가. 정의

패스워드를 암호화되지 않은 텍스트의 형태로 저장하는 것은 시스템 손상의 원인이 될 수있다. 환경설정 파일에 평문으로 패스워드를 저장하면, 환경설정 파일에 접근할 수 있는 사람은 누구나 패스워드를 알아낼 수 있다. 패스워드는 높은 수준의 암호화 알고리즘을 사용하여 관리되어져야 한다.

나. 안전한 코딩기법

패스워드를 외부 환경 파일에 저장한다면, 암호화하여 저장하는 것이 바람직하다

다. 예제

안전하지 않는 코드 예제


1: package testbed.unsafe;
2: import java.sql.*;
3: import java.util.Properties;
4: import java.io.*;
5: public class U256 {
6: public void f(String url, String name) throws IOException {
7: Connection con = null;
8: try {
9: Properties props = new Properties();
10: FileInputStream in = new FileInputStream("External.properties");
11: byte[] pass = new byte[8];
12: // 외부 파일로부터 password를 읽는다.
13: in.read(pass);
14: // password가 DB connection의 인자변수로 그대로 사용이 된다.
15: con = DriverManager.getConnection(url, name, new String(pass));
16: con.close();
17: } catch (SQLException e) {
18: System.err.println("SQLException Occured ");
19: } finally {
20: try {
21: if (con != null)
22: con.close();
23: } catch (SQLException e) {
24: System.err.println("SQLException Occured ");
25: }
26: }
27: }
28: }

위 프로그램은 속성 파일에서 읽어들인 패스워드를 String 형태 그대로 데이터베이스를 연결하는데 사용하고 있다. 사용자가 속성 파일에 공격을 위한 문자열을 저장한 경우, 프로그램이 의도한 공격에 노출될 수 있다.

안전한 코드 예제


1: package testbed.safe;
2: import java.sql.*;
3: import java.util.Properties;
4: import java.io.*;
5: public class S256 {
6: public void f(String[] args) throws IOException {
7: Connection con = null;
8: try {
9: Properties props = new Properties();
10: FileInputStream in = new FileInputStream("External.properties");
11: props.load(in);
12: String url = props.getProperty("url");
13: String name = props.getProperty("name");
14: // 외부 파일로부터 password를 읽은 후, 복호화 한다.
15: String pass = decrypt(props.getProperty("password" ));
16: // 외부 파일로부터의 패스워드를 복호화 후 사용함.
17: con = DriverManager.getConnection(url, name, pass);
18: } catch (SQLException e) {
19: System.err.println("SQLException Occured ");
20: } finally {
21: try {
22: if (con != null)
23: con.close();
24: } catch (SQLException e) {
25: System.err.println("SQLException Occured ");
26: }
27: }
28: }
29: }

외부에서 입력된 패스워드는 사용 전에 복호화 후 사용되어야 한다.

라. 참고 문헌

[1]. CWE-256 패스워드 평문저장 - http://cwe.mitre.org/data/definitions/256.html 
[2]. J. Viega and G. McGraw. “Building Secure Software: How to Avoid Security Problems the Right Way”. 2002.

8. 설정파일에 패스워드(Password in Configuration File)

가. 정의

패스워드를 설정파일에 저장하는 것은 위험하다. 설정파일 등에 패스워드를 암호화되지 않은 상태로 저장하게 되면, 암호가 외부에 직접적으로 드러날 위험성이 있다. 따라서, 패스워드는 쉽게 접근할 수 없는 저장소에 저장하든지 아니면 암호화한 상태로 저장하여야 한다.

나. 안전한 코딩기법

패스워드를 외부 환경 파일에 저장한다면, 암호화하여 저장하는 것이 바람직하다.

다. 예제

안전하지 않는 코드 예제


1: package testbed.unsafe;
2: import java.io.FileInputStream;
3: import java.io.FileNotFoundException;
4: import java.io.IOException;
5: import java.sql.Connection;
6: import java.sql.DriverManager;
7: import java.sql.SQLException;
8: public class U260 {
9: public boolean connectTest(String url, String usr) {
10: Connection con = null;
11: byte[] b = new byte[1024];
12: boolean result = false;
13: try {
14: FileInputStream fs = new FileInputStream("sample.cfg");
15: // 외부데이터를 배열로 읽어온다.
16: fs.read(b);
17: // 패스워드 문자열을 만든다
18: String password = new String(b);
19: // 패스워드가 DB 연결정보로 사용이 된다.
20: con = DriverManager.getConnection(url, usr, password);
21: } catch (FileNotFoundException e) {
22: System.err.println("File Not Found Exception Occurred!");
23: } catch (IOException e) {
24: System.err.println("I/O Exception Occurred!");
25: } catch (SQLException e) {
26: System.err.println("SQL Exception Occurred!");
27: } finally {
28: try {
29: if (con != null) {
30: con.close();
31: result = true;
32: }
33: } catch (SQLException e) {
34: System.err.println("SQL Exception Occurred!");
35: }
36: }
37: return result;
38: }
39: }

위의 프로그램은 configuration 파일에 저장된 패스워드를 읽어서 그대로 데이터베이스 연결에 사용하고 있다. 이것은 다른 사람이 패스워드에 쉽게 접근할 수 있도록 하므로 프로그램 취약점을 유발할 수 있다.

안전한 코드 예제


1: public class S260 {
2: public boolean connectTest(String url, String usr, Key key) {
3: Connection con = null;
4: byte[] b = new byte[1024];
5: boolean result = false;
6: try {
7: FileInputStream fs = new FileInputStream("sample.cfg");
8: if (fs == null || fs.available() <= 0) return false;
9: // 외부 파일로 부터 암호화된 입력값을 받는다.
10: int length = fs.read(b);
11: if (length == 0) {
12: result = false;
13: } else {
14: // 암호화된 패스워드를 복호화한다.
15: Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding" );
16: cipher.init(Cipher.DECRYPT_MODE, key);
17: byte[] db = cipher.doFinal(b);
18: // 문자열 변환
19: String password = new String(db, "utf-8");
20: // DB 연결
21: con = DriverManager.getConnection(url, usr, password);
22: }
23: } catch (FileNotFoundException e) {
24: System.err.println("File Not Found Exception Occurred!");
25: } catch (IOException e) {
26: System.err.println("I/O Exception Occurred!");
27: } catch (SQLException e) {
28: System.err.println("SQL Exception Occurred!");
29: } catch (NoSuchAlgorithmException e) {
30: System.err.println("NoSuchAlgorithmException Occurred!");
31: } catch (NoSuchPaddingException e) {
32: System.err.println("NoSuchPaddingException Occurred!");
33: } catch (InvalidKeyException e) {
34: System.err.println("InvalidKeyException Occurred!");
35: } catch (IllegalBlockSizeException e) {
36: System.err.println("IllegalBlockSizeException Occurred!");
37: } catch (BadPaddingException e) {
38: System.err.println("BadPaddingException Occurred!");
39: } finally {
40: try {
41: if (con != null) {
42: con.close();
43: result = true; } } catch (SQLException e) {
44: System.err.println("SQL Exception Occurred!");
45: } } return result; } }

외부에 저장된 패스워드(예를 들어, 환경파일)를 데이터베이스 연결에 사용하는 경우, 읽어들인 패스워드를 검증하거나 추가적인 정보로 가공하는 로직을 거쳐서 사용해야 한다.

라. 참고 문헌

[1] CWE-260 설정파일에 패스워드 - http://cwe.mitre.org/data/definitions/260.html 
[2]. J. Viega and G. McGraw. “Building Secure Software: How to Avoid Security Problems the Right Way”. 2002.

9. 패스워드에 사용된 취약한 암호화(Weak Cryptography for Passwords)

가. 정의

SW 개발자들은 환경설정 파일에 저장된 패스워드를 보호하기 위하여 간단한 인코딩 함수를 이용하여 패스워드를 감추는 방법을 사용하기도 한다. 그렇지만 base64와 같은 지나치게 간단한 인코딩 함수를 사용하는 것은 패스워드를 제대로 보호할 수 없다.

나. 안전한 코딩기법

패스워드를 인코딩하기 위해서는 이미 취약점이 알려진 인코딩 방법이나 검증되지 않은 인코딩 방법을 사용하면 안된다. 패스워드는 최소한 128비트 길이의 키를 이용하여 암호화하는 것이 바람직하다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public boolean DBConnect() throws SQLException {
3: String url = "DBServer";
4: String usr = "Scott";
5: Connection con = null;
6:
7: try {
8: Properties prop = new Properties();
9: prop.load(new FileInputStream("config.properties"));
10:
11: // 패스워드를 64bit로 decoding한다.
12: byte password[] = Base64.decode(prop.getProperty("password" ));
13:
14: // 유효성 점검없이 패스워드를 문자열로 읽는다.
15: con = DriverManager.getConnection(url, usr, password.toString());
16: } catch (FileNotFoundException e) {
17: e.printStackTrace();
18: } catch (IOException e) {
19: e.printStackTrace();
20: }
21: }

패스워드를 base64로 인코딩하여 configuration 파일에 저장한 경우이다. Basea64 인코딩 기법 자체가 가지는 취약점 때문에 이 경우 패스워드를 안전하게 보호할 수 없다.

안전한 코드 예제


1: ……
2: public boolean DBConnect() throws SQLException {
3: String url = "DBServer";
4: String usr = "Scott";
5: Connection con = null;
6:
7: try {
8: Properties prop = new Properties();
9: prop.load(new FileInputStream("config.properties"));
10:
11: // 패스워드를 AES 알고리즘 기반의 복호화 코드로 암호화 한다.
12: String password = decrypt(prop.getProperty("password" ));
13:
14: con = DriverManager.getConnection(url, usr, password);
15: } catch (FileNotFoundException e) {
16: e.printStackTrace();
17: } catch (IOException e) {
18: e.printStackTrace();
19: }
20: }
21: private static String decrypt(String encrypted) throws Exception {
22: SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");
23: Cipher cipher = Cipher.getInstance("AES");
24: cipher.init(Cipher.DECRYPT_MODE, skeySpec);
25: byte[] original = cipher.doFinal(hexToByteArray(encrypted));
26: return new String(original);
27: }

패스워드를 사용하는 경우에는 최소한 128비트 길이의 키를 이용하여 암호화하는 것이 바람직하다.

라. 참고 문헌

[1] CWE-261 패스워드에 사용된 취약한 암호화 - http://cwe.mitre.org/data/definitions/261.html 
[2] OWASP Top 10 2010 - (OWASP 2010) A7 Insecure Cryptographic Storage 
[3] J. Viega and G. McGraw. “Building Secure Software: How to Avoid Security Problems the Right Way”. 2002.

10. 중요한 함수 사용 시 자격인증 미비(Missing Authentication for Critical Function)

가. 정의

사용자의 신원이 요구되는 기능이나 상당한 자원을 소모하는 기능을 사용할 때, SW가 사용자의 자격인증 과정을 수행하지 않게 된다.

나. 안전한 코딩기법

  • 클라이언트의 보안검사를 우회하여 서버에 접근하지 못하도록 한다.

  • 중요한 정보가 있는 페이지는 재인증이 적용되도록 설계하여야 한다(은행 계좌이체 등).


※ 안전하다고 확인된 라이브러리나 프레임워크를 사용한다. 즉 OpenSSL이나 ESAPI의 보안 기능을 사용한다.

다. 예제

안전하지 않는 코드 예제


1: public void sendBankAccount(String accountNumber,double balance) {
2: ...
3: BankAccount account = new BankAccount();
4: account.setAccountNumber(accountNumber);
5: account.setToPerson(toPerson);
6: account.setBalance(balance);
7: AccountManager.send(account);
8: ...
9: }

재 인증을 거치지 않고 계좌 이체를 하고 있다.

안전한 코드 예제


1: public void sendBankAccount(HttpServletRequest request, HttpSession session,
2: String accountNumber,double balance) {
3: ...
4: // 재인증을 위한 팝업 화면을 통해 사용자의 credential을 받는다.
5: String newUserName = request.getParameter("username");
6: String newPassword = request.getParameter("password");
7: if ( newUserName == null || newPassword == null ) {
8: throw new MyEception("데이터 오류:);
9: }
10:
11: // 세션으로부터 로긴한 사용자의 credential을 읽는다.
12: String password = session.getValue("password");
13: String userName = session.getValue("username");
14:
15: // 재인증을 통해서 이체여부를 판단한다.
16: if ( isAuthenticatedUser() && newUserName.equal(userName) &&
17: newPassword.equal(password) ) {
18: BankAccount account = new BankAccount();
19: account.setAccountNumber(accountNumber);
20: account.setToPerson(toPerson);
21: account.setBalance(balance);
22: AccountManager.send(account);
23: }
24: ...
25: }

인증을 수행된 사용자만이 다시 재인증을 거쳐 계좌 이체가 가능하도록 한다.

라. 참고 문헌

[1] CWE-306 중요한 함수 사용시 자격인증 미비 - http://cwe.mitre.org/data/definitions/306.html 
CWE-302 허위-불변 데이터로 인증우회 - http://cwe.mitre.org/data/definitions/302.html 
CWE-307 과도한 인증 시도 제한실패 - http://cwe.mitre.org/data/definitions/307.html 
CWE-287 부적절한 인가 - http://cwe.mitre.org/data/definitions/287.html 
CWE-602 서버단 보안에 클라이언트단 보안강제 - http://cwe.mitre.org/data/definitions/602.html 
[2] CWE/SANS Top 25 Most Dangerous Software Errors, http://cwe.mitre.org/top25/

11. 취약한 암호화: 충분하지 못한 키의 길이(Weak Encryption: Insufficient Key Size)

가. 정의

길이가 짧은 키를 사용하는 것은 암호화 알고리즘을 취약하게 만들 수 있다. 현재 RSA 알고리즘은 적어도 1024 비트 이상의 길이를 가진 키와 함께 사용해야 한다고 알려져 있다. 
Symmetric 암호화의 경우에는 적어도 128비트 이상의 키를 사용하는 것이 바람직하다.

나. 안전한 코딩기법

  • 최소한 1024 비트 이상의 키를 사용하는 것이 바람직하다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public void target() throws NoSuchAlgorithmException {
3: KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
4: // Key generator의 불충분한 키 크기
5: keyGen.initialize(512);
6: KeyPair myKeys = keyGen.generateKeyPair();
7: }

위 예제는 보안성이 강한 RSA 알고리즘을 사용함에도 불구하고, 키 사이즈를 작게 설정함으로써 프로그램의 취약점을 야기한 경우이다.

안전한 코드 예제


1: ……
2: public void target() throws NoSuchAlgorithmException {
3: KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
4: // Key generator의 값은 최소 1024bit로 설정한다.
5: keyGen.initialize(1024);
6: KeyPair myKeys = keyGen.generateKeyPair();
7: }

암호화에 사용하는 키의 길이는 적어도 1024비트 이상으로 설정한다.

라. 참고 문헌

[1] CWE-310 암호화 이슈 - http://cwe.mitre.org/data/definitions/310.html 
[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을 사용한다.

다. 예제

안전하지 않는 코드 예제


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: }

인증을 통과한 사용자의 패스워드 정보가 평문으로 DB에 저장된다.

안전한 코드 예제


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: }

패스워드 등 중요 데이터를 해쉬값으로 변환하여 저장한다.

라. 참고 문헌

[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/

11. 취약한 암호화: 충분하지 못한 키의 길이(Weak Encryption: Insufficient Key Size)

가. 정의

길이가 짧은 키를 사용하는 것은 암호화 알고리즘을 취약하게 만들 수 있다. 현재 RSA 알고리즘은 적어도 1024 비트 이상의 길이를 가진 키와 함께 사용해야 한다고 알려져 있다. 
Symmetric 암호화의 경우에는 적어도 128비트 이상의 키를 사용하는 것이 바람직하다.

나. 안전한 코딩기법

최소한 1024 비트 이상의 키를 사용하는 것이 바람직하다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public void target() throws NoSuchAlgorithmException {
3: KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
4: // Key generator의 불충분한 키 크기
5: keyGen.initialize(512);
6: KeyPair myKeys = keyGen.generateKeyPair();
7: }

위 예제는 보안성이 강한 RSA 알고리즘을 사용함에도 불구하고, 키 사이즈를 작게 설정함으로써 프로그램의 취약점을 야기한 경우이다.

안전한 코드 예제


1: ……
2: public void target() throws NoSuchAlgorithmException {
3: KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
4: // Key generator의 값은 최소 1024bit로 설정한다.
5: keyGen.initialize(1024);
6: KeyPair myKeys = keyGen.generateKeyPair();
7: }

암호화에 사용하는 키의 길이는 적어도 1024비트 이상으로 설정한다.

라. 참고 문헌

[1] CWE-310 암호화 이슈 - http://cwe.mitre.org/data/definitions/310.html 
[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을 사용한다.

다. 예제

안전하지 않는 코드 예제


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: }

인증을 통과한 사용자의 패스워드 정보가 평문으로 DB에 저장된다.

안전한 코드 예제


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: }

패스워드 등 중요 데이터를 해쉬값으로 변환하여 저장한다.

라. 참고 문헌

[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가 보안과 관련된 민감한 데이터를 명백한 텍스트의 형태로 통신 채널을 통해서 보내는 경우, 인증받지 않은 주체에 의해서 스니핑이 일어날 수 있다.

나. 안전한 코딩기법

민감한 정보를 통신 채널을 통하여 내보낼 때는 반드시 암호화 과정을 거쳐야 한다.

다. 예제

안전하지 않는 코드 예제


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: }

속성 파일에서 읽어들인 패스워드(Plain text)를 네트워크를 통하여 서버에 전송하고 있다. 
이 경우 패킷 스니핑을 통하여 패스워드가 노출될 수 있다.

안전한 코드 예제


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: }

패스워드를 네트워크를 통하여 서버에 전송하기 전에 최소한 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은 사용하지 말아야 한다.

다. 예제

안전하지 않는 코드 예제


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: }

암호화에 사용되는 키를 상수의 형태로 코드 내부에서 사용하는 것은 프로그램 소스가 노출되는 경우 암호화 키도 동시에 노출되는 취약점을 가지게 된다.

안전한 코드 예제


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:

암호화된 패스워드를 복호화하기 위하여 사용되는 암호화 키도 코드 내부에 상수형태로 정의해서 사용하면 안된다.

라. 참고 문헌

[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”)하지 말고, 암호화 알고리즘에 적합한 패딩과 함께 사용해야 한다.

다. 예제

안전하지 않는 코드 예제


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: }

위 예제는 충분한 패딩없이 RSA 알고리즘을 사용하여 프로그램에 취약점하게 만드는 경우이다.

안전한 코드 예제


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: }

사용하는 알고리즘에 따라 알려져 있는 적절한 패딩방식을 사용해야 한다. 예를 들어 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)값으로는 예측하기 어려운 난수를 사용하며, 특정한 값의 재사용은 금지해야 한다.

다. 예제

안전하지 않는 코드 예제


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: }

위 예제는 암호화된 해쉬함수를 사용할 때, 상수로 정의된 salt를 사용함으로써 취약점을 야기하는 경우이다.

안전한 코드 예제


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: }

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처럼 보다 강력한 암호화 알고리즘을 사용하는 것이 바람직하다.

다. 예제

안전하지 않는 코드 예제


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: }

암호화 알고리즘 중에서 DES 알고리즘을 사용하는 것은 안전하지 않다.

안전한 코드 예제


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: }

취약하다고 알려진 알고리즘 대신 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를 사용하는 경우에는 예측하기 어려운 방법으로 변경하여 사용하는 것이 바람직하다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public double roledice() {
3: return Math.random();
4: }
5: }

java.lang.Math 클래스의 random() 메소드는 seed를 재설정할 수 없기 때문에 위험하다.

안전한 코드 예제


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: }

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 방식으로 파라미터를 전달해야 한다.

다. 예제

안전하지 않는 코드 예제


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: }

위 예제는 HTTP 요청(Request)을 GET 방식으로 재전송함으로써 프로그램울 취약하게 만드는 경우이다.

안전한 코드 예제


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: }

다른 페이지로 보안에 민감한 정보를 보낼 때는 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)

가. 정의

사용자에게 강한 패스워드를 요구하지 않으면, 결국 공격자가 사용자 계정을 뚫기 쉽게 만 들며, 사용자 계정을 보호하기 힘들다.

나. 안전한 코딩기법

패스워드에 대한 검증을 통해 보안성이 높은 문자열을 입력하도록 유도한다.

다. 예제

안전하지 않는 코드 예제


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: }

신뢰할 수 없는 외부입력으로부터 할당된 변수(passwd)가 검증 과정없이 패스워드로 사용되는 문장이다.

안전한 코드 예제


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: }

패스워드(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)

가. 정의

보안상 민감한 데이터를 영속적인 쿠키에 저장하는 것은 시스템 보안을 취약하게 만든다. 
대부분의 웹 응용프로그램에서 쿠키는 메모리에 상주하며, 브라우저의 실행이 종료되면 사라진다. 프로그래머가 원하는 경우, 브라우저 세션에 관계없이 계속적으로 지속되도록 설정할 수 있으며, 이것은 디스크에 기록되고 다음 브라우저 세션이 시작되었을 때 메모리에 로드된다. 만약 개인 정보 등의 이런 형태의 영속적인 쿠키에 저장된다면, 공격자는 쿠키에 접근할 수 있는 보다 많은 기회를 가지게 되며, 이는 시스템을 취약하게 만든다.

나. 안전한 코딩기법

쿠키의 만료시간은 세션이 지속되는 시간과 관련하여 최소한으로 설정해야 한다.

다. 예제

안전하지 않는 코드 예제


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: }

javax.servlet.http.Cookie.setMaxAge 메소드 호출에 외부의 입력이 쿠키의 유효시한 설정에 그대로 사용되어 프로그램의 취약점을 야기하는 경우이다.

 

PHRASE

Level 60  머나먼나라

군사란 승리가 보이면, 강해지지만 패기를 보면 약해진다. -손자병법

댓글 ( 4)

댓글 남기기

작성

자바 목록    more