복붙노트

htmlspecialchars와 mysql_real_escape_string은 PHP 코드를 주입으로부터 안전하게 유지합니까?

PHP

htmlspecialchars와 mysql_real_escape_string은 PHP 코드를 주입으로부터 안전하게 유지합니까?

오늘은 웹 앱의 입력 검증 전략에 관한 질문이있었습니다.

이 글을 쓰는 시점에서의 가장 중요한 대답은 PHP에서 htmlspecialchars와 mysql_real_escape_string을 사용하는 것입니다.

내 질문은 : 이것은 항상 충분한가요? 더 알아야 할 것이 있습니까? 이 기능들은 어디서 고장 났는가?

해결법

  1. ==============================

    1.데이터베이스 쿼리에 관해서는 항상 준비된 매개 변수화 된 쿼리를 사용해보십시오. mysqli와 PDO 라이브러리는 이것을 지원한다. 이것은 mysql_real_escape_string과 같은 이스케이프 함수를 사용하는 것보다 훨씬 안전합니다.

    데이터베이스 쿼리에 관해서는 항상 준비된 매개 변수화 된 쿼리를 사용해보십시오. mysqli와 PDO 라이브러리는 이것을 지원한다. 이것은 mysql_real_escape_string과 같은 이스케이프 함수를 사용하는 것보다 훨씬 안전합니다.

    예, mysql_real_escape_string은 사실 단순한 문자열 이스케이프 함수입니다. 그것은 마법의 총알이 아닙니다. 위험한 문자를 이스케이프 처리하면 단일 쿼리 문자열에서 안전하게 사용할 수 있습니다. 그러나 입력 내용을 미리 살균하지 않으면 특정 공격 경로에 취약합니다.

    다음 SQL을 상상해보십시오.

    $result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);
    

    이 취약점이 악용 될 수 있음을 알 수 있어야합니다. id 매개 변수에 일반적인 공격 경로가 포함되어 있다고 상상해보십시오.

    1 OR 1=1
    

    인코딩 할 위험 문자가 없으므로 이스케이프 필터를 통과합니다. 우리를 떠나기 :

    SELECT fields FROM table WHERE id= 1 OR 1=1
    

    멋진 SQL 삽입 벡터이며 공격자가 모든 행을 반환 할 수 있습니다. 또는

    1 or is_admin=1 order by id limit 1
    

    생산하는

    SELECT fields FROM table WHERE id=1 or is_admin=1 order by id limit 1
    

    따라서 공격자는이 가상의 예에서 첫 번째 관리자의 세부 정보를 반환 할 수 있습니다.

    이 기능은 유용하지만주의해서 사용해야합니다. 모든 웹 입력을 어느 정도 검증해야합니다. 이 경우 숫자로 사용하는 변수가 실제로 숫자인지 확인하지 않았으므로 악용 될 수 있음을 알 수 있습니다. PHP에서는 입력이 정수, 부동 소수점, 영숫자 등인지 확인하기 위해 함수 세트를 널리 사용해야합니다. 그러나 SQL에 관해서는 준비된 명령문의 가치에 유의하십시오. 데이터베이스 함수가 ​​1 OR 1 = 1이 유효한 리터럴이 아니라는 것을 알고 있었으므로 위의 코드는 준비된 문인 경우 안전합니다.

    htmlspecialchars ()를 참조하십시오. 그것은 그 자체의 지뢰밭입니다.

    PHP에는 다양한 HTML 관련 이스케이프 함수가 있으며, 정확히 어떤 함수가 무엇을하는지에 대한 명확한 지침이 없다는 점에서 실제 문제가 있습니다.

    첫째, HTML 태그 안에 있다면 실제 문제가됩니다. 보다

    echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';
    

    우리는 이미 HTML 태그 안에 있으므로, 위험한 것을하기 위해 <또는>가 필요하지 않습니다. 우리의 공격 벡터는 javascript 일 수 있습니다 : alert (document.cookie)

    이제 결과 HTML은 다음과 같이 보입니다.

    <img src= "javascript:alert(document.cookie)" />
    

    공격은 곧장 끝납니다.

    더 심해진다. 왜? 왜냐하면 htmlspecialchars (이 방식이라고 할 때)는 단일 따옴표가 아닌 큰 따옴표 만 인코딩하기 때문입니다. 그래서 우리가

    echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";
    

    우리의 사악한 공격자는 이제 완전히 새로운 매개 변수를 주입 할 수 있습니다.

    pic.png' onclick='location.href=xxx' onmouseover='...
    

    우리에게 주어지다

    <img src='pic.png' onclick='location.href=xxx' onmouseover='...' />
    

    이 경우에는 마법의 탄환이 없으므로 직접 입력을해야합니다. 잘못된 문자를 필터링하려고 시도하면 반드시 실패합니다. 화이트리스트 접근 방식을 사용하고 좋은 문자 만 처리하십시오. 다양한 벡터가 어떻게 될 수 있는지에 대한 예제는 XSS 치트 시트를보십시오.

    HTML 태그 외부에서 htmlspecialchars ($ string)를 사용하더라도 멀티 바이트 문자 집합 공격 벡터에 여전히 취약합니다.

    다음과 같이 mb_convert_encoding과 htmlentities의 조합을 사용하는 것이 가장 효과적 일 수 있습니다.

    $str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
    $str = htmlentities($str, ENT_QUOTES, 'UTF-8');
    

    UTF를 처리하는 방식 때문에 IE6은 취약한 상태입니다. 그러나 IE6 사용이 중단 될 때까지 ISO-8859-1과 같이보다 제한된 인코딩으로 폴백 할 수 있습니다.

    멀티 바이트 문제에 대한 심층 연구는 https://stackoverflow.com/a/12118602/1820을 참조하십시오.

  2. ==============================

    2.Cheekysoft의 우수한 답변 외에도 :

    Cheekysoft의 우수한 답변 외에도 :

    HTML 삽입 (예 : 크로스 사이트 스크립팅)을 방지하기위한 실버 글 머리 기호는 없지만 HTML을 출력하기 위해 라이브러리 또는 템플릿 시스템을 사용하는 경우 더 쉽게 구현할 수 있습니다. 적절한 탈출 방법에 대한 설명서를 읽으십시오.

    HTML에서는 상황에 따라 다르게 이스케이프 처리해야합니다. 이것은 특히 자바 스크립트에 배치되는 문자열에 해당됩니다.

  3. ==============================

    3.위의 게시물에 분명히 동의 하겠지만 Cheekysoft의 대답에 대한 답변으로 추가 할 작은 것이 하나 있습니다.

    위의 게시물에 분명히 동의 하겠지만 Cheekysoft의 대답에 대한 답변으로 추가 할 작은 것이 하나 있습니다.

    필자는 데이터베이스 클래스에 넣은 간단한 함수를 코딩하여 번호가 아닌 것을 제거합니다. 그것은 preg_replace를 사용하므로 좀 더 최적화 된 기능을 가진 prob가 있지만 핀치로 작동합니다 ...

    function Numbers($input) {
      $input = preg_replace("/[^0-9]/","", $input);
      if($input == '') $input = 0;
      return $input;
    }
    

    그래서 대신에

    나는

    쿼리를 안전하게 실행합니다.

    물론, 그것은 단지 올바른 행을 표시하는 것을 멈추었지만, 나는 당신의 사이트에 SQL을 주입하려고하는 누구에게나 큰 문제라고 생각하지 않는다;)

  4. ==============================

    4.이 퍼즐의 중요한 부분은 컨텍스트입니다. "1 OR 1 = 1"을 ID로 보내는 사람은 쿼리의 모든 인수를 인용 할 경우 문제가되지 않습니다.

    이 퍼즐의 중요한 부분은 컨텍스트입니다. "1 OR 1 = 1"을 ID로 보내는 사람은 쿼리의 모든 인수를 인용 할 경우 문제가되지 않습니다.

    SELECT fields FROM table WHERE id='".mysql_real_escape_string($_GET['id'])."'"
    

    어떤 결과 :

    SELECT fields FROM table WHERE id='1 OR 1=1'
    

    이는 효과가 없다. 문자열을 벗어 났으므로 입력 내용을 문자열 컨텍스트에서 벗어날 수 없습니다. 나는 버전 5.0.45까지 MySQL을 테스트했고, 정수 컬럼에 문자열 컨텍스트를 사용한다고해서 문제가 발생하지는 않는다.

  5. ==============================

    5.

    $result = "SELECT fields FROM table WHERE id = ".(INT) $_GET['id'];
    

    64 비트 시스템에서도 잘 작동합니다. 그러나 많은 수의 주소를 지정하는 데있어 시스템 제한 사항에주의해야하지만 데이터베이스 ID의 경우 99 %의 시간이 걸립니다.

    값을 정리하는 데 하나의 함수 / 메소드를 사용해야합니다. 이 함수가 mysql_real_escape_string ()에 대한 래퍼 일지라도. 왜? 데이터를 정리하는 데 선호하는 방법을 이용한 공격이 발견 된 날이 있기 때문에 시스템 전반의 찾기 및 바꾸기가 아니라 한 곳에서 업데이트하면됩니다.

  6. ==============================

    6.왜, 왜 SQL 문에 사용자 입력과 관련된 따옴표를 넣지 않겠습니까? 꽤 어리석은 것처럼 보이지 않습니다! SQL 문에서 따옴표를 포함하면 "1 또는 1 = 1"이 효과가없는 시도로 렌더링됩니까?

    왜, 왜 SQL 문에 사용자 입력과 관련된 따옴표를 넣지 않겠습니까? 꽤 어리석은 것처럼 보이지 않습니다! SQL 문에서 따옴표를 포함하면 "1 또는 1 = 1"이 효과가없는 시도로 렌더링됩니까?

    이제 사용자가 "사용자가 따옴표 (또는 큰 따옴표)를 입력에 포함하면 어떻게 될까요?"라고 말할 것입니다.

    글쎄, 쉽게 해결할 수 있습니다 : 그냥 사용자 입력시 인용 부호를 삭제하십시오. 예 : input = ~ s / '// g; 어쨌든 나에게 보이는 것처럼, 그 사용자 입력은 안전 할 것이다 ...

  7. from https://stackoverflow.com/questions/110575/do-htmlspecialchars-and-mysql-real-escape-string-keep-my-php-code-safe-from-inje by cc-by-sa and MIT license