자바

JAVA 보안 개발 가이드 2

 

18. 무제한 파일 업로드(Unrestricted Upload of File with Dangerous Type)

가. 정의

운영 환경 내에서 자동으로 처리될 수 있는 위험한 유형의 파일을 공격자가 업로드하거나 전송할 수 있게 허용하면 취약점을 야기할 수 있다.

나. 안전한 코딩기법

업로드하는 파일 타입과 크기를 제한하고, 업로드 디렉터리를 웹서버의 다큐먼트 외부에 설정한다. 
화이트리스트 방식으로 허용된 확장자만 업로드되도록 하고, 확장자도 대소문자 구분 없이 처리하도록 한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public void upload(HttpServletRequest request) throws ServletException {
3: MultipartHttpServletRequest mRequest = (MultipartHttpServletRequest) request;
4: String next = (String) mRequest.getFileNames().next();
5: MultipartFile file = mRequest.getFile(next);
6:
7: // MultipartFile로부터 file을 얻음
8: String fileName = file.getOriginalFilename();
9:
10: // upload 파일에 대한 확장자, 크기의 유효성 체크를 하지 않음
11: File uploadDir = new File("/app/webapp/data/upload/notice");
12: String uploadFilePath = uploadDir.getAbsolutePath()+"/" + fileName;
13:
14: /* 이하 file upload 루틴 */
15: ……

업로드할 파일에 대한 유효성을 검사하지 않으면, 위험한 유형의 파일을 공격자가 업로드하거나 전송할 수 있다.

안전한 코드 예제


1: ……
2: public void upload(HttpServletRequest request) throws ServletException {
3: MultipartHttpServletRequest mRequest = (MultipartHttpServletRequest) request;
4: String next = (String) mRequest.getFileNames().next();
5: MultipartFile file = mRequest.getFile(next);
6: if ( file == null )
7: return ;
8:
9: // 업로드 파일 크기를 제한한다.
10: int size = file.getSize();
11: if ( size > MAX_FILE_SIZE ) throw new ServletException("에러“);
12:
13: // MultipartFile로 부터 file을 얻음
14: String fileName = file.getOriginalFilename().toLowerCase();
15:
16: // 화이트리스트 방식으로 업로드 파일의 확장자를 체크한다.
17: if ( fileName != null ) {
18: if ( fileName.endsWith(".doc") || fileName.endsWith(".hwp" )
19: || fileName.endsWith(" .pdf") || fileName.endsWith(".xls" ) ) {
20: /* file 업로드 루틴 */
21: }
22: else throw new ServletExeption("에러");
23: }
24: // 업로드 파일의 디렉터리 위치는 다큐먼트 루트의 밖에 위치시킨다.
25: File uploadDir = new File("/app/webapp/data/upload/notice");
26: String uploadFilePath = uploadDir.getAbsolutePath()+"/" + fileName;
27:
28: /* 이하 file upload 루틴 */
29: ……

위의 예제는 업로드 파일의 크기와 위치를 제한하고 있다. 또한 파일의 확장자를 검사하여 허용되지 않은 확장자일 경우 업로드를 제한하고 있다.

라. 참고 문헌

[1] CWE-434 무제한 파일 업로드 - http://cwe.mitre.org/data/definitions/434.html 
[2] OWASP Top Ten 2007 A3, Malicious File Execution 
[3] SANS Top 25 2010 - (SANS 2010) Insecure Interaction - CWE ID 434 Unrestricted Upload of File with Dangerous Type

19. 안전하지 않은 리플렉션(Use of Externally-Controlled Input to Select Classes or Code ('Unsafe Reflection'))

가. 정의

동적 클래스 적재(loading)에 외부의 검증되지 않은 입력을 사용할 경우, 공격자가 외부 입력을 변조하여 의도하지 않은 클래스가 적재되도록 할 수 있다.

나. 안전한 코딩기법

외부의 입력을 직접 클래스 이름으로 사용하지 말고, 외부의 입력에 따라 미리 정한 후보(white list) 중에서 적절한 클래스 이름을 선택하도록 한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public void f() {
3: Properties props = new Properties();
4: ....
5: if ( in !=null && in.available() > 0 ) {
6: props.load(in);
7: if ( props == null || props.isEmpty() )
8: return ;
9: }
10: String type = props.getProperty("type");
11: Worker w;
12:
13: // 외부에서 입력된 type값의 유효성을 검증하지 않고 있다.
14: try {
15: Class workClass = Class.forName(type + "Worker");
16: w = (Worker) workClass.newInstance();
17: w.doAction();
18: } catch (ClassNotFoundException e) { …… }
19: ……
20: }
21:
22: abstract class Worker {
23: String work = "";
24: public abstract void doAction();
25: }

위의 예제는 외부의 입력(type)을 클래스 이름의 일부로 사용하여 객체를 생성하고 있다. 
이 경우 공격자가 외부 입력을 변조하여 부적절한 다른 클래스가 적재되도록 할 수 있다.

안전한 코드 예제


1: ……
2: public void f() {
3: Properties props = new Properties();
4: ....
5: if ( in !=null && in.available() > 0 ) {
6: props.load(in);
7: if ( props == null || props.isEmpty() )
8: return ;
9: }
10: String type = props.getProperty("type");
11: Worker w;
12:
13: // 외부 입력되는 값에 대해 유효성을 검증하여야한다.
14: if (type == null || "".equals(type)) return;
15: if (type.equals("Slow" )) {
16: w = new SlowWorker();
17: w.doAction();
18: } else if (type.equals("Hard" )) {
19: w = new HardWorker();
20: w.doAction();
21: } else {
22: System.err.printf("No propper class name!");
23: }
24: ……
25: }
26:
27: abstract class Worker {
28: String work = "";
29: public abstract void doAction();
30: }

외부의 입력(type)에 따라, 미리 정한 후보(white list) 중에서 적절한 클래스 이름이 설정되도록 함으로써, 외부의 악의적인 입력에 의하여 부적절한 클래스가 사용되는 위험성을 제거할 수 있다.

라. 참고 문헌

[1] CWE-470 안전하지 않은 리플렉션 - http://cwe.mitre.org/data/definitions/470.html

20. 무결성 점검 없는 코드 다운로드(Download of Code Without Integrity Check)

가. 정의

웹서버에서 수행될 수 있는 위험한 형식의 파일을 원격지로부터 다운로드하여, 코드의 출처나 무결성 검사없이 클라이언트에서 실행하는 경우 공격자가 의도하는 행위를 수행할 수 있다.

나. 안전한 코딩기법

SW의 자동 업데이트와 같이 다운로드될 코드를 제공할 때는 코드에 대한 암호화된 시그너쳐를 사용하고 클라이언트가 시그너쳐를 검증하도록 한다.

다. 예제

안전하지 않는 코드 예제


1: URL[] classURLs= new URL[]{new URL("file:subdir/")};
2: URLClassLoader loader = new URLClassLoader(classURLs);
3: Class loadedClass = Class.forName("MyClass", true, loader);

위의 프로그램은 URLClassLoader를 사용하여, 원격의 파일을 다운로드 한다. 다운로드 대상 파일에 대한 무결성 검사를 수행하지 않을 경우, 파일변조 등으로 피해가 발생할 수 있다.

안전한 코드 예제


1: // 서버에서는 private key를 가지고 MyClass를 암호화한다.
2: String jarFile = "./download/util.jar";
3: byte[] loadFile = FileManager.getBytes(jarFile);
4: loadFile = encrypt(loadFile,privateKey);
5: // jarFile명으로 암호화된 파일을 생성한다.
6: FileManager.createFile(loadFile,jarFileName);
7: ....
8: // 클라이언트에서는 파일을 다운로드 받을 경우 public key로 복호화 한다.
9: URL[] classURLs= new URL[]{new URL("http://filesave.com/download/util.jar")};
10: URLConnection conn=classURLs.openConnection();
11: InputStream is = conn.getInputStream();
12: // 입력 스트림을 읽어 서버의 jarFile명으로 파일을 출력한다.
13: FileOutputStream fos = new FileOutputStream(new File(jarFile));
14: while ( is.read(buf) != -1 ) {
15: ...
16: }
17: byte[] loadFile = FileManager.getBytes(jarFile);
18: loadFile = decrypt(loadFile,publicKey);
19: // 복호화된 파일을 생성한다.
20: FileManager.createFile(loadFile,jarFile);
21: URLClassLoader loader = new URLClassLoader(classURLs);
22: Class loadedClass = Class.forName("MyClass", true, loader);

공개키 방식의 암호알고리즘과 메커니즘을 이용하여 전송파일에 대한 시그니처를 생성하고, 파일의 변조유무를 판단한다.

라. 참고 문헌

[1] CWE-494 무결성 점검 없는 코드 다운로드 - http://cwe.mitre.org/data/definitions/494.html 
[2] SANS Top 25 Most Dangerous Software Errors, http://www.sans.org/top25-software-errors/ 
[3] Richard Stanway (r1CH). “Dynamic File Uploads, Security and You 
[4] Johannes Ullrich. “8 Basic Rules to Implement Secure File Uploads”. 2009-12-28

21. SQL 삽입 공격: Hibernate(SQL Injection: Hibernate)

가. 정의

외부의 신뢰할 수 없는 입력을 적절한 검사 과정을 거치지 않고 Hibernate API의 SQL 질의문 생성을 위한 문자열로 사용하면, 공격자가 프로그래머가 의도하지 않았던 문자열을 전달함으로써 질의문의 의미를 왜곡시키거나 그 구조를 변경하여 임의의 데이터베이스 명령어가 수행되도록 할 수 있다.

나. 안전한 코딩기법

질의문의 생성시 상수 문자열만 사용한다. 외부의 입력에 따라 질의문을 수정해야 한다면 인자를 받는 질의문을 상수 문자열로 생성한 후, 쿼리의 인자값을 setParameter(), set<타입이름>() 등의 메소드를 사용하여 설정한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public void listHoney() {
3: Session session = new Configuration().configure().buildSessionFactory().openSession();
4: try {
5: Properties props = new Properties();
6: String fileName = "Hibernate.properties";
7: FileInputStream in = new FileInputStream(fileName);
8: props.load(in);
9: ……
10: // 외부로부터 입력을 받음
11: String idValue = props.getProperty(" idLow" );
12: // 외부 입력을 검증없이 SQL qeuery문의 인자로 사용한다.
13: Query query = session.createQuery("from Address a where a.name='" + idValue);
14: query.list();
15: } catch (IOException e) { …… }
16: ……

위의 예제는 외부의 입력(idValue)을 아무 검증과정 없이 질의문에 그대로 사용하고 있다. 
만일, 외부의 입력으로 “n' or '1'='1” 과 같은 문자열이 입력되면, 다음과 같은 질의문이 생성되어 테이블 내의 모든 레코드가 반환된다. 


("from Address a where a.name='n' or '1'='1'")

안전한 코드 예제


1: ……
2: public void listHoney() {
3: Session session = new Configuration().configure().buildSessionFactory().openSession();
4: try {
5: Properties props = new Properties();
6: String fileName = "Hibernate.properties";
7: FileInputStream in = new FileInputStream(fileName);
8: if (in == null || in.available() <= 0) return;
9: props.load(in);
10: ……
11: // 외부로 부터 입력을 받는다.
12: String idValue = props.getProperty("idLow");
13: // 입력값에 대한 유효성을 검사한다.
14: if (idValue == null || " " .equals(idValue)) idValue = "defaultID";
15: // SQL query 문장을 작성한다.
16: Query query = session.createSQLQuery("select h from Honey as h where h.id '= :idVal‘");
17: query.setParameter(" idVal", idValue);
18: query.list();
19: } catch (IOException e) { …… }
20: ……

외부 입력(idValue)에 따른 인자값은 setParameter 메소드를 사용하여 설정함으로써 질의문의 구조가 바뀌는 것을 방지할 수 있다.

라. 참고 문헌

[1] CWE-564 SQL 삽입 공격: Hibernate - http://cwe.mitre.org/data/definitions/564.html 
[2] SANS Top 25 2009 - (SANS 2009) Insecure Interaction - CWE ID 116 Improper Encoding or Escaping of Output

22. 신뢰되지 않는 URL 주소로의 자동 접속 연결(URL Redirection to Untrusted Site ('Open Redirect'))

가. 정의

외부로부터 받은 문자열을 URL 주소로 사용하여 자동으로 연결하는 서버 프로그램은 취약점을 가질 수 있다. 일반적으로 클라이언트에게 전송된 폼으로부터 전송된 URL 주소로 연결하기 때문에 안전하다고 생각할 수 있으나, 해당 폼의 요청을 변조함으로써 공격자는 희생자가 위험한 URL로 접속할 수 있도록 공격할 수 있다.

나. 안전한 코딩기법

타 사이트로의 자동전환에 사용할 URL과 도메인들의 화이트리스트를 사용한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: protected void doGet(HttpServletRequest request, HttpServletResponse response)
3: throws ServletException, IOException {
4: String query = request.getQueryString();
5: if (query.contains("url")) {
6: String url = request.getParameter("url" );
7: response.sendRedirect(url);
8: }	
9: ……

위의 코드가 서버에 존재할 경우 공격자가 다음과 같은 링크를 희생자가 접근하도록 함으로써 희생자가 의도치 않는 사이트(피싱 사이트 등)로 접근하도록 만들 수 있다. 


(<a href="http://bank.example.com/redirect?url=http://attacker.example.net">Click here to log in</a>)

안전한 코드 예제


1: ……
2: protected void doGet(HttpServletRequest request, HttpServletResponse response)
3: throws ServletException, IOException {
4: String query = request.getQueryString();
5:
6: // 다른 페이지 이동하는 URL 리스트를 만든다.
7: String allowURL[] = { "url1", "url2", "url3" };
8: ArrayList arr = new ArrayList();
9: for ( int i = 0; i < allowURL.length; i++ )
10: arr.add(allowURL[i]);
11:
12: if (query.contains("url")) {
13: String url = request.getParameter("url");
14: // url에 대한 유효성 점검을 한다. 만약 http://가 있으면 다른 도메인으로 URL을
redirect로 의심된다.
15: if (url != null && url.indexOf("http://") != -1 ) {
16: url = url.replaceAll("\r", "").replaceAll("\n", "");
17: // URL 목록에 있지 않으면 요청을 거부한다.
18: if ( !arr.contains(url) ) throw new MyException("에러“);
19: response.sendRedirect(url);
20: }
21: }
22: ……

접근할 URL 주소를 외부에서 직접 받는 것이 아니라, 허용할 URL과 도메인들의 화이트리스트를 작성한 다음 그 중에서 선택함으로써 악의적인 사이트 접근을 근원적으로 차단할 수 있다.

라. 참고 문헌

[1] CWE-601 신뢰되지 않는 URL 주소로의 자동 접속 연결 - http://cwe.mitre.org/data/definitions/601.html 
[2] OWASP Top Ten 2010 Category A10 - Unvalidated Redirects and Forward 
[3] SANS 2010 Top 25 - Insecure Interaction Between Components

23. XPath 삽입(Failure to Sanitize Data within XPath Expressions (XPath injection))

가. 정의

외부의 신뢰할 수 없는 입력을 적절한 검사 과정을 거치지 않고 XPath 질의문 생성을 위한 문자열로 사용하면, 공격자가 프로그래머가 의도하지 않았던 문자열을 전달함으로써 질의문의 의미를 왜곡시키거나 그 구조를 변경하고 임의의 질의 명령어를 수행할 수 있다.

나. 안전한 코딩기법

기본 질의문 골격에 인자값을 설정하는 인자화된 질의문을 사용할 수 있는 XQuery 등을 사용한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: // 외부로 부터 입력을 받음
3: String name = props.getProperty("name" );
4: String passwd = props.getProperty("password" );
5: ……
6: XPathFactory factory = XPathFactory.newInstance();
7: XPath xpath = factory.newXPath();
8: ……
9: // 외부 입력이 xpath의 인자로 사용
10: XPathExpression expr = xpath.compile("//users/user[login/text()='" + name
11: + "' and password/text() = '" + passwd + "']/home_dir/text()");
12: Object result = expr.evaluate(doc, XPathConstants.NODESET);
13: NodeList nodes = (NodeList) result;
14: for (int i = 0; i < nodes.getLength(); i++) {
15: String value = nodes.item(i).getNodeValue();
16: if (value.indexOf(">") < 0) {
17: System.out.println(value);
18: }
19: ……

위의 예제에서 name의 값으로 “user1”, passwd의 값으로 “' or ='”을 전달하면 다음과 같은 질의문이 생성되어 인증과정을 거치지 않고 로그인할 수 있다. 
(/users/user[login/text()=‘user1' or 
='' and password/text() = “ or ”=“]/home_dir/text())

안전한 코드 예제


dologin.xp 파일
1: declare variable $loginID as xs:string external;
2: declare variable $password as xs:string external;
3: //users/user[@loginID=$loginID and @password=$password]
XQuery를 이용한 XPath Injection 방지
1: // 외부로 부터 입력을 받음
2: String name = props.getProperty("name");
3: String passwd = props.getProperty("password");
4: Document doc = new Builder().build("users.xml");
5: // XQuery를 위한 정보 로딩
6: XQuery xquery = new XQueryFactory().createXQuery(new File("dologin.xq" ));
7: Map vars = new HashMap();
8: vars.put("loginID", name);
9: vars.put("password", passwd);
10: Nodes results = xquery.execute(doc, null, vars).toNodes();
11: for (int i=0; i < results.size(); i++) {
12: System.out.println(results.get(i).toXML());
13: }

위와 예제와 같이 인자화된 질의문을 지원하는 XQuery를 사용하여 미리 질의 골격을 생성하고 이에 인자값을 설정함으로써 외부의 입력으로 인하여 질의 구조가 바뀌는 것을 막을 수 있다.

라. 참고 문헌

[1] CWE-643 XPath 삽입 - http://cwe.mitre.org/data/definitions/643.html 
[2] OWASP Top 10 2010 A1 Injection Flaws 
[3] Web Application Security Consortium. “XPath Injection”. 
http://www.webappsec.org/projects/threat/classes/xpath_injection.shtml

24. XQuery 삽입(Failure to Sanitize Data within XQuery Expressions (XQuery injection))

가. 정의

XQuery를 사용하여 XML 데이터에 접근하는 응용프로그램에서 외부의 입력이 질의문 문자열을 생성하는데 사용될 경우에, 공격자는 프로그래머가 의도하지 않았던 문자열을 전달함으로써 질의문의 의미를 왜곡시키거나 그 구조를 변경하여 임의의 질의 명령어를 수행할 수 있다.

나. 안전한 코딩기법

prepareExpression() 메소드에 상수 문자열을 사용하여 인자를 받는 질의문(Parameterized Query)을 생성하고, 나중에 인자를 설정함으로써 질의 구조의 변형을 방지한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: // 외부로 부터 입력을 받음
3: String name = props.getProperty("name" );
4: Hashtable env = new Hashtable();
5: env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
6: env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=rootDir");
7: javax.naming.directory.DirContext ctx = new InitialDirContext(env);
8: javax.xml.xquery.XQDataSource xqds =
9: (javax.xml.xquery.XQDataSource) ctx.lookup("xqj/personnel");
10: javax.xml.xquery.XQConnection conn = xqds.getConnection();
11:
12: String es = "doc('users.xml')/userlist/user[uname='" + name + "']";
13: // 입력값이 Xquery의 인자로 사용
14: XQPreparedExpression expr = conn.prepareExpression(es);
15: XQResultSequence result = expr.executeQuery();
16: while (result.next()) {
17: String str = result.getAtomicValue();
18: if (str.indexOf('>') < 0) {
19: System.out.println(str);
20: }
21: ……

위의 예제는 외부의 입력(name)값을 executeQuery를 사용한 질의생성의 문자열 인자 생성에 사용하고 있다. 만일 다음과 something' or '='1 을 name의 값으로 전달하면 아래와 같은 질의문을 수행할 수 있으며, 이를 통해 파일 내의 모든 값을 출력할 수 있게 된다. 


(doc('users.xml')/userlist/user[uname='something' or '=')

안전한 코드 예제


1: ……
2: // 외부로 부터 입력을 받음
3: String name = props.getProperty("name");
4: Hashtable env = new Hashtable();
5: env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
6: env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=rootDir");
7: javax.naming.directory.DirContext ctx = new InitialDirContext(env);
8: javax.xml.xquery.XQDataSource xqds =
9: (javax.xml.xquery.XQDataSource) ctx.lookup("xqj/personnel");
10: javax.xml.xquery.XQConnection conn = xqds.getConnection();
11:
12: String es = "doc('users.xml')/userlist/user[uname='$xpathname']";
13: // 입력값이 Xquery의 인자로 사용
14: XQPreparedExpression expr = conn.prepareExpression(es);
15: expr.bindString(new QName("xpathname"), name, null);
16: XQResultSequence result = expr.executeQuery();
17: while (result.next()) {
18: String str = result.getAtomicValue();
19: if (str.indexOf('>') < 0) {
20: System.out.println(str);
21: }
22: ……

위와 같이 외부입력 값을 받고 해당 값 기반의 XQuery상의 질의 구조를 변경시키지 않는 bindXXX 함수를 이용함으로써 외부의 입력으로 인하여 질의 구조가 바뀌는 것을 막을 수 있다.

라. 참고 문헌

[1] CWE-652 XQuery 삽입 - http://cwe.mitre.org/data/definitions/652.html 
[2] OWASP Top 10 2010 A1 Injection Flaws

25. 보안결정을 신뢰할 수 없는 입력 값에 의존(Reliance on Untrusted Inputs in a Security Decision)

가. 정의

응용프로그램의 보안결정이 입력값의 내용에 의지하는 경우에 발생하는 취약점이다. 
입력값이 신뢰할 수 없는 사용자에 의해서 변조되는 경우 응용프로그램의 보호수단을 피해갈 수 있는 방법을 제공하게 된다.

나. 안전한 코딩기법

시스템의 상태정보와 중요한 정보는 서버에만 저장한다. 
중요한 정보를 클라이언트 쪽에 저장할 경우, 암호화와 무결성 검사를 거친 데이터만 저장되도록 한다. 
외부입력과 관련된 검사가 자바스크립트를 통해 브라우저에서 이루어지더라도 서버 측에서 재검사를 한다.

다. 예제

안전하지 않는 코드 예제


1: <%
2: String username = request.getParameter("username");
3: String password = request.getParameter("password");
4: if (username==nill || password==null || !isAuthenticatedUser(usename, password)) {
5: throw new MyException("인증 에러");
6: }
7: Cookie userCookie = new Cookie("user" ,username);
8: Cookie authCookie = new Cookie("authenticated" ,"1" );
9:
10: response.addCookie(userCookie);
11: response.addCookie(authCookie);
12: %>

평문으로 사용자의 인증정보 및 “authenticated”를 쿠키에 저장하고 있다. 공격자는 쿠키정보를 변경 가능하기 때문에 중요한 정보를 쿠키에 저장시에는 암호화해서 사용하고, 가급적 해당정보는 WAS(Web Application Server) 서버의 세션에 저장한다.

안전한 코드 예제


1: <%
2: String username = request.getParameter("username");
3: String password = request.getParameter("password");
4: if (username==nill || password==null || !isAuthenticatedUser(usename, password)) {
5: throw new MyException("인증 에러");
6: }
7: // 사용자 정보를 세션에 저장한다.
8: HttpSession ses = new HttpSession(true);
9: ses.putValue("user",username);
10: ses.putValue("authenticated","1" );
11: %>

사용자의 인증정보를 세션에 저장함으로써 인증정보가 외부에 노출될 가능성은 없다.

라. 참고 문헌

[1] CWE-807 보안결정을 신뢰할 수 없는 입력값에 의존 - http://cwe.mitre.org/data/definitions/807.html 
CWE-247 보안 결정시 DNS Lookup에 의존 - http://cwe.mitre.org/data/definitions/247.html 
CWE-302 허위-불변 데이터로 인증우회 - http://cwe.mitre.org/data/definitions/302.html 
CWE-784 보안 의사결정에서 검증 및 무결성 점검 없이 쿠키신뢰 - http://cwe.mitre.org/data/definitions/784.html 
[2] CWE/SANS Top 25 Most Dangerous Software Errors

2절. API 악용

API(Application Programming Interface)는 운영체제와 응용프로그램간의 통신에 사용되는 언어나 메시지 형식 또는 규약으로, 응용 프로그램 개발시 개발 편리성 및 효율성을 제공하는 이점이 있다. 그러나 API 오용 및 취약점이 알려진 API의 사용은 개발효율성 및 유지보수성의 저하 및 보안상의 심각한 위협요인이 될 수 있다.

1. J2EE: 직접 연결 관리(J2EE Bad Practices: Direct Management of Connections)

가. 정의

J2EE 애플리케이션이 컨테이너에서 제공하는 자원 연결 관리를 사용하지 않고 직접 제작하는 경우 에러를 유발할 수 있기 때문에 J2EE 표준에서 금지하고 있다.

나. 안전한 코딩기법

J2EE 애플리케이션이 컨테이너에서 제공하는 연결 관리 기능을 사용한다.

다. 예제

안전하지 않는 코드 예제


1: public class U245 extends javax.servlet.http.HttpServlet {
2: private Connection conn;
3:
4: public void dbConnection(String url, String user, String pw) {
5: try {
6: // j2ee 서블릿에서 자원에 대한 연결을 직접 얻는다.
7: conn = DriverManager.getConnection(url, user, pw);
8: } catch (SQLException e) {
9: System.err.println("...");
10: } finally {
11: ……
12: }

연결(connection)을 직접 관리 하면 안된다.

안전한 코드 예제


1: public class S245 extends javax.servlet.http.HttpServlet {
2: private static final String CONNECT_STRING = "jdbc:ocl:orcl";
3:
4: public void dbConnection() throws NamingException, SQLException {
5: Connection conn = null;
6: try {
7: // 자원관리기능을 이용해서 자원에 대한 연결을 얻는다.
8: InitialContext ctx = new InitialContext();
9: DataSource datasource = (DataSource) ctx.lookup(CONNECT_STRING);
10: conn = datasource.getConnection();
11: } catch (SQLException e) {
12: ……
13: } finally {
14: if ( conn != null )
15: conn.close();
16: }
17: }

자원 관리 기능을 사용하여 자원에 대한 연결을 얻어야 한다.

라. 참고 문헌

[1] CWE-245 J2EE: 직접 연결 관리 - http://cwe.mitre.org/data/definitions/245.html

2. J2EE: 직접 소켓 사용(J2EE Bad Practices: Direct Use of Sockets)

가. 정의

J2EE 애플리케이션이 프레임워크 메소드 호출을 사용하지 않고, 소켓을 직접 사용하는 경우 채널 보안, 에러 처리, 세션 관리 등 다양한 고려 사항이 필요하다.

나. 안전한 코딩기법

소켓을 직접 사용하는 대신에 프레임워크에서 제공하는 메소드 호출을 사용해야 한다.

다. 예제

안전하지 않는 코드 예제


1: public class S246 extends javax.servlet.http.HttpServlet {
2: private Socket socket;
3:
4: protected void doGet(HttpServletRequest request,
5: HttpServletResponse response) throws ServletException {
6: try {
7: // J2EE 응용프로그램에서 프레임워크 메소드 호출 대신에 소켓(Socket)을 직접
사용하고 있다.
8: socket = new Socket("kisa.or.kr", 8080);
9: } catch (UnknownHostException e) {
10: System.err.println("UnknownHostException occured");
11: } catch (IOException e) {
12: System.err.println("IOException occured");
13: } finally {
14: ...
15: }
16: }
17: }

doGet 메소드 내에서 소켓(Socket)을 직접 사용하면 위험하다.

안전한 코드 예제


1: public class S246 extends javax.servlet.http.HttpServlet {
2: protected void doGet(HttpServletRequest request,
3: HttpServletResponse response) throws ServletException {
4: ObjectOutputStream oos = null;
5: ObjectInputStream ois = null;
6: try {
7: // 타겟이 WAS로 작성이 되면 URL Connection을 이용하거나, EJB를 통해서 호출한다.
8: URL url = new URL("http://127.0.0.1:8080/DataServlet");
9: URLConnection urlConn = url.openConnection();
10: urlConn.setDoOutput(true);
11: oos = new ObjectOutputStream(urlConn.getOutputStream());
12: oos.writeObject("data");
13: ois = new ObjectInputStream(urlConn.getInputStream());
14: Object obj = ois.readObject();
15: } catch (ClassNotFoundException e) {
16: System.err.println("Class Not Found");
17: } catch (IOException e) {
18: System.err.println("URL Connection Error occured");
19: } finally {
20: ……
21: }
22: }
23: }

자원 관리 기능을 사용하여 자원에 대한 연결을 얻어야 한다.

라. 참고 문헌

[1] CWE-246 J2EE: 직접 소켓 사용 - http://cwe.mitre.org/data/definitions/246.html

3. 보안 결정시 DNS lookup에 의존(Reliance on DNS Lookups in a Security Decision )

가. 정의

공격자가 DNS 엔트리를 속일 수 있다. 보안 상 DNS 명에 의존하면 안 된다. DNS 서버는 스푸핑 공격 대상이며, SW가 훼손된 DNS 서버 환경에서 언젠가는 실행될 수 있음을 가정하여야 한다. 만일 공격자가 DNS를 수정할 수 있다면, 공격자 IP 주소로 도메인명을 지정할 수 있다.

나. 안전한 코딩기법

IP 주소도 조작 가능하지만 DNS 이름보다는 안전하다.

다. 예제

안전하지 않는 코드 예제


1: public class U247 extends HttpServlet {
2: public void doGet(HttpServletRequest req, HttpServletResponse res)
3: throws ServletException, IOException {
4: boolean trusted = false;
5: String ip = req.getRemoteAddr();
6:
7: // 호스트의 IP 주소를 얻어온다.
8: InetAddress addr = InetAddress.getByName(ip);
9:
10: // 호스트의 IP정보와 지정된 문자열(trustme.com)이 일치하는지 검사한다.
11: if (addr.getCanonicalHostName().endsWith(" trustme.com" ) ) {
12: trusted = true;
13: }
14: if (trusted) {
15: ……
16: } else {
17: ……
18: }
19: }
20: }

DNS 이름을 통해 해당 요청이 신뢰할 수 있는지를 검사한다. 그러나 공격자가 DNS 캐쉬등을 조작하면 잘못된 신뢰 상태 정보를 얻을 수 있다..

안전한 코드 예제


1: public class S247 extends HttpServlet {
2:
3: public void doGet(HttpServletRequest req, HttpServletResponse res)
4: throws ServletException, IOException {
5:
6: String ip = req.getRemoteAddr();
7: if ( ip == null || "".equals(ip) )
8: return ;
9:
10: String trustedAddr = "127.0.0.1";
11:
12: if (ip.equals(trustedAddr) ) {
13: ……
14: } else {
15: ……
16: }
17: }
18: }

DNS lookup에 의한 호스트 이름 비교를 하지 않고 IP 주소를 직접 비교하도록 수정한다.

라. 참고 문헌

[1] CWE-247 보안 결정시 DNS lookup에 의존 - http://cwe.mitre.org/data/definitions/247.html 
[2] SANS Top 25 2010 - (SANS 2010) Porus Defense - CWE ID 807 Reliance on Untrusted Inputs in a Security Decision

4. J2EE: System.exit() 사용(J2EE Bad Practices:Use of System.exit())

가. 정의

J2EE 응용프로그램에서 System.exit()의 사용은 컨테이너까지 종료시킨다.

나. 안전한 코딩기법

J2EE 프로그램에서 System.exit를 사용해서는 안 된다.

다. 예제

안전하지 않는 코드 예제


1: public class U382 extends HttpServlet {
2: public void doPost(HttpServletRequest request, HttpServletResponse response)
3: throws ServletException, IOException {
4:
5: FileHandler handler = new FileHandler("errors.log");
6: Logger logger = Logger.getLogger("com.mycompany");
7: logger.addHandler(handler);
8: try {
9: do_something(logger);
10: } catch (IOException ase) {
11: // J2EE 프로그램에서 System.exit()을 사용
12: System.exit(1);
13: }
14: }
15:
16: private void do_something(Logger logger) throws IOException {
17: }
18: }

doPost() 메소드 내에서 System.exit()를 호출하면 컨테이너까지 종료된다.

안전한 코드 예제


1: public class S382 extends HttpServlet {
2: public void doPost(HttpServletRequest request, HttpServletResponse response)
3: throws ServletException, IOException {
4:
5: FileHandler handler = new FileHandler("errors.log");
6: Logger logger = Logger.getLogger("com.mycompany");
7: logger.addHandler(handler);
8: try {
9: do_something(logger);
10: } catch (IOException ase) {
11: logger.info("Caught: " + ase.toString());
12: //System.exit(1)의 사용을 금한다.
13: //System.exit(1);
14: }
15: }
16:
17: private void do_something(Logger logger) throws IOException {
18: }
19: }

System.exit()를 호출하지 않고 doPost 메소드를 종료한다.

라. 참고 문헌

[1] CWE-382 J2EE: System.exit() 사용 - http://cwe.mitre.org/data/definitions/382.html

5. null 매개변수 미검사(Missing Check for Null Parameter)

가. 정의

Java 표준에 따르면 Object.equals(), Comparable.compareTo() 및 Comparator.compare()의 구현은 매개변수가 null인 경우 지정된 값을 반환해야 한다. 이 약속을 따르지 않으면 예기치 못한 동작이 발생할 수 있다.

나. 안전한 코딩기법

Object.equals(), Comparable.compareTo()과 Comparator.compare() 구현에서는 매개변수를 null과 비교해야 한다.

다. 예제

안전하지 않는 코드 예제


1: public class U9201 implements java.util.Comparator {
2: public int compare(Object o1, Object o2) {
3: //o1, o2에 대한 null 체크 유무가 없음
4: int i1 = o1.hashCode();
5: int i2 = o2.hashCode();
6: int ret;
7: if (i1 > i2) { ret = 1; }
8: else if (i1 == i2) { ret = 0; }
9: else { ret = -1; }
10: return ret;
11: }
12: ……
13: }

매개 변수가 null인지 검사하지 않았다.

안전한 코드 예제


1: public class S9201 implements java.util.Comparator {
2: public int compare(Object o1, Object o2) {
3: int ret;
4: // 비교되는 객체에 대한 null 여부를 점검을 한다.
5: if (o1 != null && o2 != null) {
6: int i1 = o1.hashCode();
7: int i2 = o2.hashCode();
8: if (i1 > i2) { ret = 1; }
9: else if (i1 == i2) { ret = 0; }
10: else { ret = -1; }
11: } else
12: ret = -1;
13: return ret;
14: }
15: ……
16: }

매개 변수가 null인지 먼저 검사한다.

라. 참고 문헌

[1] CWE-398 부족한 코드 품질 지시자 - http://cwe.mitre.org/data/definitions/398.html

6. EJB: 소켓 사용(EJB Bad Practices: Use of Sockets)

가. 정의

Enterprise JavaBeans(EJB) 규격에는 bean내부에서 서버 소켓(ServerSocket)을 직접 사용하여 클라이언트에 서비스를 제공하는 것을 금지하고 있다. EJB 컨테이너 내의 bean은 모두 EJB 클라이언트에 대해서 네트워크 서버 형태로 서비스를 제공하도록 설계되어 있는데 bean 내에서 다시 ServerSocket을 생성 할 경우 구조적인 혼동을 야기할 수 있기 때문이다.

나. 안전한 코딩기법

EJB 프로그램에서 서버 소켓을 사용하지 않는다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: public void function_test() throws IOException {
3: ServerSocket s = new ServerSocket(1122);
4: Socket clientSocket = serverSocket.accept();
5: ……
6: }
7: ……

EJB 프로그램에서 서버 소켓을 사용하면 안 된다.

안전한 코드 예제


1: ……
2: public void function_test() throws IOException {
3: //EJB기반에서 server socket 사용을 금한다.
4: //ServerSocket s = new ServerSocket(1122);
8: //Socket clientSocket = serverSocket.accept();
9: ……
5: }
6: ……

EJB 프로그램에서 서버 소켓을 사용하면 안 된다.

라. 참고 문헌

[1] CWE-577 EJB: 소켓 사용 - http://cwe.mitre.org/data/definitions/577.html

7. equals()와 hashCode() 하나만 정의(Object Model Violation: Just one of equals() and hashCode() Defined)

가. 정의

Java 표준에 따르면, Java의 같은 객체는 같은 해시코드를 가져야 한다. 
즉 “a.equals(b) == true”이면 “a.hashCode() == b.hashCode()” 이어야 한다. 따라서 한 클래스 내에서 equals()와 hashCode()는 둘 다 구현하거나 둘 다 구현하지 않아야 한다.

나. 안전한 코딩기법

한 클래스 내에 equals()를 정의하면 hashCode()도 정의해야 하고 hashCode()를 정의하면 equals()도 정의해야 한다.

다. 예제

안전하지 않는 코드 예제


1: public class U581 {
2: ……
3: // equals()만 구현
4: public boolean equals(Object obj) {
5: boolean ret;
6: if (obj != null) {
7: int i1 = this.hashCode();
8: int i2 = obj.hashCode();
9: if (i1 == i2) { ret = true; }
10: else { ret = false; }
11: } else {
12: ret = false;
13: }
14: return ret;
15: }
16: ……
17: }

equals()와 hashCode() 중 하나만 정의하였다.

안전한 코드 예제


1: public class S581 {
2: ……
3: // 자신의 객체와 비교하는 equals() 구현
4: public boolean equals(Object obj) {
5: boolean ret;
6: if (obj != null) {
7: int i1 = this.hashCode();
8: int i2 = obj.hashCode();
9: if (i1 == i2) { ret = true; }
10: else { ret = false; }
11: } else {
12: ret = false;
13: }
14: return ret;
15: }
16: // hashCode() 구현
17: public int hashCode() {
18: return new HashCodeBuilder(17, 37).toHashCode();
19: }
20: ……
21: }

equals()와 hashCode() 모두 정의해야 한다.

라. 참고 문헌

[1] CWE-581 equals()와 hashCode() 하나만 정의 - http://cwe.mitre.org/data/definitions/581.html

3절. 보안특성

기본적인 보안 기능을 다룰 때는 세심한 주의가 필요하다. 부적절한 보안특성의 사용은 오히려 성능이나 부가적인 문제를 불러 올 수도 있다. 보안특성에는 인증, 접근제어, 기밀성, 암호화, 권한 관리 등이 포함된다.

1. 하드코드된 패스워드(Hard-coded Password)

가. 정의

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

나. 안전한 코딩기법

패스워드는 암호화하여 별도의 파일에 저장하여 사용하는 것이 바람직하다. 
SW 설치 시 사용하는 디폴트 패스워드, 키 등을 사용하는 대신 “최초-로그인” 모드를 두어 사용자가 직접 강력한 패스워드나 키를 입력하도록 설계한다.

다. 예제

안전하지 않는 코드 예제


1: public class U259 {
2: private Connection conn;
3:
4: public Connection DBConnect(String url, String id) {
5: try {
6: // password가 하드-코드 되어있다.
7: conn = DriverManager.getConnection(url, id, "tiger");
8: } catch (SQLException e) {
9: System.err.println("...");
10: }
11: return conn;
12: }
13: ……
14: }

데이터베이스를 연결하기 위하여 코드 내부에 상수 형태로 정의된 패스워드를 사용하면 프로그램에 취약점을 야기할 수 있다.

안전한 코드 예제


1: public class S259 {
2: public Connection connect(Properties props) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException,
BadPaddingException {
3: try {
4: String url = props.getProperty("url");
5: String id = props.getProperty("id");
6: String pwd = props.getProperty("passwd" );
7:
8: //외부 설정 파일에서 패스워드를 가져오며, 패스워드가 값이 있는지 체크하고 있음
9: if (url != null && !"".equals(url) && id != null && !"".equals(id)
10: && pwd != null && !"".equals(pwd)) {
11: KeyGenerator kgen = KeyGenerator.getInstance("Blowfish");
12: SecretKey skey = kgen.generateKey();
13: byte[] raw = skey.getEncoded();
14: SecretKeySpec skeySpec = new SecretKeySpec(raw, "Blowfish");
15:
16: Cipher cipher = Cipher.getInstance("Blowfish");
17: cipher.init(Cipher.DECRYPT_MODE, skeySpec);
18: byte[] decrypted_pwd = cipher.doFinal(pwd.getBytes());
19: pwd = new String(decrypted_pwd);
20: conn = DriverManager.getConnection(url, id, pwd);
21: }
22: } catch (SQLException e) {
23: …

데이터베이스를 사용하는 프로그램 작성시 패스워드를 구하는 로직을 따로 구현하여, 주어진 로직에 의하여 검증된 패스워드를 사용한다.

안전하지 않는 코드 예제


1: try {
2: Connection con = DriverManager.getConnection(url, "scott" , " tiger" );
3: ......
4: } catch (SQLException e) {
5: throw new MyException("DB 에러“);
6: }

DB Connection 객체를 생성할 때, 디폴트 설치시 제공되는 계정을 사용하고 있다. 
패스워드가 프로그램 내에 하드 코딩되어 있어 외부에 노출되기 쉽다.

안전한 코드 예제


1: /* mkstore -wrl /mydir -createCredential MyTNSName some_user some_password */
2: try {
3: System.setProperty("oracle.net.tns_admin", "/mydir");
4: java.util.Properties info = new java.util.Properties();
5: // DB 커넥션을 위한 계정은 oracle 기능을 사용한다.
6: info.put("oracle.net.wallet_location",
7: " (SOURCE=(METHOD=file)(METHOD_DATA=(DIRECTORY=/mydir)))" );
8: OracleDataSource ds = new OracleDataSource();
9: ds.setURL("jdbc:oracle:thin:@MyTNSName");
10: ds.setConnectionProperties(info);
11: Connection conn = ds.getConnection();
12: } catch (SQLException e) {
13: throw new MyException("DB 에러“);
14: }

오라클 툴인 mkstore를 사용하여 DB 계정을 암호화하여 사용한다.

라. 참고 문헌

[1] CWE-259 하드코드된 패스워드 - http://cwe.mitre.org/data/definitions/259.html 
CWE-321 하드코드된 암호화키 - http://cwe.mitre.org/data/definitions/321.html 
CWE-798 하드코드된 증명서 - http://cwe.mitre.org/data/definitions/798.html 
[2] SANS Top 25 2010 - (SANS 2010) Porus Defense - CWE ID 798 Use of Hard-coded Credentials

2. 부적절한 인가(Improper Authorization)

가. 정의

SW가 모든 가능한 실행경로에 대해서 접근제어를 검사하지 않거나 불완전하게 검사하는 경우, 공격자는 접근가능한 실행경로를 통해 정보를 유출할 수 있다.

나. 안전한 코딩기법

응용프로그램이 제공하는 정보와 기능을 역할에 따라 배분함으로써 공격자에게 노출되는 공격표면(attack surface)을 감소시킨다. 
사용자의 권한에 따른 ACL(Access Control List)을 관리한다. 
※ 프레임워크를 사용해서 취약점을 피할 수 있다. 예를 들면, JAAS Authorization Framework나 OWASP ESAPI Access Control 등이 인증 프레임워크로 사용 가능하다.

다. 예제

안전하지 않는 코드 예제


1: public void f(String sSingleId, int iFlag, String sServiceProvider, String sUid, String sPwd)
{
2: ……
3: env.put(Context.INITIAL_CONTEXT_FACTORY, CommonMySingleConst.INITCTX);
4: env.put(Context.PROVIDER_URL, sServiceProvider);
5: // 익명으로 LDAP 인증을 사용
6: env.put(Context.SECURITY_AUTHENTICATION, "none");
7: env.put(Context.SECURITY_PRINCIPAL, sUid);
8: env.put(Context.SECURITY_CREDENTIALS, sPwd);
9: ……

외부의 입력인 name 값이 필터가 아닌 동적인 LDAP 질의문에서 사용자명으로 사용되었으며, 사용자 인증을 위한 별도의 접근제어 방법이 사용되지 않고 있다. 이는 anonymous binding을 허용하는 것으로 볼 수 있다. 따라서 임의 사용자의 정보를 외부에서 접근할 수 있게 된다.

안전한 코드 예제


1: public void f(String sSingleId, int iFlag, String sServiceProvider, String sUid, String sPwd)
{
2: ……
3: env.put(Context.PROVIDER_URL, sServiceProvider);
4: // 익명의 인증을 사용하지 않는다.
5: env.put(Context.SECURITY_AUTHENTICATION, "simple");
6: env.put(Context.SECURITY_PRINCIPAL, sUid);
7: env.put(Context.SECURITY_CREDENTIALS, sPwd);
8: ……

사용자 ID와 password를 컨텍스트에 설정한 후 접근하도록 접근제어를 사용한다.

안전하지 않는 코드 예제


1: <%
2: String username = request.getParameter("username");
3: String password = request.getParameter("password");
4: if (username==nill || password==null || !isAuthenticatedUser(usename, password)) {
5: throw new Exception("invalid username or password");
6: }
7:
8: String msgId = request.getParameter("msgId");
9: if ( msgId == null ) {
10: throw new MyException("데이터 오류");
11: }
12: Message msg = LookupMessageObject(msgId);
13: if ( msg != null ) {
14: out.println("From: " + msg.getUserName()");
15: out.println("Subject: " + msg.getSubField()");
16: out.println("\n" + msg.getBodyField()");
17: }
18: %>

인증이 성공적으로 끝나면, 어떤 메시지도 조회가능하다. 즉 타인의 메시지 정보를 볼 수가 있다.

안전한 코드 예제


1: <%
2: String username = request.getParameter("username");
3: String password = request.getParameter("password");
4: if (username==nill || password==null || !isAuthenticatedUser(usename, password)) {
5: throw new MyException("인증 에러");
6: }
7:
8: String msgId = request.getParameter("msgId");
9: if ( msgId == null ) {
10: throw new MyException("데이터 오류");
11: }
12: Message msg = LookupMessageObject(msgId);
13:
14: if ( msg != null && username.equals(msg.getUserName()) ) {
15: out.println("From: " + msg.getUserName()");
16: out.println("Subject: " + msg.getSubField()");
17: out.println("\n" + msg.getBodyField()");
18: } else { throw new MyException("권한 에러“); }
19: %>

인증한 사용자와 메시지 박스 사용자가 일치했을 경우, 해당 메시지를 조회하도록 한다.

라. 참고 문헌

[1] CWE-285 부적절한 인가 - http://cwe.mitre.org/data/definitions/285.html 
CWE-219 웹 루트 아래 민감한 데이터 - http://cwe.mitre.org/data/definitions/219.html 
[2] OWASP Top 10 2010 - (OWASP 2010) A8 Failure to Restrict URL Access 
[3] SANS Top 25 2010 - (SANS 2010) Porus Defense - CWE ID 285 Improper Authorization 
[4] NIST. “Role Based Access Control and Role Based Security” 
[5] M. Howard and D. LeBlanc. “Writing Secure Code”. Chapter 4, “Authorization” Page 114; 
Chapter 6, “Determining Appropriate Access Control” Page 171. 2nd Edition. Microsoft. 2002

3. 사이트 간 요청 위조(Cross-Site Request Forgery (CSRF))

가. 정의

CSRF 공격은 악의적인 웹 사이트가 사용자의 웹 브라우져로 하여금 신뢰하는 사이트에서 원치 않는 행동을 취하도록 할 때 발생한다. 공격자는 사용자가 인증한 세션이 특정 동작을 수행하여도 계속 유지되어 정상적인 요청과 비정상적인 요청을 구분하지 못하는 점을 악용하여 피해가 발생한다. 
웹 응용프로그램에 요청을 전달할 경우, 해당 요청의 적법성을 입증하기 위하여 전달되는 값이 고정되어 있고 이러한 자료가 GET 방식으로 전달된다면 공격자가 이를 쉽게 알아내어 원하는 요청을 보냄으로써 위험한 작업을 요청할 수 있게 된다.

나. 안전한 코딩기법

form data posting에 있어서 POST 방식을 사용한다. 
OWASP CSRFGuard 등의 anti-CSRF 패키지를 사용한다.

다. 예제

안전하지 않는 코드 예제


1: ……
2: <form name="MyForm" method="get" action="customer.do">
3: <input type=text name="txt1">
4: <input type=submit value="보내기">
5: </form>
6: ……

GET방식은 단순히 form 데이터를 URL 뒤에 덧붙여서 전송하기 때문에 GET 방식의 form을 사용하면 전달 값이 노출되므로 CSRF 공격에 쉽게 노출될 수 있다.

안전한 코드 예제


1: ……
2: <form name="MyForm" method="post" action="customer.do">
3: <input type=text name="txt1">
4: <input type=submit value="보내기">
5: </form>
6:

Post 방식을 사용하여 위협을 완화한다.

라. 참고 문헌

[1] CWE-352 사이트 간 요청 위조 - http://cwe.mitre.org/data/definitions/352.html 
[2] OWASP Top Ten 2010 Category A5 - Cross-Site Request Forgery(CSRF) 
[3] SANS Top 25 2010 - (SANS 2010) Insecure Interaction - CWE ID 352 Cross-Site Request Forgery

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

가. 정의

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

 

about author

PHRASE

Level 60  머나먼나라

인간의 미래는 인간의 마음에 있다. - A. 슈바이처

댓글 ( 4)

댓글 남기기

작성

자바 목록    more