최고의 PHP 입력 살균 기능은 무엇입니까?


161

살균하기 위해 모든 문자열을 전달할 수있는 기능을 고안하려고합니다. 따라서 나오는 문자열은 데이터베이스 삽입에 안전합니다. 그러나 필터링 기능 이 너무 많아서 어떤 기능을 사용 해야하는지 확실하지 않습니다.

빈칸을 채우도록 도와주세요 :

function filterThis($string) {
    $string = mysql_real_escape_string($string);
    $string = htmlentities($string);
    etc...
    return $string;
}

4
삽입하려면 mysql_real_escape_string을 사용하여 SQL 삽입에 대해 위생 처리하는 것이 좋습니다. 당신은 당신이를 htmlentities 적용해야 (HTML 출력이나 PHP는 식 / 함수) 선택한 데이터를 사용하는 때이다
davidosomething

데이터베이스 삽입 정리에 대한 답변 은 stackoverflow.com/questions/60174/… 를 참조하십시오 (다른 사람들이 아래에 언급 한 PDO의 예를 제공함).
Pat

답변:


433

중지!

당신은 여기서 실수를하고 있습니다. 아뇨, 데이터를 좀 더 안전하게 만들기 위해 올바른 PHP 기능을 선택했습니다. 괜찮아. 실수는 작업 순서 와 이러한 기능을 사용하는 방법 및 위치입니다.

사용자 데이터 삭제 및 유효성 검사, 스토리지 데이터 이스케이프 및 프리젠 테이션 데이터 이스케이프의 차이점을 이해하는 것이 중요합니다.

사용자 데이터 삭제 및 확인

사용자가 데이터를 제출할 때 원하는 것을 제공했는지 확인해야합니다.

살균 및 필터링

예를 들어 숫자 가 필요한 경우 제출 된 데이터가 숫자인지 확인하십시오 . 사용자 데이터 를 다른 유형으로 캐스트 할 수도 있습니다. 제출 된 모든 것은 처음에 문자열처럼 취급되므로 알려진 숫자 데이터를 정수 또는 부동 소수점으로 강제 설정하면 소독이 빠르고 고통스럽지 않습니다.

자유형 텍스트 필드와 텍스트 영역은 어떻습니까? 해당 필드에 예상치 못한 것이 없는지 확인해야합니다. 주로 HTML 내용이 없어야하는 필드에 실제로 HTML이 포함되어 있지 않은지 확인해야합니다. 이 문제를 처리 할 수있는 두 가지 방법이 있습니다.

먼저 HTML 입력을 빠져 나갈 수 있습니다.htmlspecialchars . htmlentitiesHTML을 중화 하는 데 사용해서는 안됩니다. HTML은 인코딩해야 할 것으로 생각되는 악센트 및 기타 문자의 인코딩도 수행합니다.

둘째, 가능한 HTML을 제거 할 수 있습니다 . strip_tags빠르고 쉽고 빠르지 않습니다. HTML Purifier 는 모든 HTML을 제거하고 태그 및 속성의 선택적 화이트리스트를 허용하는 훨씬 철저한 작업을 수행합니다.

최신 PHP 버전은 에는 필터 확장 기능이 포함 되어있어 사용자 입력을 위생적으로 처리 할 수 ​​있습니다.

확인

제출 된 데이터에 예기치 않은 컨텐츠가 없는지 확인하는 것은 작업의 절반에 불과합니다. 제출 된 데이터에 실제로 작업 할 수있는 값이 포함되어 있는지 확인해야합니다.

1에서 10 사이의 숫자를 예상하면 해당 값을 확인해야합니다. 스피너 및 단계와 함께 새로운 멋진 HTML5 시대 숫자 입력 중 하나를 사용하는 경우 제출 된 데이터가 단계와 일치하는지 확인하십시오.

해당 데이터가 드롭 다운 메뉴에서 가져온 것이면 제출 된 값이 메뉴에 나타나는 값인지 확인하십시오.

