준비된 문은 어떻게 SQL 주입 공격으로부터 보호할 수 있습니까?
준비된 문이 SQL 주입 공격을 방지하는 데 어떻게 도움이 됩니까?
위키피디아는 다음과 같이 말합니다.
준비된 문은 나중에 다른 프로토콜을 사용하여 전송되는 매개 변수 값을 올바르게 제거할 필요가 없기 때문에 SQL 주입에 대해 탄력적입니다.원래 문 템플릿이 외부 입력에서 파생되지 않으면 SQL 주입을 수행할 수 없습니다.
나는 그 이유를 잘 알 수가 없습니다.간단한 설명은 쉬운 영어와 몇가지 예로 무엇이 있을까요?
이 아이디어는 매우 간단합니다. 쿼리와 데이터는 별도로 데이터베이스 서버로 전송됩니다.
그게 전부입니다.
SQL 주입 문제의 근원은 코드와 데이터의 혼합에 있습니다.
사실 우리의 SQL 쿼리는 합법적인 프로그램입니다.그리고 우리는 그러한 프로그램을 동적으로 만들고 있으며, 즉석에서 데이터를 추가하고 있습니다.따라서 모든 SQL 주입 예제에서 알 수 있듯이 데이터가 프로그램 코드를 방해하고 심지어 프로그램 코드를 변경할 수도 있습니다(PHP/Mysql의 모든 예).
$expected_data = 1;
$query = "SELECT * FROM users where id=$expected_data";
일반 쿼리를 생성할 것입니다.
SELECT * FROM users where id=1
이 암호를 쓰는 동안에
$spoiled_data = "1; DROP TABLE users;"
$query = "SELECT * FROM users where id=$spoiled_data";
악의적인 서열을 만들어낼 겁니다
SELECT * FROM users where id=1; DROP TABLE users;
프로그램 본체에 데이터를 직접 추가하기 때문에 작동하며 프로그램의 일부가 되므로 데이터가 프로그램을 변경할 수 있으며 전달된 데이터에 따라 정규 출력 또는 테이블이 있습니다.users삭제된
준비된 진술의 경우 프로그램을 변경하지는 않지만 그대로 유지됩니다.
문제는 바로 그거예요.
먼저 서버로 프로그램을 보냅니다.
$db->prepare("SELECT * FROM users where id=?");
여기서 데이터는 매개 변수 또는 자리 표시자라고 하는 변수로 대체됩니다.
서버에 데이터가 포함되지 않은 상태에서 정확히 동일한 쿼리가 서버로 전송된다는 점에 유의하십시오!그런 다음 두 번째 요청과 함께 데이터를 전송합니다. 쿼리 자체와는 본질적으로 분리됩니다.
$db->execute($data);
프로그램을 변경할 수도 없고 해를 끼칠 수도 없습니다
아주 간단합니다. 그렇지 않습니까?
제가 덧붙여야 할 유일한 사항은 모든 매뉴얼에서 항상 생략되어 있습니다.
준비된 문은 데이터 리터럴만 보호할 수 있지만 다른 쿼리 부분에서는 사용할 수 없습니다.
따라서 동적 식별자(예를 들어 필드 이름)를 추가해야 하는 경우 준비된 문은 도움이 되지 않습니다.최근에 그 일을 설명했으니 반복하지 않겠습니다.
예제 설정을 위한 SQL 문은 다음과 같습니다.
CREATE TABLE employee(name varchar, paymentType varchar, amount bigint);
INSERT INTO employee VALUES('Aaron', 'salary', 100);
INSERT INTO employee VALUES('Aaron', 'bonus', 50);
INSERT INTO employee VALUES('Bob', 'salary', 50);
INSERT INTO employee VALUES('Bob', 'bonus', 0);
주입 클래스는 SQL 주입에 취약합니다.쿼리는 사용자 입력과 함께 동적으로 붙여넣습니다.그 질문의 의도는 밥에 대한 정보를 보여주기 위함이었습니다.사용자 입력에 따라 급여 또는 보너스 중 하나입니다.그러나 악의적인 사용자는 where 절에 '또는 true'에 해당하는 것을 붙여 쿼리를 손상시키는 입력을 조작하여 숨겨야 할 아론에 대한 정보를 포함한 모든 것이 반환되도록 합니다.
import java.sql.*;
public class Inject {
public static void main(String[] args) throws SQLException {
String url = "jdbc:postgresql://localhost/postgres?user=user&password=pwd";
Connection conn = DriverManager.getConnection(url);
Statement stmt = conn.createStatement();
String sql = "SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='" + args[0] + "'";
System.out.println(sql);
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
System.out.println(rs.getString("paymentType") + " " + rs.getLong("amount"));
}
}
}
이를 실행하면 첫 번째 경우는 정상적으로 사용되고 두 번째 경우는 악성 주입입니다.
c:\temp>java Inject salary
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='salary'
salary 50
c:\temp>java Inject "salary' OR 'a'!='b"
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='salary' OR 'a'!='b'
salary 100
bonus 50
salary 50
bonus 0
사용자 입력의 문자열 연결로 SQL 문을 구축해서는 안 됩니다.주입에 취약할 뿐만 아니라 서버에도 캐싱 영향을 미칩니다(문이 변경되므로 바인딩 예제는 항상 동일한 문을 실행하는 반면 SQL 문 캐시 히트가 발생할 가능성이 줄어듭니다.
다음은 이러한 종류의 주입을 피하기 위한 Binding의 예입니다.
import java.sql.*;
public class Bind {
public static void main(String[] args) throws SQLException {
String url = "jdbc:postgresql://localhost/postgres?user=postgres&password=postgres";
Connection conn = DriverManager.getConnection(url);
String sql = "SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?";
System.out.println(sql);
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, args[0]);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("paymentType") + " " + rs.getLong("amount"));
}
}
}
이전 예와 동일한 입력으로 이를 실행하면 결제가 되지 않아 악성코드가 작동하지 않음을 알 수 있습니다.해당 문자열과 일치하는 입력:
c:\temp>java Bind salary
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?
salary 50
c:\temp>java Bind "salary' OR 'a'!='b"
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?
기본적으로 준비된 문을 사용하면 잠재적인 해커로부터 들어오는 데이터는 데이터로 취급됩니다. 또한 애플리케이션 SQL과 혼합하거나 SQL로 해석할 수 있는 방법은 없습니다(전달된 데이터를 애플리케이션 SQL에 직접 넣을 때 발생할 수 있음).
준비된 문은 효율적인 쿼리 계획을 찾기 위해 SQL 쿼리를 먼저 "준비"하고 나중에 양식에서 들어온 실제 값을 전송하기 때문입니다. 이때 쿼리가 실제로 실행됩니다.
자세한 정보는 다음과 같습니다.
저는 답을 다 읽었지만 여전히 준비된 진술의 본질을 보여주는 요점을 강조해야 할 필요성을 느꼈습니다.사용자 입력이 관련된 데이터베이스를 쿼리하는 두 가지 방법을 생각해 보십시오.
나이브 어프로치
하나는 사용자 입력을 일부 SQL 문자열과 연결하여 SQL 문을 생성합니다.이 경우 사용자는 악의적인 SQL 명령을 내장할 수 있으며 이 명령은 실행을 위해 데이터베이스로 전송됩니다.
String SQLString = "SELECT * FROM CUSTOMERS WHERE NAME='"+userInput+"'"
예를 들어 악의적인 사용자 입력은SQLString과 동등한"SELECT * FROM CUSTOMERS WHERE NAME='James';DROP TABLE CUSTOMERS;'
악의적인 사용자로 인해,SQLString2개의 문장이 포함되어 있습니다. 여기서 두 번째 문장("DROP TABLE CUSTOMERS")에 위해를 가할 것입니다.
준비된 문
이 경우 쿼리와 데이터의 분리로 인해 사용자 입력은 SQL 문으로 처리되지 않으므로 실행되지 않습니다.그렇기 때문에 악의적인 SQL 코드를 주입해도 아무런 해를 끼치지 않습니다.그래서."DROP TABLE CUSTOMERS"위의 경우에는 절대로 실행되지 않을 것입니다.
한마디로 사용자 입력을 통해 유입된 준비된 진술로 악성코드는 실행되지 않을 것입니다.
준비된 문을 생성하여 DBMS로 전송하면 SQL 쿼리로 저장되어 실행됩니다.
나중에 DBMS가 해당 데이터를 실행(파라미터화)을 위한 쿼리 매개변수로 사용하도록 데이터를 쿼리에 바인딩할 수 있습니다.DBMS는 사용자가 바인딩한 데이터를 이미 컴파일된 SQL 쿼리에 대한 보충 자료로 사용하지 않고 단순히 데이터만 사용합니다.
이는 준비된 문을 사용하여 SQL 주입을 수행하는 것이 근본적으로 불가능하다는 것을 의미합니다.준비된 문장의 특성과 DBMS와의 관계가 이를 방지합니다.
SQL Server에서는 입력 매개 변수가 쿼리를 구성하지 않기 때문에 준비된 문을 사용하는 것이 확실히 주입 방지입니다.실행된 쿼리가 동적 쿼리가 아님을 의미합니다.SQL 주입 취약성 문의 예입니다.
string sqlquery = "select * from table where username='" + inputusername +"' and password='" + pass + "'";
이제 inoutusername 변수의 값이 a' 또는 1=1 --와 같은 경우 이 쿼리는 다음과 같습니다.
select * from table where username='a' or 1=1 -- and password=asda
그리고 나머지는 다음에 댓글을 달았습니다.--, 따라서 아래와 같이 준비된 문 예제를 사용하여 실행 및 바이패스되지 않습니다.
Sqlcommand command = new sqlcommand("select * from table where username = @userinput and password=@pass");
command.Parameters.Add(new SqlParameter("@userinput", 100));
command.Parameters.Add(new SqlParameter("@pass", 100));
command.prepare();
따라서 사실상 다른 파라미터를 보낼 수 없으므로 SQL 주입을 피할 수 있습니다.
핵심 문구는.need not be correctly escaped. 즉, 대시, 아포스트로피, 인용문 등을 던지려는 사람들에 대해 걱정할 필요가 없다는 뜻입니다.
모든 것은 당신을 위해 처리됩니다.
ResultSet rs = statement.executeQuery("select * from foo where value = " + httpRequest.getParameter("filter");
당신이 서블릿에 그것을 가지고 있다고 가정해 보겠습니다.악의적인 사람이 '필터' 값을 잘못 전달한 경우 데이터베이스를 해킹할 수 있습니다.
근본 원인 #1 - 구분 기호 문제
sql 주입은 따옴표를 사용하여 문자열을 구분하고 문자열의 일부가 되어 해석이 불가능하기 때문에 가능합니다.문자열 데이터에 사용할 수 없는 구분자가 있었다면 sql 주입은 절대 일어나지 않았을 것입니다.구분 기호 문제를 해결하면 sql 주입 문제가 사라집니다.구조 쿼리가 이를 수행합니다.
Root Cause #2 - Human Nature, People are Crafty and Some Crafty People Are Malicious And All People Make Mistakes
The other root cause of sql injection is human nature. People, including programmers, make mistakes. When you make a mistake on a structured query, it does not make your system vulnerable to sql injection. If you are not using structured queries, mistakes can generate sql injection vulnerability.
How Structured Queries Resolve the Root Causes of SQL Injection
Structured Queries Solve The Delimiter Problem, by by putting sql commands in one statement and putting the data in a separate programming statement. Programming statements create the separation needed.
Structured queries help prevent human error from creating critical security holes. With regard to humans making mistakes, sql injection cannot happen when structure queries are used. There are ways of preventing sql injection that don't involve structured queries, but normal human error in that approaches usually leads to at least some exposure to sql injection. Structured Queries are fail safe from sql injection. You can make all the mistakes in the world, almost, with structured queries, same as any other programming, but none that you can make can be turned into a ssstem taken over by sql injection. That is why people like to say this is the right way to prevent sql injection.
So, there you have it, the causes of sql injection and the nature structured queries that makes them impossible when they are used.
The simple example:
"select * from myTable where name = " + condition;
And if user input is:
'123'; delete from myTable; commit;
The query will be executed like this:
select * from myTable where name = '123'; delete from myTable; commit;
ReferenceURL : https://stackoverflow.com/questions/8263371/how-can-prepared-statements-protect-from-sql-injection-attacks
'codememo' 카테고리의 다른 글
| 우커머스 주문에서 패키지당 배송비를 어떻게 가져오나요? (0) | 2023.09.20 |
|---|---|
| 절차 프로그램과 객체 지향 프로그램의 차이점은 무엇입니까? (0) | 2023.09.20 |
| 카탈로그 가시성 설정 숨겨진 우-커머스 (0) | 2023.09.20 |
| 폰트 어썸(Chrome) 경고: "청렴도 불일치", "적절한" 값, "요청 자격 증명이 일치하지 않음" (0) | 2023.09.20 |
| pthread mutex로 변수를 보호하면 캐시되지 않는 것이 보장됩니까? (0) | 2023.09.15 |