Bre*_*ent 1069 php security xss user-input sql-injection
是否有一个catchall函数适用于清理SQL注入和XSS攻击的用户输入,同时仍允许某些类型的html标记?
tro*_*skn 1149
这是一种常见的误解,即用户输入可以被过滤.PHP甚至还有一个(现已弃用的)"功能",称为魔术引号,它建立在这个想法的基础之上.这是胡说八道.忘记过滤(或清洁,或任何人称之为).
为了避免出现问题,你应该做的很简单:每当你在外国代码中嵌入一个字符串时,你必须根据该语言的规则来逃避它.例如,如果在某些SQL目标MySql中嵌入字符串,则必须为此目的使用MySql函数转义字符串(mysqli_real_escape_string
).(或者,对于数据库,如果可能,使用预处理语句是更好的方法)
另一个例子是HTML:如果在HTML标记中嵌入字符串,则必须使用它进行转义htmlspecialchars
.这意味着每个单词echo
或print
语句都应该使用htmlspecialchars
.
第三个例子可能是shell命令:如果你要将字符串(例如参数)嵌入到外部命令中,并用它们调用它们exec
,那么你必须使用escapeshellcmd
和escapeshellarg
.
等等等等 ...
您需要主动过滤数据的唯一情况是,您是否接受预先格式化的输入.例如.如果您允许用户发布HTML标记,那么您计划在网站上显示该标记.但是,你应该不惜一切代价避免这种情况,因为无论你如何过滤它,它总是一个潜在的安全漏洞.
And*_*ter 209
不要试图通过清理输入数据来阻止SQL注入.
相反,不要在创建SQL代码时使用数据.使用使用绑定变量的Prepared Statements(即使用模板查询中的参数).这是防止SQL注入的唯一方法.
有关阻止SQL注入的更多信息,请访问我的网站http://bobby-tables.com/.
Dan*_*ian 77
不可以.如果没有任何上下文,您无法对数据进行一般过滤.有时您想要将SQL查询作为输入,有时您希望将HTML作为输入.
您需要过滤白名单上的输入 - 确保数据符合您期望的某些规格.然后,您需要在使用它之前将其转义,具体取决于您使用它的上下文.
转义SQL数据的过程 - 防止SQL注入 - 与转换(X)HTML数据的过程非常不同,以防止XSS.
Sch*_*kie 48
PHP现在具有新的漂亮的filter_input函数,例如,现在有一个内置的FILTER_VALIDATE_EMAIL类型可以让你找到"最终的电子邮件正则表达式"
我自己的过滤器类(使用javascript来突出显示错误的字段)可以由ajax请求或普通表单发布.(见下面的例子)
/**
* 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;
}
}
Run Code Online (Sandbox Code Playgroud)
当然,请记住,您需要进行sql查询转义,具体取决于您使用的数据库类型(例如,mysql_real_escape_string()对于SQL Server无用).您可能希望在适当的应用程序层(如ORM)自动处理此问题.另外,如上所述:输出到html使用其他php专用函数,如htmlspecialchars;)
对于真正允许带有类似剥离类和/或标记的HTML输入,取决于其中一个专用的xss验证包.不要将自己的注册内容写入PARSE HTML!
Pet*_*ley 44
不,那里没有.
首先,SQL注入是一个输入过滤问题,XSS是一个输出转义问题 - 所以你甚至不会在代码生命周期中同时执行这两个操作.
基本的经验法则
mysql_real_escape_string()
)strip_tags()
过滤掉不需要的HTMLhtmlspecialchars()
在此处转义所有其他输出并注意第二和第三参数.jas*_*bar 22
要解决XSS问题,请查看HTML Purifier.它相当可配置,并具有良好的跟踪记录.
至于SQL注入攻击,请确保检查用户输入,然后通过mysql_real_escape_string()运行它.但是,该函数不会破坏所有注入攻击,因此在将数据转储到查询字符串之前检查数据非常重要.
更好的解决方案是使用预准备语句.该PDO库和mysqli扩展支持这些.
dan*_*gel 20
PHP 5.2引入了filter_var函数.
它支持大量的SANITIZE,VALIDATE过滤器.
http://php.net/manual/en/function.filter-var.php
Ham*_*ner 16
在你有一个页面的特定情况下可以帮助的一个技巧,/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
}
Run Code Online (Sandbox Code Playgroud)
但是当然只能删除一个特定的攻击,所以阅读所有其他答案.(是的,我知道上面的代码不是很好,但它显示了具体的防御.)
Mar*_*tin 13
使用PHP清理用户输入的方法:
$mysqli->set_charset("utf8");手册
$pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF8', $user, $password);手册
$pdo->exec("set names utf8");手册
$pdo = new PDO( "mysql:host=$host;dbname=$db", $user, $pass, array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8" ) );手册
[在PHP 5.5.0中弃用,在PHP 7.0.0中删除].mysql_set_charset('utf8')
$stmt = $mysqli->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$param = "' OR 1=1 /*";
$stmt->bind_param('s', $param);
$stmt->execute();
PDO :: quote() - 在输入字符串周围放置引号(如果需要)并使用适合于底层驱动程序的引用样式转义输入字符串中的特殊字符:
$pdo = new 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->quote("' 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 = new 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 test WHERE name = ? LIMIT 1'); $stmt->execute(["' OR 1=1 /*"]);
ctype_digit — Check for numeric character(s);
$value = (int) $value;
$value = intval($value);
$var = filter_var('0755', FILTER_VALIDATE_INT, $options);
is_string() — Find whether the type of a variable is string
$email = filter_var($email, FILTER_SANITIZE_EMAIL);预定义过滤器
$newstr = filter_var($str, FILTER_SANITIZE_STRING);
$search_html = filter_input(INPUT_GET, 'search', FILTER_SANITIZE_SPECIAL_CHARS);
web*_*lik 10
没有包罗万象的功能,因为有多个问题需要解决。
查看(唯一合适的)PDO 教程,了解您需要了解的有关 PDO 的几乎所有内容。(衷心感谢顶级 SO 贡献者 @YourCommonSense 提供了有关该主题的重要资源。)
HTML Purifier已经存在很长时间了,并且仍在积极更新中。您可以使用它来清理恶意输入,同时仍然允许大量且可配置的标签白名单。适用于许多 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;
}
Run Code Online (Sandbox Code Playgroud)
echo
或print
显示用户提供的值时,htmlspecialchars
除非数据经过适当的安全处理并允许显示 HTML ,否则请使用。json_encode
是一种将用户提供的值从 PHP 提供到 Javascript 的安全方式exec()
或system()
函数还是向backtick
操作员调用外部 shell 命令?如果是这样,除了 SQL 注入和 XSS 之外,您可能还有一个需要解决的问题,即用户在您的服务器上运行恶意命令。escapeshellcmd
如果您想转义整个命令或escapeshellarg
转义单个参数,则需要使用。如果您正在使用PostgreSQL,可以使用pg_escape_string()转义PHP的输入
$username = pg_escape_string($_POST['username']);
Run Code Online (Sandbox Code Playgroud)
从文档(http://php.net/manual/es/function.pg-escape-string.php):
pg_escape_string()转义用于查询数据库的字符串.它返回PostgreSQL格式的转义字符串,不带引号.
您为使其安全地包含在 SQL 语句中而对数据应用的转换与您申请包含在 HTML 中的转换完全不同,与您申请包含在 Javascript 中的转换完全不同,与您申请包含在 LDIF 中的转换完全不同:与您应用于包含在 CSS 中的内容完全不同 与您应用于包含在电子邮件中的内容完全不同......
无论如何都要验证输入- 决定是否应该接受它以进行进一步处理或告诉用户这是不可接受的。但是,在数据即将离开 PHP 之前,不要对数据的表示进行任何更改。
很久以前,有人试图发明一种万能的转义数据机制,我们最终得到了“ magic_quotes ”,它没有正确转义所有输出目标的数据,并导致不同的安装需要不同的代码才能工作。
归档时间: |
|
查看次数: |
497649 次 |
最近记录: |