PHP로 사용자 입력을 삭제하려면 어떻게 해야 합니까?
특정 유형의 HTML 태그를 허용하면서 SQL 주입 및 XSS 공격에 대한 사용자 입력을 검사하는 데 적합한 캐치올 기능이 있습니까?
사용자 입력을 필터링할 수 있다는 것은 일반적인 오해입니다.PHP는 이 아이디어를 기반으로 하는 매직쿼트라고 불리는 (지금은 더 이상 사용되지 않는) "기능"도 가지고 있습니다.말도 안 돼요.필터링(또는 클리닝, 또는 다른 사람이 부르는 것)은 불필요합니다.
문제를 피하기 위해 해야 할 일은 매우 간단합니다.외국 코드에 데이터를 삽입할 때마다 해당 코드의 포맷 규칙에 따라 데이터를 처리해야 합니다.그러나 이러한 규칙은 너무 복잡하여 모든 규칙을 수동으로 따를 수 없다는 것을 이해해야 합니다.예를 들어 SQL에서는 문자열, 숫자 및 식별자에 대한 규칙이 모두 다릅니다.사용자의 편의를 위해 대부분의 경우 이러한 매립을 위한 전용 도구가 있습니다.예를 들어 SQL 쿼리에서 PHP 변수를 사용해야 할 경우 모든 적절한 포맷/처리를 처리하는 준비된 문을 사용해야 합니다.
다른 예로는 HTML을 들 수 있습니다.HTML 마크업 내에 문자열을 삽입할 경우 로 이스케이프해야 합니다.즉, 모든 것이echo
★★★★★★★★★★★★★★★★★」print
스테이트먼트는 다음과 같이 사용할 필요가 있습니다.htmlspecialchars
.
세 번째 예로는 셸 명령어를 들 수 있습니다.외부 명령어에 문자열(인수 등)을 삽입하여에서 호출하는 경우 및 을 사용해야 합니다.
또한 JSON은 매우 설득력 있는 예입니다.규칙이 너무 많고 복잡하기 때문에 수동으로 모든 규칙을 따를 수는 없습니다.따라서 JSON 문자열을 수동으로 생성해서는 안 되며, 항상 모든 데이터의 형식을 올바르게 지정하는 전용 함수를 사용해야 합니다.
기타 등등...
데이터를 능동적으로 필터링해야 하는 유일한 경우는 미리 포맷된 입력을 받아들이는 경우입니다.예를 들어 사용자가 HTML 마크업을 게시할 수 있도록 하는 경우 사이트에 표시할 계획입니다.그러나 아무리 잘 필터링해도 잠재적인 보안 취약점이 되므로 반드시 피해야 합니다.
입력 데이터를 삭제하여 SQL 주입을 방지하지 마십시오.
대신 SQL 코드를 만드는 데 데이터가 사용되지 않도록 하십시오.바인딩 변수를 사용하는 준비 문(템플릿 쿼리에서 매개 변수 사용)을 사용합니다.이것이 SQL 주입에 대해 보증되는 유일한 방법입니다.
SQL 주입 방지에 대한 자세한 내용은 제 웹사이트 http://bobby-tables.com/을 참조하십시오.
아뇨, 용도가 무엇인지에 대한 어떤 맥락도 없이 데이터를 일반적으로 필터링할 수 없어요SQL 쿼리를 입력으로 사용할 수도 있고 HTML을 입력으로 사용할 수도 있습니다.
화이트리스트에서 입력을 필터링해야 합니다. 데이터가 예상 사양과 일치하는지 확인합니다.그런 다음 사용 중인 컨텍스트에 따라 사용하기 전에 데이터를 이스케이프해야 합니다.
SQL용 데이터 이스케이프 프로세스(SQL 주입 방지)는 (X)용 데이터 이스케이프 프로세스와 크게 다릅니다.HTML, XSS를 방지합니다.
PHP는 새로운 기능을 갖추고 있습니다.예를 들어, 빌트인이 있기 때문에, 「최고의 E-메일 정규식」을 찾을 필요가 없습니다.FILTER_VALIDATE_EMAIL
나만의 필터 클래스(JavaScript를 사용하여 장애가 있는 필드를 강조 표시)는 Ajax 요청 또는 일반 폼 투고로 시작할 수 있습니다.(다음 예 참조) <? /**** Fork Formvalidator 。는 정규식을 사용하여 필드를 검증하고 필드를 삭제할 수 있습니다.PHP filter_var 내장 함수와 추가 정규식 * @package fork */ 를 사용합니다.
/**
* Pork.FormValidator
* Validates arrays or properties by setting up simple arrays.
* Note that some of the regexes are for dutch input!
* Example:
*
* $validations = array('name' => 'anything','email' => 'email','alias' => 'anything','pwd'=>'anything','gsm' => 'phone','birthdate' => 'date');
* $required = array('name', 'email', 'alias', 'pwd');
* $sanitize = array('alias');
*
* $validator = new FormValidator($validations, $required, $sanitize);
*
* if($validator->validate($_POST))
* {
* $_POST = $validator->sanitize($_POST);
* // now do your saving, $_POST has been sanitized.
* die($validator->getScript()."<script type='text/javascript'>alert('saved changes');</script>");
* }
* else
* {
* die($validator->getScript());
* }
*
* To validate just one element:
* $validated = new FormValidator()->validate('blah@bla.', 'email');
*
* To sanitize just one element:
* $sanitized = new FormValidator()->sanitize('<b>blah</b>', 'string');
*
* @package pork
* @author SchizoDuckie
* @copyright SchizoDuckie 2008
* @version 1.0
* @access public
*/
class FormValidator
{
public static $regexes = Array(
'date' => "^[0-9]{1,2}[-/][0-9]{1,2}[-/][0-9]{4}\$",
'amount' => "^[-]?[0-9]+\$",
'number' => "^[-]?[0-9,]+\$",
'alfanum' => "^[0-9a-zA-Z ,.-_\\s\?\!]+\$",
'not_empty' => "[a-z0-9A-Z]+",
'words' => "^[A-Za-z]+[A-Za-z \\s]*\$",
'phone' => "^[0-9]{10,11}\$",
'zipcode' => "^[1-9][0-9]{3}[a-zA-Z]{2}\$",
'plate' => "^([0-9a-zA-Z]{2}[-]){2}[0-9a-zA-Z]{2}\$",
'price' => "^[0-9.,]*(([.,][-])|([.,][0-9]{2}))?\$",
'2digitopt' => "^\d+(\,\d{2})?\$",
'2digitforce' => "^\d+\,\d\d\$",
'anything' => "^[\d\D]{1,}\$"
);
private $validations, $sanatations, $mandatories, $errors, $corrects, $fields;
public function __construct($validations=array(), $mandatories = array(), $sanatations = array())
{
$this->validations = $validations;
$this->sanitations = $sanitations;
$this->mandatories = $mandatories;
$this->errors = array();
$this->corrects = array();
}
/**
* Validates an array of items (if needed) and returns true or false
*
*/
public function validate($items)
{
$this->fields = $items;
$havefailures = false;
foreach($items as $key=>$val)
{
if((strlen($val) == 0 || array_search($key, $this->validations) === false) && array_search($key, $this->mandatories) === false)
{
$this->corrects[] = $key;
continue;
}
$result = self::validateItem($val, $this->validations[$key]);
if($result === false) {
$havefailures = true;
$this->addError($key, $this->validations[$key]);
}
else
{
$this->corrects[] = $key;
}
}
return(!$havefailures);
}
/**
*
* Adds unvalidated class to thos elements that are not validated. Removes them from classes that are.
*/
public function getScript() {
if(!empty($this->errors))
{
$errors = array();
foreach($this->errors as $key=>$val) { $errors[] = "'INPUT[name={$key}]'"; }
$output = '$$('.implode(',', $errors).').addClass("unvalidated");';
$output .= "new FormValidator().showMessage();";
}
if(!empty($this->corrects))
{
$corrects = array();
foreach($this->corrects as $key) { $corrects[] = "'INPUT[name={$key}]'"; }
$output .= '$$('.implode(',', $corrects).').removeClass("unvalidated");';
}
$output = "<script type='text/javascript'>{$output} </script>";
return($output);
}
/**
*
* Sanitizes an array of items according to the $this->sanitations
* sanitations will be standard of type string, but can also be specified.
* For ease of use, this syntax is accepted:
* $sanitations = array('fieldname', 'otherfieldname'=>'float');
*/
public function sanitize($items)
{
foreach($items as $key=>$val)
{
if(array_search($key, $this->sanitations) === false && !array_key_exists($key, $this->sanitations)) continue;
$items[$key] = self::sanitizeItem($val, $this->validations[$key]);
}
return($items);
}
/**
*
* Adds an error to the errors array.
*/
private function addError($field, $type='string')
{
$this->errors[$field] = $type;
}
/**
*
* Sanitize a single var according to $type.
* Allows for static calling to allow simple sanitization
*/
public static function sanitizeItem($var, $type)
{
$flags = NULL;
switch($type)
{
case 'url':
$filter = FILTER_SANITIZE_URL;
break;
case 'int':
$filter = FILTER_SANITIZE_NUMBER_INT;
break;
case 'float':
$filter = FILTER_SANITIZE_NUMBER_FLOAT;
$flags = FILTER_FLAG_ALLOW_FRACTION | FILTER_FLAG_ALLOW_THOUSAND;
break;
case 'email':
$var = substr($var, 0, 254);
$filter = FILTER_SANITIZE_EMAIL;
break;
case 'string':
default:
$filter = FILTER_SANITIZE_STRING;
$flags = FILTER_FLAG_NO_ENCODE_QUOTES;
break;
}
$output = filter_var($var, $filter, $flags);
return($output);
}
/**
*
* Validates a single var according to $type.
* Allows for static calling to allow simple validation.
*
*/
public static function validateItem($var, $type)
{
if(array_key_exists($type, self::$regexes))
{
$returnval = filter_var($var, FILTER_VALIDATE_REGEXP, array("options"=> array("regexp"=>'!'.self::$regexes[$type].'!i'))) !== false;
return($returnval);
}
$filter = false;
switch($type)
{
case 'email':
$var = substr($var, 0, 254);
$filter = FILTER_VALIDATE_EMAIL;
break;
case 'int':
$filter = FILTER_VALIDATE_INT;
break;
case 'boolean':
$filter = FILTER_VALIDATE_BOOLEAN;
break;
case 'ip':
$filter = FILTER_VALIDATE_IP;
break;
case 'url':
$filter = FILTER_VALIDATE_URL;
break;
}
return ($filter === false) ? false : filter_var($var, $filter) !== false ? true : false;
}
}
물론 사용하는 DB 유형에 따라 SQL 쿼리 이스케이프도 수행해야 한다는 점에 유의하십시오(예를 들어 mysql_real_escape_string()은 SQL 서버에서 사용할 수 없습니다).ORM과 같은 적절한 애플리케이션 층에서 이 작업을 자동으로 처리해야 합니다.또한 위에서 설명한 바와 같이 html로 출력하기 위해서는 htmlspecialchars와 같은 다른 php 전용 함수를 사용합니다.
같은 클래스나 태그가 제거된 HTML 입력을 실제로 허용하려면 전용 xss 검증 패키지 중 하나에 의존합니다.HTML을 해석하기 위해 자신의 정규식을 쓰지 마십시오!
아니, 없어.
우선 SQL 주입은 입력 필터링 문제이고 XSS는 출력 이스케이프 문제이므로 코드 라이프 사이클에서 이 두 작업을 동시에 실행할 수도 없습니다.
경험의 기본 규칙
- SQL 쿼리의 경우 매개 변수 바인딩
- 원하지 않는 HTML을 필터링하기 위해 사용합니다.
- 를 사용하여 다른 모든 출력을 이스케이프하고 여기서 두 번째 및 세 번째 파라미터에 주의하십시오.
XSS 문제에 대처하려면 HTML Pureator를 참조하십시오.그것은 꽤 구성이 가능하고 상당한 실적을 가지고 있다.
SQL 주입 공격에 대해서는 준비된 문을 사용하는 것이 해결책입니다.PDO 라이브러리와 mysqli 확장은 이러한 기능을 지원합니다.
PHP 5.2는 이 기능을 도입했습니다.
을 지지한다.SANITIZE
,VALIDATE
필터가 포함되어 있습니다.
PHP를 사용하여 사용자 입력을 삭제하는 방법:
MySQL 및 PHP의 최신 버전을 사용합니다.
문자 집합을 명시적으로 설정합니다.
$mysqli->set_charset-utf8";
설명서$pdo = 새 PDO('mysql:host=localhost;dbname=testdb;charset=UTF8', $user, $password);
설명서$pdo-> exec set names utf8";
설명서$pdo = 새로운 PDO ("param:host=$host;dbname=$db", $user, $pass,배열()PDO:: ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,PDO:: MYSql_ATTR_INIT_COMMAND => "SET NAMS utf8"));
설명서
[PHP 5.5.0에서는 폐지, PHP 7.0.0에서는 삭제]mysql_set_charset'utf8')
보안 문자 집합 사용:
- utf8, latin1, ascii.., 취약한 문자 집합 big5, cp932, gb2312, gbk, sjis를 선택합니다.
공간화된 기능 사용:
- MySQLi가 준비한 문:
= $* name ? 1 $stmt = $mysqli->glines('SELECT * FROM WHERE name = ? LIMIT 1')
= "" 1 =1 $140 = "OR 1 = 1 /*",
$ $stmt->discs_discs, $discs);
$stmt->filename(); PDO::quote() - 입력 문자열 주위에 따옴표를 붙이고(필요한 경우), 기본 드라이버에 적합한 따옴표 스타일을 사용하여 입력 문자열 내의 특수 문자를 이스케이프합니다.
$pdo = 새 PDO('mysql:host=localhost;dbname=testdb;charset=UTF8', $user, $password);explicit set the character set
$pdo-> setAttribute(PDO::ATTR_EMULATE_PREPARES, false);disable emulating prepared statements to prevent fallback to emulating statements that MySQL can't prepare natively (to prevent injection)
$var = $pdo - > display' OR 1 = 1 /*not only escapes the literal, but also quotes it (in single-quote ' characters) );$stmt = $pdo->query("SELECT * FROM test WHERE name = $var LIMIT 1");PDO 준비 스테이트먼트:vs MySQLi 준비 스테이트먼트는 더 많은 데이터베이스 드라이버와 명명된 파라미터를 지원합니다.
$pdo = 새 PDO('mysql:host=localhost;dbname=testdb;charset=UTF8', $user, $password);explicit set the character set
$pdo-> setAttribute(PDO::ATTR_EMULATE_PREPARES, false);disable emulating prepared statements to prevent fallback to emulating statements that MySQL can't prepare natively (to prevent injection) $stmt = $pdo-> prepare ('SELECT * FROM WHERE name = ? LIMIT 1');$stmt->flash(['OR 1=1 /*");mysql_real_sysql_string[PHP 5.5.0에서는 폐지, PHP 7.0.0에서는 삭제]- mysqli_real_escape_string 연결의 현재 문자 집합을 고려하여 SQL 문에서 사용하기 위해 문자열 내의 특수 문자를 이스케이프합니다.단, Prepared 문은 단순히 이스케이프된 문자열이 아니기 때문에 사용하는 테이블과 인덱스를 포함한 완전한 쿼리 실행 계획을 제시하는 것이 좋습니다.이 방법은 최적화되어 있습니다.
- 쿼리 내 변수 주변에는 작은따옴표(')를 사용합니다.
- MySQLi가 준비한 문:
변수에 기대하는 내용이 포함되어 있는지 확인합니다.
- 과 같이
: ctype_digit : 자숫 c 。
= ( $value = (int) $value;
value = intvalval value);
$ $var = filter_varsup0755 FILTER_VALIDATE_INT, $varsup); - " " " "
is_string() : 변수 유형이 문자열인지 여부를 확인합니다.
Use Filter Function filter_var() - 지정된 필터를 사용하여 변수를 필터링합니다.$ FILTER_SANITIZE_EMAIL $email = filter_varsemail, FILTER_SANITIZE_EMAIL
prefined (더 정의된 필터)
$ FILTER_SANITIZE_STRINGnewstr = filter_varsecstr, FILTER_SANITIZE_STRING - filter_input() : 특정 외부 변수를 이름으로 가져오고 필요에 따라 필터링합니다.
$search_input = filter_input(INPUT_GET, '검색', FILTER_SANITIZE_SPECIAL_CHARS);
- preg_match() : 정규 표현 조회를 수행합니다.
- 사용자 고유의 검증 함수를 작성합니다.
- 과 같이
때 이 될 수 있는 입니다./mypage?id=53
WHERE 절의 ID를 사용하면 다음과 같이 id가 확실히 정수임을 확인할 수 있습니다.
if (isset($_GET['id'])) {
$id = $_GET['id'];
settype($id, 'integer');
$result = mysql_query("SELECT * FROM mytable WHERE id = '$id'");
# now use the result
}
하지만 물론 그것은 하나의 특정 공격만 차단하기 때문에 다른 모든 답변을 읽어보세요.(그리고 위의 코드가 훌륭하지 않다는 것은 알지만, 그것은 구체적인 방어를 보여줍니다.)
대처해야 할 여러 우려가 있기 때문에 캐치올 기능은 없습니다.
- SQL Injection - 오늘날 모든 PHP 프로젝트에서는 PHP Data Objects(PDO)를 통해 준비된 스테이트먼트를 베스트 프랙티스로 사용하여 잘못된 인용문 오류 및 주입에 대한 풀기능 솔루션을 방지해야 합니다.또한 데이터베이스에 액세스하는 가장 유연하고 안전한 방법이기도 합니다.
PDO에 대해 알아야 할 거의 모든 것에 대해서는 (유일한) PDO 튜토리얼을 참조해 주십시오.(이 주제에 대한 이 훌륭한 리소스에 대해 SO의 최고 기고가인 @YourCommonSense 덕분에)
- XSS - 들어오는 길에 데이터 삭제...
HTML Pursure는 오랜 기간 사용되었으며 여전히 활발하게 업데이트되고 있습니다.이를 사용하여 악의적인 입력을 삭제하면서 태그 화이트리스트를 풍부하게 설정할 수 있습니다.많은 WYSIWYG 편집기에서 잘 작동하지만, 일부 사용 사례에서는 부담이 클 수 있습니다.
HTML/Javascript를 전혀 받고 싶지 않은 경우에는 이 간단한 기능이 유용하다는 것을 알게 되었습니다(XSS에 대해 여러 번 감사를 통과했습니다).
/* Prevent XSS input */ function sanitizeXSS () { $_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING); $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING); $_REQUEST = (array)$_POST + (array)$_GET + (array)$_REQUEST; }
- XSS - 나가는 길에 데이터 삭제...데이터를 데이터베이스에 추가하기 전에 데이터를 적절히 삭제하지 않으면 사용자에게 표시하기 전에 데이터를 삭제해야 합니다.이러한 유용한 PHP 기능을 활용할 수 있습니다.
- 했을 때
echo
★★★★★★★★★★★★★★★★★」print
사용자가 지정한 값을 표시하려면 데이터가 올바르게 삭제되어 HTML을 표시할 수 없는 한 를 사용하십시오. json_encode
사용자가 제공한 값을 PHP에서 Javascript로 안전하게 제공하는 방법입니다.
- 외부 셸 명령어는, 또는 함수를 사용하여 호출합니까, 아니면 오퍼레이터에게 호출합니까?이 경우 SQL Injection & XSS 외에 서버에서 악의적인 명령어를 실행하는 사용자도 대처해야 할 문제가 있습니다.전체 명령어 OR을 이스케이프하여 개별 인수를 이스케이프하려면 를 사용해야 합니다.
여기서 설명하는 것은 두 가지 별개의 문제입니다.
- 사용자 입력 데이터 삭제/필터링
- 출력을 이스케이프하고 있습니다.
1) 사용자 입력은 항상 불량으로 간주한다.
준비된 문을 사용하거나 mysql_real_escape_string을 사용한 필터링은 필수입니다.또한 PHP에는 filter_input이 내장되어 있습니다.이것부터 시작하는 것이 좋습니다.
2) 이것은 큰 토픽이며, 출력되는 데이터의 컨텍스트에 따라 다릅니다.HTML의 경우 htmlpurifier와 같은 솔루션이 있습니다. 경험으로 볼 때, 항상 출력되는 모든 것을 이스케이프하십시오.
두 이슈 모두 하나의 투고에서 다루기에는 너무 큰 문제이지만, 더 자세한 내용을 설명하는 투고가 많습니다.
Postgre Postgre 사용하는, 은 SQL, PHP로 수 있습니다.pg_escape_literal()
$username = pg_escape_literal($_POST['username']);
매뉴얼에서 다음 항목을 참조하십시오.
pg_escape_literal()
는 PostgrePostgre를 위한 . "Postgre Postgre"에서을 반환합니다.SQL 식식
넌 절대 입력을 삭제하지 않아.
항상 출력을 삭제합니다.
SQL 스테이트먼트에 포함시키기 위해 데이터에 적용하는 변환은 HTML에 포함을 신청하는 변환과는 완전히 다릅니다.Javascript에 포함을 신청하는 변환과는 완전히 다릅니다.LDIF에 포함을 신청하는 변환과는 완전히 다릅니다.CSS의 n은 이메일에 포함할 때 적용하는 것과 완전히 다릅니다.
반드시 입력의 유효성을 확인합니다.추가 처리를 위해 입력을 수락할지, 아니면 사용자에게 허용할 수 없다고 말할지 결정합니다.그러나 데이터가 PHP 랜드를 떠나려고 할 때까지 데이터 표현에 어떠한 변경도 적용하지 마십시오.
오래 전에 누군가가 데이터를 이스케이프하기 위한 모든 메커니즘에 맞는 단일 사이즈를 발명하려고 했습니다.그 결과, 모든 출력 타겟의 데이터가 올바르게 이스케이프되지 않고, 다른 인스톨을 실시하기 위해서 다른 코드가 필요한 「magic_quotes」가 되었습니다.
입력 삭제 및 데이터 이스케이프 오류를 방지하는 가장 쉬운 방법은 Symfony, Nette 등의 PHP 프레임워크 또는 해당 프레임워크의 일부(템플릿 엔진, 데이터베이스 계층, ORM)를 사용하는 것입니다.
Twig나 Latte와 같은 템플릿 엔진은 기본적으로 출력이 이스케이프됩니다. 컨텍스트(웹 페이지의 HTML 또는 Javascript 부분)에 따라 출력이 올바르게 이스케이프되어 있으면 수동으로 해결할 필요가 없습니다.
프레임워크는 자동으로 입력을 삭제합니다.$_POST, $_GET 또는 $_SESSION 변수를 직접 사용하는 것이 아니라 라우팅, 세션 처리 등의 메커니즘을 통해 사용해야 합니다.
또한 데이터베이스(모델) 레이어에는 Autrin과 같은 ORM 프레임워크나 Nete Database와 같은 PDO 주변에 래퍼가 있습니다.
자세한 내용은 여기를 참조하십시오.소프트웨어 프레임워크란?
출력 이스케이프라는 주제에 대해 추가하고 싶습니다.html 출력을 만들기 위해 php DOMDocument를 사용하면 올바른 컨텍스트에서 자동으로 이스케이프됩니다.속성(value=")과 <span>의 내부 텍스트가 같지 않습니다.XSS로부터 보호하려면 , 다음의 문서를 참조해 주세요.OWASP XSS Prevention 치트 시트
필터 확장 기능(링크 방법, 수동)이 있어 모든 GPC 변수에서 잘 작동합니다.만능은 아니지만 그래도 써야 할 것 같아요.
이 트리밍 공백 사용 및 인쇄할 수 없는 문자 제거
$data = trim(preg_replace('/[[:^print:]]/', '', $data));
언급URL : https://stackoverflow.com/questions/129677/how-can-i-sanitize-user-input-with-php
'programing' 카테고리의 다른 글
Jar/war에서 파일을 빠르게 삭제할 수 있는 방법이 있습니까? Jar/war를 추출하여 다시 만들지 않아도 됩니다. (0) | 2022.10.01 |
---|---|
InnoDB를 사용한 전문 검색 (0) | 2022.10.01 |
yii2에서 드롭다운 목록을 만드는 방법 (0) | 2022.10.01 |
메서드를 스태틱으로 선언함으로써 얻을 수 있는 이점은 무엇입니까? (0) | 2022.10.01 |
Java에서 현재 열려 있는 창/프로세스 목록을 가져오려면 어떻게 해야 합니까? (0) | 2022.10.01 |