[php] 드롭 다운을 사용하는 경우 SQL 주입을 방지해야합니까?

주로 SQL 삽입의 기회로 인해 양식의 사용자 입력을 신뢰해서는 안된다는 것을 이해합니다.

그러나 이것은 드롭 다운에서 유일한 입력 인 양식에도 적용됩니까 (아래 참조)?

나는 $_POST['size']세션에 저장하고 있으며, 사이트 전체에서 다양한 데이터베이스 ( mysqli선택 쿼리 사용) 를 쿼리하는 데 사용되며 모든 SQL 주입은 확실히 해를 끼칠 것입니다 (아마도 삭제).

데이터베이스를 쿼리하기위한 입력 된 사용자 입력 영역이 없으며 드롭 다운 만 있습니다.

<form action="welcome.php" method="post">
<select name="size">
  <option value="All">Select Size</option>
  <option value="Large">Large</option>
  <option value="Medium">Medium</option>
  <option value="Small">Small</option>
</select>
<input type="submit">
</form>



답변

게시 된 크기가 예상 한 크기인지 확인하기 위해 다음 예제와 같이 간단한 작업을 수행 할 수 있습니다.

$possibleOptions = array('All', 'Large', 'Medium', 'Small');

if(in_array($_POST['size'], $possibleOptions)) {
    // Expected
} else {
    // Not Expected
}

그런 다음 결과를 저장하려면 php> = 5.3.0 버전을 사용하는 경우 mysqli_ *를 사용하십시오. 올바르게 사용하면 SQL 주입에 도움이됩니다.


답변

네, 이것으로부터 보호해야합니다.

Firefox의 개발자 콘솔을 사용하여 이유를 보여 드리겠습니다.

드롭 다운의 값 중 하나를 드롭 테이블 문으로 편집했습니다.

이 데이터를 정리하지 않으면 데이터베이스가 파괴됩니다. (이것은 완전히 유효한 SQL 문이 아닐 수도 있지만 제 요점을 이해했으면합니다.)

드롭 다운에서 사용할 수있는 옵션을 제한했다고 해서 내가 서버에 보낼 수있는 데이터가 제한 되었다는 의미는 아닙니다 .

페이지에서 동작을 사용하여 이것을 추가로 제한하려는 경우 내 옵션에는 해당 동작을 비활성화하거나 어쨌든이 양식 제출을 모방하는 사용자 지정 HTTP 요청을 서버에 작성하는 것이 포함됩니다. 이라는 도구의 정확히 사용은, 내가 생각하는 명령은 다음과 같이 보일 것이다 어쨌든이 SQL 주입 제출 :

curl --data "size=%27%29%3B%20DROP%20TABLE%20*%3B%20--"  http://www.example.com/profile/save

(이것은 완전히 유효한 curl 명령이 아닐 수도 있지만, 다시 말하지만 제 요점을 이해했으면합니다.)

그래서 반복하겠습니다.

사용자 입력을 신뢰하지 마십시오. 항상 자신을 보호하십시오.

사용자 입력이 안전하다고 가정하지 마십시오. 양식이 아닌 다른 수단을 통해 도착하더라도 잠재적으로 안전하지 않습니다. SQL 주입으로부터 자신을 보호하는 것을 잊을만큼 신뢰할 수있는 것은 없습니다.


답변

이 질문에 태그가 지정되었으므로 , 다음은 이러한 특정 유형의 공격에 대한 답변입니다.

주석에서 언급했듯이 모든 변수 데이터와 관련된 모든 단일 쿼리에 대해 준비된 문 예외없이 사용해야 합니다.

HTML에 관계없이!
SQL 쿼리는 HTML 입력 또는 기타 모든 외부 요인에 관계없이 올바르게 형식화되어야 함을 이해하는 것이 중요합니다 .

입력 유효성 검사 목적으로 다른 답변에서 제안 된 화이트리스트를 사용할 수 있지만 SQL 관련 작업에는 영향을주지 않아야합니다. HTML 입력의 유효성을 검사했는지 여부에 관계없이 동일하게 유지되어야합니다. 이는 쿼리에 변수를 추가 할 때 준비된 문을 사용해야 함을 의미합니다.

여기에서 철저한 설명, 준비된 명령문이 필수 인 이유, 적절하게 사용하는 방법, 적용 할 수없는 경우 및 이러한 경우 수행 할 작업을 찾을 수 있습니다. The Hitchhiker ‘s Guide to SQL Injection protection

