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


96

주로 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>

112
예. 공격자가 입력에 원하는 값을 제출하는 것을 막는 것은 없습니다 <select>. 실제로 약간 기술적 인 사용자라도 브라우저 콘솔을 사용하여 추가 옵션을 추가 할 수 있습니다. 당신이 화이트리스트 사용 가능한 값의 배열을 유지하고 대한 입력을 비교하면 (원치 않는 값을 방지하기 때문에 당신은해야한다), 당신은을 완화 할 수
마이클 Berkowski을

13
기본적인 요청 / 응답 사항과 요청에 대해 프런트 엔드가 구축되는 방식, 즉이 경우 드롭 다운이 중요하지 않은 점을 이해해야합니다
Royal Bg

13
@YourCommonSense는 좋은 질문이기 때문에. 모든 사람이 클라이언트가 얼마나 조작 가능한지 깨닫지는 못합니다. 이것은이 사이트에 대한 매우 귀중한 답변을 불러 일으킬 것입니다.
Cruncher 2014 년

8
@Cruncher 알겠습니다. 평균적인 stackoverflowian에게 그것은 그들이 전에 들었던 로켓 과학입니다. PHP 태그에서 가장 많이 찬성 된 질문에도 불구하고.
당신의 상식

9
"사용자 입력을 절대 신뢰해서는 안된다는 것을 이해합니다." 예외 없음.
Prinzhorn

답변:


69

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

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

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

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


이것은 '화이트리스트'OliverBS의 축약 형 버전입니까?
Tatters

매우 기본적인 버전이 아니라 데이터베이스에 값을 추가하여 더 쉽고 재사용 할 수 있도록 할 수도 있고, 각 화이트리스트에 대해 검사 할 특정 메서드가있는 화이트리스트 클래스를 만들 수도 있습니다. 데이터베이스를 사용하지 않으려는 경우 화이트리스트 속성은 화이트리스트 클래스의 배열 속성 내에있을 수 있습니다.
Oliver Bayes-Shelton 2014 년

9
그럼에도 불구하고 Prepared Statements (권장) 또는 mysqli_real_escape_string. 또한 출력 할 때 값을 적절하게 이스케이프하십시오 (예 : HTML 문서에서 htmlspecialchars () 사용 ).
ComFreek

4
엄격한 비교 in_arraytrue위해 to 의 세 번째 매개 변수를 설정하는 것이 좋습니다 . 나는 무엇이 잘못 될 수 있는지 잘 모르겠지만 느슨한 비교는 꽤 기발합니다.
Brilliand

1
@OliverBS $ _POST 값은 배열이 될 수도 있습니다. 숫자 문자열은 숫자로 비교됩니다 ( '5'== '05'). 특정 예에 보안 허점이 있다고 생각하지 않지만 규칙은 복잡하고 내가 이해하지 못하는 이유로 허점이 열릴 수 있습니다. 엄격한 비교는 추론하기 쉬우므로 안전하게 사용하기가 더 쉽습니다.
Brilliand

195

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

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

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

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

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

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

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

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

그래서 반복하겠습니다.

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

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


24
.NET을 사용하여 사용자 지정 페이로드를 만드는 것은 말할 것도 없습니다 curl. 항상 입력 서버 측을 삭제하십시오 !
recursion.ninja

14
이미지는 천 단어 이상을 말합니다.
davidkonrad

4
이것이 기본 답변이어야합니다. 또한에 대한 내용을 포함해야합니다 curl. 사람들은 모든 형식을 사용하고 값을 전달하여 어디에서나 HTTP 요청을 보낼 수 있다는 것을 이해하지 못합니다. 요청을 처리하기 전에 요청이 유효한지 확인하는 것은 서버의 몫입니다.
retrohacker

2
얼마나 귀여워! 작은 바비 테이블입니다!
Aura

45

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

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

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

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

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

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


5
i = 랜덤 (0, 15); // i를 사용하는 일부 쿼리. 여기에 성명서를 준비해야합니까?
Cruncher 2014 년

