-
How To Fix SQL Injection - Developer How to Guide 번역, SANSInfomation Security/소스레벨 취약점 2013. 3. 25. 17:49
원문: http://software-security.sans.org/developer-how-to/#how_to_fix_sql_injection
쓸모가 있을것 같아서 번역하였습니다. 어색하거나 잘못된 부분이 있다면 지적바랍니다^^;
JAVA
How to Fix SQL Injection Using Java PreparedStatement & CallableStatement
어떻게 Java의 PreparedStatement & CallableStatement를 사용하여 SQL Injection 공격을 방지하는가
Java PreparedStatement
A PreparedStatement represents a precompiled SQL statement that can be executed multiple times without having to recompile for every execution.
PreparedStatement는 매번 실행될때마다 재컴파일이 필요없고 (선)컴파일된 상태로 여러번 실행될 수 있는 SQL문이다.
안전한 사용법(예)
1234PreparedStatement stmt = connection.prepareStatement("SELECT * FROM users WHERE userid=? AND password=?");stmt.setString(1, userid);stmt.setString(2, password);ResultSet rs = stmt.executeQuery();This code is not vulnerable to SQL Injection because it correctly uses parameterized queries. By utilizing Java's PreparedStatement class, bind variables (i.e. the question marks) and the corresponding setString methods, SQL Injection can be easily prevented.
이 코드는 파라미터화된 쿼리를 올바르게 사용했으므로 SQL Injection에 취약하지 않다. JAVA의 PreparedStatement 클래스를 활용하여 setString 메소드에 해당하는 변수(?)들을 바인드하면 SQL Injection 공격은 쉽게 예방할 수 있다.
취약한 사용법(예)1234// Example #1String query = "SELECT * FROM users WHERE userid ='"+ userid + "'" + " AND password='" + password + "'";Statement stmt = connection.createStatement();ResultSet rs = stmt.executeQuery(query);This code is vulnerable to SQL Injection because it uses dynamic queries to concatenate malicious data to the query itself. Notice that it uses the Statement class instead of the PreparedStatement class.
이 코드는 기존의 쿼리와 악의적인 데이터(SQL Injection)가 연결되는 동적인 쿼리를 사용하기 때문에 SQL Injection 공격에 취약하다. PreparedStatement 클래스 대신에 Statement 클래스를 사용할때는 주의해야한다.
1234// Example #2String query = "SELECT * FROM users WHERE userid ='"+ userid + "'" + " AND password='" + password + "'";PreparedStatement stmt = connection.prepareStatement(query);ResultSet rs = stmt.executeQuery();This code is also vulnerable to SQL Injection. Even though it uses the PreparedStatement class it is still creating the query dynamically via string concatenation.
이 코드 또한 SQL Injection 공격에 취약하다. PreparedStatement 클래스를 사용했더라도 여전히 문자열 연결을 통해서 동적인 쿼리를 생성할 수 있다.
Java CallableStatement
Java CallableStatement class is used to execute SQL stored procedures. Invoking a stored procedure or a function using CallableStatement in itself is not vulnerable to SQL Injection; however, the underlying database code could be vulnerable. Refer to the Database Code section of this guide to see how to write secure database code
Java CallableStatement 클래스는 저장된 프로시저 SQL을 실행하기 위해 사용한다. CallableStatement를 사용한 함수나 저장된 프로시저는 취약하지 않지만 근본적으로 데이터베이스 코드는 취약할 수 있다. 이 가이드 문서의 "데이터베이스 코드" 부분을 보면 안전한 데이터베이스 코드를 어떻게 작성하는지 볼수있다.
Authors
Priya Gnanasundar
Contributors
Daniel Ryan
How to Fix SQL Injection using Hibernate
어떻게 Hibernate를 사용하여 SQL Injection 공격을 방지하는가
Hibernate facilitates the storage and retrieval of Java domain objects via Object/Relational Mapping (ORM). It is a very common misconception that ORM solutions, like hibernate, are SQL Injection proof. Hibernate allows the use of "native SQL" and defines a proprietary query language, named, HQL (Hibernate Query Language); the former is prone to SQL Injection and the later is prone to HQL (or ORM) injection.
Hibernate는 스토리지와 ORM을 통한 Java domain objects의 정보 검색/수정을 용이하게 한다. 하지만 Hibernate가 SQL Injection 공격을 방지한다는 것은 ORM 솔루션에 대한 오해다. Hibernate는 "Native SQL"의 사용을 허용하며, HQL이라는 독자적인 쿼리 랭귀지를 정의하고 있다. 따라서 고전적인 SQL Injection과 HQL(ORM) Injection이 가능하다.
This article is intended to illustrate how certain syntax offered by hibernate to define SQL & HQL, is better over the other, in terms of defense against SQL and/or HQL injection attacks.
이 문서에서는 SQL/HQL Injection 공격에 대해서 SQL과 HQL에서 어떤 구문이 더 나은것인지 설명하고자 한다.
안전한 사용법(예)
1234567891011121314151617181920/* Positional parameter in HQL */Query hqlQuery = session.createQuery("from Orders as orders where orders.id = ?");List results = hqlQuery.setString(0, "123-ADB-567-QTWYTFDL").list();/* named parameter in HQL */Query hqlQuery = session.createQuery("from Employees as emp where emp.incentive > :incentive");List results = hqlQuery.setLong("incentive", new Long(10000)).list();/* named parameter list in HQL */List items = new ArrayList();items.add("book"); items.add("clock"); items.add("ink");List results = session.createQuery("from Cart as cart where cart.item in (:itemList)").setParameterList("itemList", items).list();/* JavaBean in HQL */Query hqlQuery = session.createQuery("from Books as books where book.name = :name and book.author = :author");List results = hqlQuery.setProperties(javaBean).list(); //assumes javaBean has getName() & getAuthor() methods./* Native-SQL */Query sqlQuery = session.createSQLQuery("Select * from Books where author = ?");List results = sqlQuery.setString(0, "Charles Dickens").list();The above code snippets use parameter binding to set data. The JDBC driver will escape this data appropriately before the query is executed, making sure that data is used just as data.위의 소스코드에서는 Data를 설정하기위해 파라미터로 연결한다. JDBC 드라이버는 쿼리가 실행되기전에 이 데이터를 escape 처리하며, 단지 데이터로만 사용된다.Assuming data used in the above code snippets is user input, that has not been validated or escaped and it contains malicious database code (payload), the payload will be escaped appropriately by the JDBC driver (since parameterized queries are used), such that it would be used as data and not as code.위의 코드에서 데이터에 사용자 입력이 사용된다면 사전검증 또는 escape 처리가 되지 않았거나 잘못된 데이터베이스 코드를 포함할 수 있다. 하지만 JDBC에 의해 실행될 수 있는 코드가 아닌 데이터로 escape 처리가되기 때문에 안전하다.취약한 사용법(예)1
2
3
4List results = session.createQuery("from Orders as orders where orders.id = " + currentOrder.getId()).list();
List results = session.createSQLQuery("Select * from Books where author = " + book.getAuthor()).list();
Assuming orderId and author are user input that have not been validated or escaped, it leaves the above queries vulnerable to SQL and HQL(ORM) injection attacks."orderId"와 "author"가 사전에 검증되지 않거나 처리되지 않았다면, 위의 쿼리는 SQL/HQL Injection 공격에 취약하다.AuthorsPriya GnanasundarContributorsDaniel RyanHow to Fix SQL Injection using MyBatis
어떻게 MyBatis를 사용하여 SQL Injection 공격을 방지하는가
The MyBatis data mapper framework makes it easier to use a relational database with object-oriented applications. Unlike traditional ORM solutions, MyBatis maps objects with SQL statements or stored procedures using a XML descriptor, rather than mapping objects to tables in a database; thus providing complete control over SQL, therefore susceptible to SQL injection if used incorrectly.
MyBatis와 같은 데이터 매핑 프레임워크는 객체지향 어플리케이션과 함께 관계형 데이터베이스의 사용을 쉽게 한다. 전통적인 ORM 솔루션과 달리, MyBatis는 오브젝트를 데이터베이스의 테이블로 매핑하기보다 SQL문 또는 저장 프로시저를 XML 디스크립터를 통해 오브젝트와 연결시킨다. 따라서 SQL의 완전한 제어를 제공하지만 잘못 사용되었을 경우 SQL Injection 공격에 취약할 수 있다.
This article is intended to illustrate how certain syntax offered by MyBatis to define SQL, is better over the other, in terms defense against SQL injection attacks.
이 문서에서는 SQL Injection 공격에 대한 방어와 MyBatis를 사용하여 SQL을 정의할 경우 어떻게 구문을 작성해야 하는지 설명하고자 한다.
안전한 사용법(예)
1 SELECT * FROM PERSON WHERE ID = #{id}The getPerson statement above takes a parameter of type int and returns an object of type Person.
getPerson 구문은 int 타입의 파라미터를 취하며 Person 타입의 오브젝트를 반환한다.
Note the parameter notation, #{id}. By default, using the #{} syntax will cause MyBatis to generate PreparedStatement parameters (e.g. ?) and set the values safely against them, like the following:
파라미터 표기에 대해서 적자면, 기본적으로 #{}를 사용하면 MyBatis는 PreparedStatement 파라미터(?)를 생성하고 SQL Injection으로부터 안전한 값으로 설정한다.
1234/* Comparable JDBC code */String selectPerson = "SELECT * FROM PERSON WHERE ID = ?";PreparedStatement ps = conn.prepareStatement(selectPerson);ps.setInt(1, id);Thus, SQL Injection proof.
따라서 SQL Injection 으로부터 안전하다.
Here are some more examples of proper usage:
적절한 사용의 몇가지 예제는 다음과 같다.
1234567insert into Person (id, name, email, phone)values (#{id}, #{name}, #{email}, #{phone})update Person set name = #{name}, email = #{email}, phone = #{phone}where id = #{id}delete from Person where id = #{id}취약한 사용법(예)1 SELECT * FROM PERSON WHERE NAME = #{name} AND PHONE LIKE '${phone}';Note the parameter notation, ${phone} in the above getPerson statement. By default, using the ${} syntax will cause MyBatis to directly inject a string, unmodified, into a SQL Statement. MyBatis does NOT modify or escape the string before substitution.
위의 getPerson 구문에서 ${phone} 파라미터에 대해서 적자면, 기본적으로 ${}구문은 MaBatis에서 SQL구문으로 수정되지 않은 문자열의 삽입을 가능하게 합니다(SQL Injection이 가능하다는 소리). (구문을 수정하기 전에)MyBatis는 문자열을 수정하거나 escape 처리를 하지 않는다.(${} 대신 #{{}을 쓰라는 얘기인듯)
Assuming phone is a user entered value, that has not been validated or escaped appropriately, an attacker can enter a string(payload) like, "1%' OR '1'='1" for phone; the query now becomes the following, returning all rows from the PERSON table.
phone 값은 사용자가 입력한 값이고, 적절한 검증 및 escape 처리가 되지 않았다. 공격자는 phone 값에 "1%' OR '1'='1"과 같은 문자열을 삽입할 수 있다. 그리고 (조작된)쿼리는 PERSON 테이블의 모든 row를 출력할 수 있다.
1 SELECT * FROM PERSON WHERE NAME = ? and PHONE LIKE '1%' OR '1' = '1'On the other hand, a payload like "A%'; DELETE FROM PERSON; --" for phone, results in the following query, deleting all data in the PERSON table.
반면에 phone 파라미터에 "A%'; DELETE FROM PERSON; --" 라는 문자열이 삽입될 경우 PERSON 테이블의 모든 데이터가 삭제될 수 있다.
1 SELECT * FROM PERSON WHERE NAME = ? and PHONE LIKE 'A%'; DELETE FROM PERSON; --'It is not safe to accept input from a user and use directly in a statement unmodified as illustrated above. This leads to potential SQL Injection attacks. Therefore, when using the ${} syntax, user input should either be disallowed or appropriate validation and escaping should be performed.
위의 예제처럼 수정되지 않은(적절히 처리되지 않은) 사용자의 입력값을 구문에 바로 사용하면 안전하지 않다. 이것은 잠재적인 SQL Injection 공격을 야기할 수 있다. 그러므로 ${} 구문을 사용할 때 사용자 입력 값을 사용하지 않거나 적절한 검증, escape 처리를 해야한다.
Here are some more examples of vulnerable usage:
취약한 예제는 다음과 같다.
1234567insert into Person (id, name, email, phone)values (#{id}, #{name}, #{email}, ${phone})update Person set phone = ${phone}where id = #{id}delete from Person where id = ${id}Authors
Priya Gnanasundar
Contributors
Daniel Ryan
How to How to Fix SQL Injection using the Java Persistence API (JPA)
어떻게 Java Persistence API를 사용하여 SQL Injection 공격을 방지하는가
Java Persistence API (JPA), is an ORM solution that is a part of the Java EE framework. It helps manage relational data in applications that use Java SE and Java EE. It is a common misconception that ORM solutions like JPA (Java Persistence API) are SQL Injection proof. JPA allows the use of native SQL and defines its own query language, named, JPQL (Java Persistence Query Language). The former is prone to traditional SQL injection attacks and the later is prone to JPQL (or ORM) injection attacks.
Java Persistence API는 Java EE 프레임워크의 한 부분인 ORM 솔루션이다. JPA는 Java SE, EE의 어플리케이션에서 관계형 데이터를 관리하는데 도움을 준다. JPA는 또한 ORM 솔루션들이 SQL Injection 으로부터 안전하다고 생각하지만 그렇지 않다. JPA는 Native SQL과 JPQL이라는 쿼리 언어를 사용한다. 따라서 고전적인 SQL Injection과 JPQL(ORM) Injection이 가능하다.
This article is intended to illustrate how certain syntax offered by JPA to define SQL & HQL, is better over the other, in terms of defense against SQL and/or HQL injection attacks.
이 문서에서는 SQL/HQL Injection 공격에 대해서 SQL과 HQL 및 JPA를 사용했을때 어떤 구문이 더 나은것인지 설명하고자 한다.
안전한 사용법(예)
123456789101112131415/* positional parameter in JPQL */Query jpqlQuery = entityManager.createQuery("Select order from Orders order where order.id = ?1");List results = jpqlQuery.setParameter(1, "123-ADB-567-QTWYTFDL").getResultList();/* named parameter in JPQL */Query jpqlQuery = entityManager.createQuery("Select emp from Employees emp where emp.incentive > :incentive");List results = jpqlQuery.setParameter("incentive", new Long(10000)).getResultList();/* named query in JPQL - Query named "myCart" being "Select c from Cart c where c.itemId = :itemId" */Query jpqlQuery = entityManager.createNamedQuery("myCart");List results = jpqlQuery.setParameter("itemId", "item-id-0001").getResultList();/* Native SQL */Query sqlQuery = entityManager.createNativeQuery("Select * from Books where author = ?", Book.class);List results = sqlQuery.setParameter(1, "Charles Dickens").getResultList();The above code snippets use parameter binding to set data. The JDBC driver will escape this data appropriately before the query is executed; making sure that data is used just as data.
위의 소스코드를 보면 데이터를 설정하기 위해 파라미터를 바인딩하는것을 알 수 있다. 따라서 JDBC 드라이버는 데이터가 단지 데이터로 사용될 수 있도록 쿼리를 실행하기 전에 적절히 escape 처리를 할 것이다.
Assuming data used in the above code snippets is user input, that has not been validated or escaped and it contains malicious database code (payload), the payload will be escaped appropriately by the JDBC driver (since parameterized queries are used), such that it would be used as data and not as code.
위의 코드에서 데이터에 사용자 입력이 사용된다면 사전검증 또는 escape 처리가 되지 않았거나 잘못된 데이터베이스 코드를 포함할 수 있다. 하지만 JDBC에 의해 실행될 수 있는 코드가 아닌 데이터로 escape 처리가되기 때문에 안전하다.(ctrl + c,v 해놨네;;)
취약한 사용법(예)123List results = entityManager.createQuery("Select order from Orders order where order.id = " + orderId).getResultList();List results = entityManager.createNativeQuery("Select * from Books where author = " + author).getResultList();int resultCode = entityManager.createNativeQuery("Delete from Cart where itemId = " + itemId).executeUpdate();Assuming orderId, author & itemId are user input that have not been validated or escaped as required, it leaves the above queries vulnerable to SQL and JPQL (ORM) injection attacks.
order.id, author, itemId와 같은 요청된 파라미터의 경우 검증되지 않았거나 escape 처리가 되지 않았기 때문에 SQL, JPQL(SQL) Injection에 취약할 수 있다.
Authors
Priya Gnanasundar
Contributors
Daniel Ryan
Database Code
How to Fix SQL Injection using Oracle Database Code
어떻게 Oracle Database Code를 사용하여 SQL Injection 공격을 방지하는가
A stored procedure is a logical set of SQL statements, performing a specific task; it is compiled once and stored on a database server for all clients to execute; they are used very commonly for the many benefits that they provide. Often times, stored procedures are blindly considered secure; however, it is not so always. SQL Injection is a concern when dynamic SQL is handled incorrectly in a stored procedure.
저장된 프로시저란 특정 작업을 수행하기 위한 SQL문의 논리적인 집합이다. 저장된 프로시저는 모든 클라이언트가 실행할 수 있도록 데이터베이스 서버에 사전에 컴파일되어 저장된다. 저장된 프로시저는 많은 이점이 있지만 종종 맹목적으로 안전하다고 생각하는 경향이 있다. SQL Injection은 저장된 프로시저에서 동적인 SQL을 잘못 다룰때 발생할 수 있다.
In Oracle, dynamic SQL can be used in 1. EXECUTE IMMEDIATE statements, 2. DBMS_SQL package and 3. Cursors. This article illustrates how dynamic SQL can be built securely to defend against SQL injection attacks.
오라클에서 동적인 SQL은 3가지 경우에 사용될 수 있다.
이 문서에서는 SQL Injection 공격으로부터 동적인 SQL을 어떻게 안전하게 하는지 설명하고자 한다.