또한이 질문에는 . 대부분 우연이라고 생각하지만 어쨌든 원시 mysqli 가 이전 mysq_ * 함수를 적절하게 대체하지 않는다는 점을 경고해야 합니다 . 단순히 이전 스타일로 사용하면 보안이 전혀 추가되지 않기 때문입니다. 준비된 명령문에 대한 지원은 고통스럽고 번거롭지 만 일반 PHP 사용자는 전혀 노력할 수 없을 정도입니다. 따라서 ORM 또는 일종의 추상화 라이브러리가 옵션이 아닌 경우 PDO 가 유일한 선택입니다.


답변

예.

누구나 실제로 전송 된 값에 대해 무엇이든 스푸핑 할 수 있습니다.

따라서 드롭 다운 메뉴의 유효성을 검사하려면 작업중인 값이 드롭 다운에 있는지 확인하면됩니다. 다음과 같은 것이 가장 좋은 (가장 건전한 편집증적인) 방법입니다.

if(in_array($_POST['ddMenu'], $dropDownValues){

    $valueYouUseLaterInPDO = $dropDownValues[array_search("two", $arr)];

} else {

    die("effin h4x0rs! Keep off my LAMP!!");

}


답변

사용자가 콘솔을 사용하여 드롭 다운을 변경하지 못하도록 보호하는 한 가지 방법은 정수 값만 사용하는 것입니다. 그런 다음 POST 값에 정수가 포함되어 있는지 확인하고 필요할 때 배열을 사용하여 텍스트로 변환 할 수 있습니다. 예 :

<?php
// No, you don't need to specify the numbers in the array but as we're using them I always find having them visually there helpful.
$sizes = array(0 => 'All', 1 => 'Large', 2 => 'Medium', 3 => 'Small');
$size = filter_input(INPUT_POST, "size", FILTER_VALIDATE_INT);

echo '<select name="size">';
foreach($sizes as $i => $s) {
    echo '<option value="' . $i . '"' . ($i == $size ? ' selected' : '') . '>' . $s . '</option>';
}
echo '</select>';

그런 다음 또는 정수만 $size포함한다는 사실을 알고 쿼리에서 사용할 수 있습니다 FALSE.


답변

다른 답변은 이미 알아야 할 사항을 다룹니다. 하지만 좀 더 명확히하면 도움이 될 수 있습니다.

다음 가지 작업을 수행해야합니다.

1. 양식 데이터의 유효성을 검사합니다.

조나단 홉스 ‘응답 쇼는 매우 명확 양식 입력을위한 HTML 요소의 선택을 위해 신뢰할 수있는 모든 필터링을하지 않습니다.

유효성 검사는 일반적으로 데이터를 변경하지 않지만 “이 항목을 수정하십시오”로 표시된 필드와 함께 양식을 다시 표시하는 방식으로 수행됩니다.

대부분의 프레임 워크와 CMS에는이 작업에 도움이되는 양식 작성기가 있습니다. 뿐만 아니라 공격의 또 다른 형태 인 CSRF (또는 “XSRF”)에 대해서도 도움이됩니다.

2. SQL 문에서 변수 삭제 / 이스케이프 ..

.. 또는 준비된 진술이 당신을 위해 일을하도록하십시오.

사용자가 제공하거나 제공하지 않은 변수를 사용하여 (My) SQL 문을 작성하는 경우 이러한 변수를 이스케이프하고 인용해야합니다.

일반적으로 MySQL 문에 삽입하는 이러한 변수는 문자열이거나 PHP가 안정적으로 MySQL이 소화 할 수있는 문자열로 변환 할 수있는 변수 여야합니다. 예 : 숫자.

문자열의 경우 여러 방법 중 하나를 선택하여 문자열을 이스케이프해야합니다. 즉, MySQL에서 부작용이있는 모든 문자를 대체해야합니다.

  • 구식 MySQL + PHP에서는 mysql_real_escape_string ()이 작업을 수행합니다. 문제는 잊기 너무 쉽기 때문에 준비된 명령문이나 쿼리 작성기를 반드시 사용해야한다는 것입니다.
  • MySQLi에서는 준비된 문을 사용할 수 있습니다.
  • 대부분의 프레임 워크와 CMS는이 작업에 도움이되는 쿼리 작성기를 제공합니다.

숫자를 다루는 경우 이스케이프와 따옴표를 생략 할 수 있습니다 (이것이 준비된 명령문에서 유형을 지정할 수있는 이유입니다).

데이터베이스 자체가 아니라 SQL 문에 대한 변수 이스케이프한다는 점을 지적하는 것이 중요 합니다 . 데이터베이스는 원래 문자열을 저장하지만 명령문에는 이스케이프 된 버전이 필요합니다.

이 중 하나를 생략하면 어떻게됩니까?

양식 유효성 검사를 사용하지 않지만 SQL 입력을 삭제하면 모든 종류의 잘못된 작업이 발생할 수 있지만 SQL 주입은 표시되지 않습니다! (*)

첫째, 계획하지 않은 상태로 신청서를 보낼 수 있습니다. 예를 들어 모든 사용자의 평균 연령을 계산하고 싶지만 한 사용자가 해당 연령에 대해 “aljkdfaqer”를 지정하면 계산이 실패합니다.

둘째, 고려해야 할 다른 모든 종류의 인젝션 공격이있을 수 있습니다. 예를 들어 사용자 입력에 javascript 또는 기타 항목이 포함될 수 있습니다.

데이터베이스에 여전히 문제가있을 수 있습니다. 예를 들어 필드 (데이터베이스 테이블 열)가 255 자로 제한되고 문자열이 그보다 긴 경우. 또는 필드에 숫자 만 허용되고 대신 숫자가 아닌 문자열을 저장하려고 시도하는 경우. 그러나 이것은 “주입”이 아니라 “응용 프로그램 충돌”일뿐입니다.

그러나 유효성 검사없이 입력을 허용하는 자유 텍스트 필드가 있어도 데이터베이스 문으로 이동할 때 적절하게 이스케이프하면 그대로 데이터베이스에 저장할 수 있습니다. 이 문자열을 어딘가에서 사용하려는 경우 문제가 발생합니다.

(*) 아니면 이건 정말 이국적인 것입니다.

SQL 문에 대한 변수를 이스케이프하지 않고 양식 입력의 유효성을 검사 한 경우 여전히 잘못된 작업이 발생하는 것을 볼 수 있습니다.

첫째, 데이터를 데이터베이스에 저장하고 다시로드하면 더 이상 동일한 데이터가 아닌 “번역에서 손실”될 위험이 있습니다.

둘째, 잘못된 SQL 문이 발생하여 애플리케이션이 중단 될 수 있습니다. 예를 들어 어떤 변수에 따옴표 또는 큰 따옴표 문자가 포함되어 있으면 사용하는 따옴표 유형에 따라 잘못된 MySQL 문이 표시됩니다.

셋째, 여전히 SQL 주입이 발생할 수 있습니다.

양식의 사용자 입력이 이미 필터링 / 검증 된 경우, 입력이 하드 코딩 된 옵션 목록으로 축소되거나 숫자로 제한되는 경우 의도적 인 SQl 삽입 가능성이 줄어들 수 있습니다. 그러나 SQL 문에서 변수를 제대로 이스케이프하지 않으면 자유 텍스트 입력을 SQL 주입에 사용할 수 있습니다.

양식 입력이 전혀 없더라도 파일 시스템에서 읽거나 인터넷에서 스크랩 한 등 모든 종류의 소스에서 가져온 문자열을 가질 수 있습니다. 아무도 이러한 문자열이 안전하다고 보장 할 수 없습니다.


답변

웹 브라우저는 php에서 페이지를 수신하고 있다는 것을 “인식”하지 못합니다. 보는 것은 html뿐입니다. 그리고 http 계층은 그보다 더 적게 알고 있습니다. http 계층을 통과 할 수있는 거의 모든 종류의 입력을 처리 할 수 ​​있어야합니다 (다행히도 대부분의 입력 PHP에서는 이미 오류가 발생합니다). 악의적 인 요청이 db를 엉망으로 만드는 것을 막으려면 상대방이 자신이 무엇을하고 있는지 알고 있으며 정상적인 상황에서 브라우저에서 볼 수있는 것에 제한되지 않는다고 가정해야합니다. 브라우저의 개발자 도구로 무엇을 조작 할 수 있는지는 말할 것도 없습니다.) 그렇습니다. 드롭 다운의 모든 입력을 수용해야하지만 대부분의 입력에 대해 오류가 발생할 수 있습니다.