2
의 구현은 random무엇입니까?
Slicedpan 2014 년

9
@YourCommonSense 좁은 시야? 나에게 "항상 X를하라. 그리고 나는 그것에 대한 이유를 제공하지 않을 것이다"는 좁은 시각으로 보인다.
Cruncher 2014 년

5
@Cruncher 항상 모든 것을 위해 항상 준비된 진술을 사용 하지 않는 이유를 생각할 수 없습니다 . 하나 말해 줄래?
Wesley Murch

3
@Cruncher 동의합니다. Devil 's Advocate 역할을하는 것 같습니다. 대답의 규정은 또한 "모든 가변 데이터 포함" 입니다. PHP int 캐스팅과 같은 몇 가지 경우가 있지만 준비된 문을 사용하는 것이 더 좋습니다. (경험이없는) 사람들에게 사소한 성능 "부스트"가 보안보다 더 중요하다고 말하는 것은 멀어집니다. 대답은 "불완전"하지만 다른 사람들이 무시하고 있다는 강력한 메시지를 보냅니다. 제 사건을 쉬겠습니다.
Wesley Murch

12

예.

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

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

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

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

} else {

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

}

5
그 주사에 관계없이 값이 설정되어 무엇을 할 수 없습니다 그래서이 답변은 또한 당신이 준비된 문을 사용한다, 불완전
Slicedpan

7
@Slicedpan 정말? 그 이유를 모른 채 시류에 뛰어 드는 것처럼 들립니다 ... 쿼리에 가능한 입력이 몇 개있어 모두 괜찮은지 확인할 수 있습니다 (내가 만든 이유). 준비된 성명서를 사용하여 추가 보안 혜택을 얻지 못합니다
Cruncher 2014 년

3
준비된 명령문을 규칙으로 사용하면 향후 SQL 주입 취약점이 도입되는 것을 방지 할 수 있습니다.
Slicedpan 2014 년

1
@Cruncher "드롭 다운의 모든 값은 항상 안전 할 것"이라는 약속을하는 것은 매우 안전하지 않은 약속입니다. 값이 변경되지만 코드가 반드시 업데이트되는 것은 아닙니다. 값을 업데이트하는 사람은 안전하지 않은 값이 무엇인지 모를 수도 있습니다! 특히 모든 종류의 보안 문제로 가득 찬 웹 프로그래밍 영역에서 이와 같은 것을 훑어 보는 것은 무책임한 일입니다.
hyde

1
@Cruncher SQL 작업을 적절하게 처리하면 SQL 이 제대로 작동하는 것을 방해하지 않고 모든 입력을 받아 들일 수 있습니다 . SQL 부분은 어디에서 왔는지에 관계없이 무엇이든 받아 들일 준비가되어 있어야합니다. 다른 모든 것은 오류가 발생하기 쉽습니다.
glglgl

8

사용자가 콘솔을 사용하여 드롭 다운을 변경하지 못하도록 보호하는 한 가지 방법은 정수 값만 사용하는 것입니다. 그런 다음 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.


2
@OliverBS filter_input서버 측에서 확인하지 않으면 무엇입니까 ? 아무도 정수 외에는 게시 할 수 없습니다.
Styphon 2014 년

감사합니다 Styphon, 그래서 이것은 OP의 양식을 대체합니까? 그리고 이것은 여러 드롭 다운이있는 더 큰 양식에 적용 할 수 있습니까? 다른 드롭 다운을 추가하여 '색상'이라고 말하면?
Tatters 2014 년

@SamuelTattersfield 예 그리고 예. 원하는만큼 많은 옵션과 함께 원하는만큼 드롭 다운에 사용할 수 있습니다. 각 드롭 다운에 대해 새 어레이를 만들고 어레이의 드롭 다운에 대한 모든 옵션을 입력하면됩니다.
Styphon 2014 년

좋은! 나는 그것을 좋아한다. 나는 그것을 시도하고 내가 테스트에서 얻는 것을 볼 것입니다.
Tatters