다른 요구를 충족시키는 텍스트 입력은 어떻습니까? 예를 들어 날짜 입력은 strtotime또는 DateTime 클래스를 통해 확인해야합니다 . 주어진 날짜는 예상 범위 사이 여야합니다. 이메일 주소는 어떻습니까? 앞에서 언급 한 필터 확장is_email 라이브러리 의 팬이지만 주소의 형식 이 올바른지 확인할 수 있습니다 .

다른 모든 폼 컨트롤에 대해서도 마찬가지입니다 . 라디오 버튼이 있습니까? 목록을 확인하십시오. 확인란이 있습니까? 목록을 확인하십시오. 파일 업로드가 있습니까? 파일이 예상 한 유형인지 확인하고 파일 이름을 필터링되지 않은 사용자 데이터처럼 취급하십시오.

모든 최신 브라우저에는 완벽한 개발자 도구 세트가 내장되어있어 누구나 양식을 조작하기가 쉽지 않습니다. 코드는 사용자가 양식 내용에 대한 모든 클라이언트 측 제한을 완전히 제거했다고 가정해야합니다 !

스토리지를위한 데이터 이스케이프

이제 데이터가 예상 형식으로되어 있고 예상 값만 포함되었으므로 해당 데이터를 스토리지에 유지하는 것에 대해 걱정할 필요가 있습니다.

모든 단일 데이터 저장 메커니즘에는 데이터가 올바르게 이스케이프 및 인코딩되도록하는 특정 방법이 있습니다. SQL을 작성하는 경우 쿼리에서 데이터를 전달하는 방법은 자리 표시자가있는 준비된 명령문을 사용하는 것 입니다.

PHP에서 대부분의 SQL 데이터베이스를 사용하는 더 좋은 방법 중 하나는 PDO 확장 입니다. 명령문준비하고 , 변수를 명령문바인딩 한 다음 , 명령문과 변수를 서버보내는 일반적인 패턴을 따릅니다 . PDO로 작업하지 않은 경우 여기에 꽤 좋은 MySQL 지향 자습서가 있습니다. 있습니다.

일부 SQL 데이터베이스에는 SQL Server , PostgreSQLSQLite 3 등 PHP에서 자체 특수 확장 기능이 있습니다. 이러한 각 확장은 PDO와 동일한 준비 결합 실행 방식으로 작동하는 명령문 지원을 준비했습니다. 비표준 기능이나 동작을 지원하기 위해 PDO 대신 이러한 확장을 사용해야 할 수도 있습니다.

MySQL에는 자체 PHP 확장이 있습니다. 사실 그 중 두 개입니다. mysqli 라는 것을 사용하고 싶습니다 . 이전 "mysql"확장은 더 이상 사용되지 않으며 현대에 사용하기에 안전하거나 제정신이 아닙니다.

나는 개인적으로 mysqli의 팬이 아니다. 준비된 명령문에서 변수 바인딩을 수행하는 방식은 융통성이 없으며 사용하기가 어려울 수 있습니다. 의심스러운 경우 대신 PDO를 사용하십시오.

SQL 데이터베이스를 사용하여 데이터를 저장하지 않는 경우 사용중인 데이터베이스 인터페이스의 설명서를 확인하여 데이터를 안전하게 전달하는 방법을 결정하십시오.

가능하면 데이터베이스가 데이터를 적절한 형식으로 저장해야합니다. 숫자를 숫자 필드에 저장하십시오. 날짜 필드에 날짜를 저장하십시오. 부동 소수점 필드가 아닌 10 진수 필드에 돈을 저장하십시오. 다른 데이터 유형을 올바르게 저장하는 방법에 대해서는 데이터베이스에서 제공 한 문서를 검토하십시오.

프리젠 테이션을위한 데이터 이스케이프

사용자에게 데이터를 표시 할 때마다 데이터가 이스케이프 되어서는 안된다는 것을 알지 않는 한 데이터가 안전하게 이스케이프 되어야합니다.

HTML을 생성 할 때는 거의 항상 원래 사용자가 제공 한 모든 데이터를 전달해야합니다. htmlspecialchars . 사실, 당신이 때 당신이하지 말아야 할 유일한 시간입니다 알고 사용자가 HTML을 한 것으로, 당신은 것을 알고 이미 화이트리스트를 사용하여 소독하고 있다고.

