준비된 명령문 은 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);
Inject 클래스는 SQL 주입에 취약합니다. 쿼리는 사용자 입력과 함께 동적으로 붙여집니다. 이 쿼리의 목적은 Bob에 대한 정보를 표시하는 것입니다. 사용자 입력에 따른 급여 또는 보너스. 그러나 악의적 인 사용자는 where 절과 ‘또는 true’에 해당하는 명령을 실행하여 쿼리를 손상시키는 입력을 조작하여 숨겨져 있던 Aaron에 대한 정보를 포함하여 모든 것이 반환됩니다.
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 문 캐시 적중이 적어 지지만 바인드 예제는 항상 동일한 명령문을 실행 함).
이러한 종류의 주입을 피하기위한 바인딩의 예는 다음과 같습니다.
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"));
}
}
}
이전 예제와 동일한 입력으로 이것을 실행하면 해당 문자열과 일치하는 paymentType이 없기 때문에 악성 코드가 작동하지 않음을 나타냅니다.
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;'
악의적 인 사용자로 인해 SQLString
두 번째 문 ( "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
입니다. 즉, 대시, 아포스트로피, 따옴표 등을 던지는 사람들에 대해 걱정할 필요가 없습니다.
그것은 모두 당신을 위해 처리됩니다.