@SamuelTattersfield 좋습니다 filter_input. 유효성 검사를 위해 부품도 사용해야합니다 . 그렇지 않으면 보안을 위해 초콜릿 주전자만큼 유용합니다.
Styphon 2014 년

7

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

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

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 주입에 사용할 수 있습니다.

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


나도 너무 오래 데이터는 숫자 필드에 캐릭터 아무것도 충돌하지 않습니다하지
당신의 상식

흠, 방금 시도했는데 실제로 오류 대신 경고가 표시됩니다. 나는 이것을 오류로 바꾸는 것이 PDO라고 생각합니다. 일부 문자열이 varchar에 비해 너무 긴 drupal.org의 여러 문제에서 논의했습니다.
donquixote 2014 년

6

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


6

특정 드롭 다운 목록의 값만 사용하도록 사용자를 제한했다는 사실은 관련이 없습니다. 기술 사용자는 네트워크를 떠나기 전에 서버로 전송 된 http 요청을 캡처하고 로컬 프록시 서버와 같은 도구를 사용하여 변경 한 다음 계속 진행할 수 있습니다. 변경된 요청을 사용하여 드롭 다운 목록에 지정하지 않은 매개 변수 값을 보낼 수 있습니다. 개발자는 클라이언트의 모든 것이 변경 될 수 있으므로 클라이언트 제한이 종종 무의미하다는 사고 방식을 가져야합니다. 클라이언트 데이터가 입력되는 모든 단일 지점 에서 서버 유효성 검사가 필요합니다 . 공격자는이 유일한 측면에서 개발자의 순진함에 의존합니다.


5

SQL 주입을 방지하기 위해 매개 변수화 된 쿼리를 사용하는 것이 가장 좋습니다. 이 경우 쿼리의 모양은 다음과 같습니다.

SELECT * FROM table WHERE size = ?

무결성에 대해 확인되지 않은 텍스트로 위와 같은 쿼리를 제공하고 (입력이 서버에서 유효성이 검사되지 않음) SQL 주입 코드가 포함되어 있으면 올바르게 처리됩니다. 즉, 요청으로 인해 데이터베이스 계층에서 다음과 같은 일이 발생합니다.

SELECT * FROM table WHERE size = 'DROP table;'

이렇게하면 반환되는 결과가 0 개로 선택되어 화이트리스트, 확인 확인 또는 기타 기술없이 쿼리가 실제로 데이터베이스에 해를 끼치는 효과가 없게됩니다. 책임있는 프로그래머는 계층에서 보안을 수행하고 쿼리를 매개 변수화하는 것 외에도 종종 유효성을 검사합니다. 그러나 성능 측면에서 쿼리를 매개 변수화하지 않을 이유는 거의 없으며이 방법으로 추가 된 보안은 매개 변수가있는 쿼리에 익숙해 져야하는 좋은 이유입니다.


4

양식에서 제출 된 모든 내용은 전선을 통해 텍스트로 서버에 제공됩니다. 클라이언트를 모방하거나 원하는 경우 터미널에서 입력하기 위해 봇을 만드는 사람을 막을 수는 없습니다. 당신이 클라이언트를 프로그래밍했기 때문에 그것이 당신이 생각하는 것처럼 행동 할 것이라고 결코 가정하지 마십시오. 스푸핑하기 정말 쉽습니다.

클라이언트를 신뢰할 때 일어날 수있는 일과 일어날 수있는 일의 .


4

해커는 텔넷을 사용하여 요청을 전송하여 자바 스크립트 양식 검사를 포함하여 브라우저를 완전히 우회 할 수 있습니다. 물론, 그는 그가 사용해야하는 필드 이름을 얻기 위해 당신의 html 페이지의 코드를 볼 것이지만, 그때부터는 그에게 '모든 것이 간다'. 따라서 서버에 제출 된 모든 값이 HTML 페이지에서 생성되지 않은 것처럼 확인해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.