때로는 PHP를 사용하여 자바 스크립트를 생성해야합니다. Javascript에는 HTML과 동일한 이스케이프 규칙이 없습니다! PHP를 통해 Javascript에 사용자 제공 값을 제공하는 안전한 방법은 json_encode입니다.

그리고 더

데이터 유효성 검사에는 더 많은 뉘앙스가 있습니다.

예를 들어, 문자 세트 인코딩은 큰 함정일 수 있습니다 . 귀하의 신청서는 " UTF-8 전체 . 문자열 데이터를 잘못된 문자 세트로 취급 할 때 발생할 수있는 가상 공격이 있습니다.

이전에는 브라우저 디버그 도구에 대해 언급했습니다. 이 도구를 사용하여 쿠키 데이터를 조작 할 수도 있습니다. 쿠키는 신뢰할 수없는 사용자 입력으로 취급해야합니다 .

데이터 유효성 검사 및 이스케이프는 웹 응용 프로그램 보안의 한 측면 일뿐입니다. 웹 애플리케이션 공격 방법론을 숙지하여 이에 대한 방어 수단을 구축해야합니다.


그리고 그것을 지정할 때 지원되는 인코딩 목록에 있는지 확인하십시오.
Charles

3
그리고 htmlentities를 전혀 사용하지 말고 htmlspecialchars로 바꾸십시오. 단지 <>모든 문자가 아닌 엔티티를 대체 할 목적으로
Common Sense

6
htmlspecialchars"사용자가 데이터를 제출할 때"부분과 "데이터를 표시 할 때"부분에서 말을하기 때문에 두 번 호출하지 마십시오 .
Savageman 2016 년

2
공감. SQL 주입에 관한 많은 Q & A에서 읽은 가장 유용한 답변입니다.
akinuri

미래의 사용자가 더 많은 옵션을 탐색 할 수 있도록 많은 설명과 링크가 포함 된 품질 답변입니다. 나도 한 사람을 얻었습니다 ...
James Walker

32

SQL 주입을 방지하기위한 가장 효과적인 살균은를 사용하는 매개 변수화 PDO입니다. 매개 변수화 된 쿼리를 사용하면 쿼리가 데이터와 분리되므로 1 차 SQL 주입의 위협이 제거됩니다.

HTML을 제거한다는 측면에서 HTML strip_tags만 제거하는 것이 가장 좋습니다. HTML 만 제거하면됩니다. htmlentities소리가 잘 들리므로 작동합니다. 허용 할 HTML을 구문 분석해야하는 경우 (즉, 일부 태그 를 허용하려는 경우 ) HTML Purifier 와 같은 기존의 기존 구문 분석기를 사용해야합니다.


2
Aw man, 나는 누군가가 HTML Purifier에 대해 언급하지 않았기 때문에 거대한 텍스트 벽을 썼다. ;)
Charles

3
출력에서 HTML 만 제거하면 안됩니까? IMO는 입력 데이터를 절대로 변경해서는 안됩니다. 필요할 때 알 수 없습니다.
Joe Phillips

11

데이터베이스 입력-SQL 삽입을 방지하는 방법

  1. 예를 들어 정수 유형의 데이터가 실제로 정수인지 확인하여 유효한지 확인하십시오.
    • 문자열이 아닌 경우 데이터가 실제로 올바른 유형인지 확인해야합니다.
    • 문자열의 경우 쿼리에서 문자열을 따옴표로 묶어야합니다 (분명히 그렇지 않으면 작동하지 않습니다)
  2. SQL 삽입을 피하면서 데이터베이스에 값을 입력하십시오 (mysql_real_escape_string 또는 매개 변수화 된 쿼리)
  3. 데이터베이스에서 값을 검색 할 때 페이지에 HTML을 삽입 할 수 없도록하여 사이트 간 스크립팅 공격을 피하십시오 (htmlspecialchars).

데이터베이스에 삽입하거나 업데이트하기 전에 사용자 입력을 이스케이프해야합니다. 여기에 오래된 방법이 있습니다. 이제 매개 변수화 된 쿼리를 사용하려고합니다 (아마도 PDO 클래스에서).

