많은 유용한 답변과 관련 하여이 스레드에 가치를 더하기를 희망합니다.
SQL 주입은 사용자 입력 (사용자가 입력 한 다음 쿼리 내부에서 사용하는 입력)을 통해 수행 할 수있는 공격입니다. SQL 인젝션 패턴은 올바른 쿼리 구문이지만 호출 할 수 있습니다. 나쁜 이유는 잘못된 쿼리이며 보안의 세 가지 원칙 (기밀성)에 영향을주는 비밀 정보를 얻는 (액세스 제어 우회) 나쁜 사람이 있다고 가정합니다. , 무결성 및 가용성).
이제 우리의 요점은 SQL 주입 공격과 같은 보안 위협을 방지하는 것입니다. (PHP를 사용하여 SQL 주입 공격을 방지하는 방법) 더 사실적이며 데이터 필터링 또는 입력 데이터 지우기는 내부에서 사용자 입력 데이터를 사용할 때의 경우입니다 PHP 나 다른 프로그래밍 언어를 사용한 쿼리는 그렇지 않거나, 더 많은 사람들이 준비된 명령문이나 현재 SQL 주입 방지를 지원하는 다른 도구와 같은 최신 기술을 사용하도록 권장하는 경우 이러한 도구를 더 이상 사용할 수 없다고 생각하십니까? 애플리케이션을 어떻게 보호합니까?
SQL 삽입에 대한 나의 접근 방식은 사용자 입력 데이터를 데이터베이스로 보내기 전에 (쿼리 내에서 사용하기 전에) 지우는 것입니다.
데이터 필터링 (안전하지 않은 데이터를 안전한 데이터로 변환)
PDO 및 MySQLi 를 사용할 수 없다는 것을 고려하십시오 . 애플리케이션을 어떻게 보호 할 수 있습니까? 내가 그들을 사용하도록 강요합니까? PHP 이외의 다른 언어는 어떻습니까? 나는 특정 언어뿐만 아니라 더 넓은 국경에 사용될 수있는 일반적인 아이디어를 선호한다.
- SQL 사용자 (제한된 사용자 권한) : 가장 일반적인 SQL 작업은 (SELECT, UPDATE, INSERT)인데, 왜 필요하지 않은 사용자에게 UPDATE 권한을 부여합니까? 예를 들어, 로그인 및 검색 페이지 는 SELECT 만 사용하는 경우 높은 권한으로이 페이지에서 DB 사용자를 사용하는 이유는 무엇입니까?
규칙 : 모든 권한에 대해 하나의 데이터베이스 사용자를 작성하지 마십시오. 모든 SQL 작업에서 (deluser, selectuser, updateuser)와 같은 체계를 사용자 이름으로 만들어 쉽게 사용할 수 있습니다.
최소 권한 원칙을 참조하십시오 .
데이터 필터링 : 쿼리 사용자 입력을 작성하기 전에 유효성을 검사하고 필터링해야합니다. 프로그래머의 경우 각 사용자 입력 변수에 대한 일부 속성 ( 데이터 유형, 데이터 패턴 및 데이터 길이) 을 정의하는 것이 중요합니다
. (x와 y) 사이의 숫자 인 필드는 정확한 규칙과 문자열 (텍스트) 인 필드에 대해 정확하게 유효성을 검사해야합니다. 예를 들어, 패턴은 경우입니다. [a-zA-Z0-9_-.]라고 말합니다. 길이는 (x와 n)에서 x와 n (정수, x <= n)입니다.
규칙 : 정확한 필터와 유효성 검사 규칙을 만드는 것이 가장 좋습니다.
다른 도구를 사용하십시오. 여기서는 준비된 문 (매개 변수화 된 쿼리) 및 저장 프로 시저에 동의합니다. 여기서 단점은 이러한 방식에는 대부분의 사용자에게는 존재하지 않는 고급 기술이 필요하다는 것입니다. 여기서 기본 아이디어는 SQL 쿼리와 내부에서 사용되는 데이터를 구별하는 것입니다. 여기서 사용자 입력 데이터는 (any 또는 x = x)와 같이 원래 쿼리에 아무것도 추가하지 않기 때문에 안전하지 않은 데이터에서도 두 가지 방법을 모두 사용할 수 있습니다.
자세한 내용은 OWASP SQL 인젝션 방지 치트 시트를 참조하십시오 .
이제 고급 사용자라면 원하는대로이 방어를 사용하기 시작하지만 초보자는 저장 프로 시저를 빠르게 구현하고 명령문을 준비 할 수 없으면 입력 데이터를 최대한 필터링하는 것이 좋습니다.
마지막으로, 사용자가 자신의 사용자 이름을 입력하는 대신 아래에이 텍스트를 전송한다고 가정 해 보겠습니다.
[1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = 'root'
이 입력은 준비된 명령문 및 스토어드 프로 시저없이 조기에 점검 할 수 있지만 사용자 데이터 필터링 및 유효성 검증 후에 시작하여 안전하게 사용할 수 있습니다.
마지막 요점은 더 많은 노력과 복잡성이 필요한 예기치 않은 동작을 감지하는 것입니다. 일반적인 웹 애플리케이션에는 권장되지 않습니다.
위의 사용자 입력에서 예기치 않은 동작은 SELECT, UNION, IF, SUBSTRING, BENCHMARK, SHA 및 root입니다. 이러한 단어가 감지되면 입력을 피할 수 있습니다.
업데이트 1 :
사용자가이 게시물이 쓸모 없다고 댓글을 달았습니다. OWASP.ORG가 제공 한 내용은 다음과 같습니다 .
기본 방어 :
옵션 # 1 : 준비된 문 사용 (매개 변수화 된 쿼리)
옵션 # 2 : 저장 프로 시저 사용
옵션 # 3 : 모든 사용자 제공 입력 탈출
추가 방어 :
또한 시행 : 최소 권한
수행 : 화이트리스트 입력 유효성 검사
아시다시피, 기사를 주장하는 것은 적어도 하나의 참조로 유효한 주장에 의해 뒷받침되어야합니다! 그렇지 않으면 공격과 나쁜 주장으로 간주됩니다!
업데이트 2 :
PHP 매뉴얼, PHP : Prepared Statements-Manual :
이스케이프 및 SQL 인젝션
바운드 변수는 서버에 의해 자동으로 이스케이프됩니다. 서버는 실행 전에 적절한 위치에서 이스케이프 된 값을 명령문 템플리트에 삽입합니다. 적절한 변환을 작성하려면 바운드 변수 유형에 대한 힌트를 서버에 제공해야합니다. 자세한 내용은 mysqli_stmt_bind_param () 함수를 참조하십시오.
서버 내에서 자동으로 값을 이스케이프 처리하는 것은 SQL 삽입을 방지하기위한 보안 기능으로 간주됩니다. 입력 값이 올바르게 이스케이프되면 준비되지 않은 명령문으로 동일한 보안 수준을 달성 할 수 있습니다.
업데이트 3 :
준비된 명령문을 사용할 때 PDO 및 MySQLi가 쿼리를 MySQL 서버에 보내는 방법을 알기위한 테스트 사례를 작성했습니다.
PDO :
$user = "''1''"; // Malicious keyword
$sql = 'SELECT * FROM awa_user WHERE userame =:username';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $user));
쿼리 로그 :
189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\''
189 Quit
MySQLi :
$stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) {
$stmt->bind_param("s", $user);
$user = "''1''";
$stmt->execute();
쿼리 로그 :
188 Prepare SELECT * FROM awa_user WHERE username =?
188 Execute SELECT * FROM awa_user WHERE username ='\'\'1\'\''
188 Quit
준비된 진술이 데이터를 탈출하고 있다는 것은 분명합니다.
위의 진술에서 언급했듯이
서버 내에서 자동으로 값을 이스케이프 처리하는 것은 SQL 삽입을 방지하기위한 보안 기능으로 간주됩니다. 입력 값이 올바르게 이스케이프되면 준비되지 않은 명령문으로 동일한 보안 수준을 달성 할 수 있습니다.
따라서 이는 intval()
쿼리를 보내기 전에 정수 값에 대한 데이터 유효성 검사 가 좋은 아이디어 임을 증명 합니다. 또한 쿼리를 보내기 전에 악의적 인 사용자 데이터를 방지 하는 것이 정확하고 유효한 방법 입니다.
자세한 내용은이 질문을 참조하십시오 : PDO는 원시 쿼리를 MySQL로 보내고 Mysqli는 준비된 쿼리를 보냅니다. 둘 다 동일한 결과를 생성합니다
참고 문헌 :
- SQL 인젝션 치트 시트
- SQL 인젝션
- 정보 보안
- 보안 원칙
- 데이터 유효성 검사