$mysql['username'] = mysql_real_escape_string($clean['username']);
$sql = "SELECT * FROM userlist WHERE username = '{$mysql['username']}'";
$result = mysql_query($sql);

데이터베이스 출력-XSS 방지 방법 (Cross Site Scripting)

htmlspecialchars()데이터베이스에서 데이터를 출력 할 때만 사용하십시오 . HTML Purifier에도 동일하게 적용됩니다. 예:

$html['username'] = htmlspecialchars($clean['username'])

그리고 마지막으로 ... 당신이 요청한 것

매개 변수가있는 쿼리 (적절한 방법)와 함께 PDO 객체를 사용하면 이것을 쉽게 달성 할 수있는 쉬운 방법이 없다는 것을 지적해야합니다. 그러나 이전 'mysql'방법을 사용하면 이것이 필요합니다.

function filterThis($string) {
    return mysql_real_escape_string($string);
}

5

내 5 센트

여기서 아무도 mysql_real_escape_string작동 방식을 이해하지 못합니다 . 이 기능은 아무것도 필터링하거나 "위생 처리"하지 않습니다.
따라서이 기능을 주입에서 절약 할 수있는 범용 필터로 사용할 수 없습니다.
작동 방식과 적용 가능한 위치를 이해 한 경우에만 사용할 수 있습니다.

필자는 이미 쓴 것과 비슷한 질문에 대한 답을 가지고 있습니다 .PHP에서 데이터베이스에 문자열을 제출할 때 htmlspecialchars ()를 사용하여 불법 문자를 처리하거나 정규식을 사용해야합니까?
데이터베이스 측 안전에 대한 자세한 설명을 보려면 클릭하십시오.

htmlentities와 관련하여 Charles는 이러한 기능을 분리하도록 지시합니다.
HTML을 게시 할 수있는 관리자가 생성 한 데이터를 삽입한다고 가정 해보십시오. 당신의 기능은 그것을 망칠 것입니다.

나는 htmlentities에 대해 조언 할 것이지만. 이 기능은 오래 전에 더 이상 사용되지 않습니다. 교체 할 경우에만 <, >"HTML의 안전을 위하여 문자는 - 안 - 그 목적을 위해 의도적으로 개발 된 기능을 사용하여 반드시 htmlspecialchars () 를.


1
mysql_real_escape_string문자열 내에서 필요한 문자를 이스케이프합니다. 그것은 엄격하게 필터링하거나 살균하는 것이 아니라 문자열을 따옴표로 묶는 것도 아닙니다 (모두가 그렇게합니다. 나는 그것에 대해 거의 질문을 보지 못했습니다). SQL을 작성할 때 위생적인 ​​것은 없습니까? 당연히 아니지. SQL 삽입을 막는 것은의 사용입니다 mysql_real_escape_string. 또한 따옴표로 묶지 만 모두가 그렇게하며 수행 한 작업을 테스트하면이 누락으로 SQL 구문 오류가 발생합니다. 진짜 위험한 부분은로 처리됩니다 mysql_real_escape_string.
Savageman 2016 년

@Savageman 죄송합니다 친구, 당신은 아무것도 이해하지 못합니다. mysql_real_escape_string의 작동 방식을 이해하지 못합니다. 이 "필요한 문자"는 따옴표입니다. 이 기능이나 따옴표만으로는 아무것도 위생 처리되지 않습니다. 이 두 가지는 함께 작동 합니다 . 쿼리 문자열을 구문 적으로 정확하고 "주입으로부터 안전하지 않음"으로 설정 그리고 어떤 구문 오류가 발생 WHERE id = 1합니까? ;)
당신의 상식

WHERE my_field = two words구문 오류를 얻으려면 따옴표없이 시도하십시오 . 당신의 예제는 따옴표가 필요하지 않고 탈출 할 필요가 없기 때문에 좋지 않습니다. 숫자 검사 만하면됩니다. 또한 나는 인용문이 쓸모 없다고 말하지 않았다. 나는 모든 사람들이 그것을 사용한다고 말했기 때문에 이것이 SQL 주입과 관련된 문제의 원인이 아닙니다.
Savageman

1
@Savageman은 다음 과 같이 말했습니다. 작동 방식과 적용 가능한 위치를 이해 한 경우에만 사용할 수 있습니다. 당신은 mysql_real_escape_string이 모든 곳에서 적용 가능하지 않다는 것을 인정했다. everyone use them여기에서 코드 를 확인할 수 있습니다. 많은 사람들이 숫자와 함께 따옴표를 사용하지 않습니다. 그림을 이동. 제발, 나는 당신이 말한 것과 당신이하지 않은 것을 여기서 논의하지 않는다는 것을 명심하십시오. 기본 데이터베이스 안전 규칙을 설명합니다. 빈 논쟁 대신 배우는 것이 좋습니다. 아무도 인용이나 캐스팅을 언급 하지 않지만 m_r_e_s는 마술처럼 보입니다. 내가 말하는 것
당신의 상식

1
@Charles뿐만 아니라 하나. 초보자, 데이터베이스 상호 작용 ... 입력 및 표시를 위해 물건을 안전하게 만드는 특수 문자, 주입 문제는 매우 가파른 학습 곡선이었습니다. . 귀하의 게시물과 그의 (뿐만 아니라 다른 질문에 다른 PHP의 답변을 읽는 것은 모두 크게 Tx는 귀하의 의견 나에게 도움이되었습니다.
제임스 워커에게

2

데이터베이스 삽입의 경우 필요한 것은 mysql_real_escape_string매개 변수화 된 쿼리를 사용하는 것입니다. 일반적으로 데이터를 저장하기 전에 데이터를 변경하지 않으려 고합니다 htmlentities. 나중에 실행할 때 깨진 혼란으로 이어질 것입니다.htmlentities 웹 페이지의 어딘가에 표시하기 위해 다시 입니다.

사용하다 htmlentities웹 페이지에 데이터를 표시 할 때 .

예를 들어 연락처 양식과 같이 이메일로 제출 된 데이터를 전자 메일로 보내는 경우 머리글에 사용될 모든 데이터에서 줄 바꿈을 제거하십시오 (보낸 사람 : 이름 및 전자 메일 주소, 하위 항목 등). )

$input = preg_replace('/\s+/', ' ', $input);

이 작업을 수행하지 않으면 스팸 봇이 양식을 찾아서 악용하기까지 시간 문제 일뿐입니다. 어려운 방법을 배웠습니다.



2

사용중인 데이터의 종류에 따라 다릅니다. 일반적으로 사용하는 것이 가장 mysqli_real_escape_string좋지만 예를 들어, HTML 콘텐츠가 없다는 것을 알고 있습니다. strip_tags를 사용하면 보안이 강화됩니다.

허용해서는 안되는 문자를 제거 할 수도 있습니다.


1

항상 GUMP와 같은 작은 유효성 검사 패키지를 사용하는 것이 좋습니다. https://github.com/Wixel/GUMP

이와 같은 라이브러리를 중심으로 모든 기본 기능을 구축하면 위생을 잊을 수 없습니다. "mysql_real_escape_string"은 좋은 필터링을위한 최선의 대안이 아닙니다 ( "일반적인 감각"과 같이 설명 함). 한 번만 사용하는 것을 잊어 버린 경우 주사 및 기타 불쾌한 공격을 통해 전체 시스템을 공격 할 수 있습니다.


1

여기 mysql_real_escape_string에 관해 이야기하고 의존하는 모든 사람들에게, 그 함수는 PHP5에서 더 이상 사용되지 않으며 PHP7에는 더 이상 존재하지 않습니다.

이 작업을 수행하는 가장 좋은 방법은 PDO를 통해 매개 변수화 된 쿼리를 사용하여 데이터베이스와 상호 작용하는 것입니다. 이것을 확인하십시오 : https://phpdelusions.net/pdo_examples/select

항상 사용자 입력을 처리하기 위해 필터를 사용하십시오. http://php.net/manual/es/function.filter-input.php 참조


이것은 실제로 질문에 대답하지 않습니다. 솔루션을 포함하도록 답변을 수정하십시오.
kris

네가 좋아하길 바래!
Kuntur

나는한다. 좋은 대답입니다!
kris

PHP 7 mysqli_real_escape_string()에서는 사용할 수 있습니다.
Chris

안녕하세요, 여기에 노출 된 솔루션은 mysql_real_escape_string을 참조했습니다. 지금부터 PHP7에는 더 이상 존재하지 않는다는 것을 알았으며 mysqli가 아닌 PDO (및 필터)를 사용하는 대안을 제안했습니다. 제안한 것을 사용하여 솔루션을 설명하는 메모를 자유롭게 추가하십시오. 감사합니다
Kuntur

0

다음과 비슷한 코드에서 mysql_real_escape_string () 을 사용 합니다.

$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
  mysql_real_escape_string($user),
  mysql_real_escape_string($password)
);

문서가 말했듯이, 목적은 연결의 현재 문자 세트를 고려하여 인수로 전달 된 문자열에서 특수 문자를 이스케이프하여 mysql_query () 에 안전하게 배치하는 것입니다 . 설명서에는 다음이 추가됩니다.

이진 데이터를 삽입하려면이 기능을 사용해야합니다.

htmlentities () 는 HTML 내용으로 문자열을 출력 할 때 엔티티의 일부 문자를 변환하는 데 사용됩니다.


0

이것이 제가 현재 연습하고있는 방법 중 하나입니다.

  1. 사용자가 요청한 csrf 및 솔트 템프 토큰을 임플란트하고 요청에서 모두 함께 검증합니다. 여기를 참조하십시오
  2. 클라이언트 측 쿠키에 너무 의존하지 않도록하고 서버 측 세션 사용을 연습하십시오.
  3. 데이터를 구문 분석 할 때 데이터 유형 및 전송 방법 (예 : POST 및 GET) 만 승인하십시오.
  4. webApp / App에 SSL을 사용해야합니다.
  5. 스팸 요청을 의도적으로 제한하려면 시간 기준 세션 요청을 생성해야합니다.
  6. 데이터가 서버로 구문 분석 될 때 요청이 json, html 등과 같은 원하는 데이터 메소드에서 이루어져야하는지 확인한 후 계속 진행하십시오.
  7. realescapestring과 같은 이스케이프 유형을 사용하여 입력에서 모든 잘못된 속성을 이스케이프하십시오.
  8. 그런 다음 사용자가 원하는 데이터 형식 u의 깨끗한 형식 만 확인하십시오.
    예 :
    -이메일 : 입력이 유효한 이메일 형식인지
    확인하십시오-텍스트 / 문자열 : 입력 만 텍스트 형식 (문자열)인지
    확인하십시오.-숫자 : 숫자 형식 만 허용하십시오.
    -Pelase는 PHP 포털에서 PHP 입력 유효성 검사 라이브러리를 참조하십시오
    -유효성 검사가 끝나면 준비된 SQL 문 / PDO를 사용하여 진행하십시오.
    -완료되면 연결을 종료하고 종료하십시오
    .-완료된 출력 값을 지우는 것을 잊지 마십시오.

그것이 내가 믿는 모든 것이 기본 보안에 충분합니다. 해커의 모든 주요 공격을 차단해야합니다.

서버 측 보안을 위해 액세스 및 로봇 방지 및 라우팅 방지의 제한을 위해 apache / htaccess에 설정할 수 있습니다. 서버 측 시스템의 sec 외에 서버 측 보안을 위해해야 ​​할 일이 많이 있습니다.

htaccess apache sec 레벨 (공통 rpactices)에서 sec의 사본을 배우고 얻을 수 있습니다.


0
function sanitize($string,$dbmin,$dbmax){
$string = preg_replace('#[^a-z0-9]#i', '', $string); //useful for strict cleanse, alphanumeric here
$string = mysqli_real_escape_string($con, $string); //get ready for db
if(strlen($string) > $dbmax || strlen($string) < $dbmin){
    echo "reject_this"; exit();
    }
return $string;
}

0

이건 어때?

$string = htmlspecialchars(strip_tags($_POST['example']));

아니면 이거

$string = htmlentities($_POST['example'], ENT_QUOTES, 'UTF-8');
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.