html%3cstript%3e标签,如何使用AJAX表单验证URL字段

这些标记不是有效的/标准的HTML标记:输入=“ url”

pattern =“ https?://.+”

必需的

像这样编写您的html输入:

(您要为其命名的dlink或网站!?)

然后,您必须首先在服务器端仔细验证/控制所有输入,因此在my_parse_file.php:

//unescape data if magic quotes is activated

function strip(&$str) {

if(!is_array($str)) { $str = stripslashes($str); }

}

if(get_magic_quotes_gpc() || get_magic_quotes_runtime()) {

array_walk($_GET, 'strip');

array_walk($_POST, 'strip');

}

//init vars

if(isset($_POST['dlink'])) { $dlink = trim($_POST['dlink']); }else{ $dlink = ''; }

//tiny protect against code injection (XSS)

//maybe need to be revised, with eventual addslashes(), depanding on what you do with $dlink

$dlink = strip_tags($dlink);

//protect against multiline injection

if(preg_match('`^([^\r\n]*)`', $dlink, $match)) { $dlink = $match[1]; }

//control is a right url, can need a little improvement for the right domain format

if(!preg_match('`^(http[s]?://.+)`i', $dlink)) { echo "error"; exit(); }

echo 'Thank you! the url is '.$dlink.', says the PHP file';

?>

然后,您可以在客户端添加JS控件,以提高响应速度,并避免在dlink错误的情况下发出http请求:

var dlink = document.getElementById("dlink").value;

if(!dlink.match(/^http[s]?:\/\/.+/gi)) { alert("url not valid"); return 0; }

var vars = "dlink="+dlink;

请注意不安全的直接回显$ _POST ['varname']。

filter_var()像Silvio所说的那样,似乎也可以控制URL。

- - 更新 - -

下一步,我的回答,我想要做某种替代来filter_var()用手寻找保护的最简单的方法$_POST,并$_GET "echo"针对注射。

我不太赞成如何filter_var()验证/清除URL,因为为什么要在数据库中记录/选择一个包含注入的URL,例如“ domain.comalert(cookie)”,甚至显示给客户端“ this url is domain.comalert(cookie)”。

所以这是我所做的:

function safe_char($str) {

$buf = '';

$enable = array(

9 => 1,//\t

10 => 1,//\n

13 => 1//\r

);

$len = mb_strlen($str);

$i = 0;

while($i < $len) {

$ascii = ord($str[$i]);

//remove unwelcome char, about decimal 0-31 and 127, keep only \t \r \n

if($ascii !== 127/*DEL*/ && ($ascii > 31 || isset($enable[$ascii]))) {

$buf .= $str[$i];

}

$i++;

}

return $buf;

}

function safe_strip_tags($str, $remove_hack=false, $log_hack=false) {

if($remove_hack) {

//$str_ini = $str;

//remove tag content only when tags script/noscript detected

$str = preg_replace('`]*>(.*?|.+)`is', '', $str);

//logs hack

//if($log_hack && $str !== $str_ini) {

//  logs(array('try injection', $str_ini));

//  }

}

//safe delete tags

$str = strip_tags($str);

//delete the last unique > or <

$str = preg_replace('`[<>]+`s', '', $str);

return $str;

}

function safe_write($str) {

//replace by the html entities the critical char that cause injection works

$char = array('&', '', '"', '\'');

$replace = array('&', '<', '>', '"', ''');

return str_replace($char, $replace, $str);

}

function filter_url($str, &$url=false, $strict=false) {

$err = true;

$str = trim($str);

//remove unwelcome control char (about from x00 to x1F), it keep only \t \r \n

$str = safe_char($str);

//remove html tag and protect against injection (XSS)

$url = safe_strip_tags($str, true, true);

//protect against multiline injection

if(preg_match('`^([^\r\n]*)`', $url, $match)) { $url = $match[1]; }

//test is like an url

if(!preg_match('`^(http|ftp)[s]?://.+`i', $url)) {

//and reject other scheme

if($url !== '' && mb_strpos($url, '://') === false) {

//maybe case "www.url.com" so try add an http scheme

$url = 'http://'.$url;

$err = false;

}

}

else{ $err = false; }

//going to confirm url have valid domain

if(!$err) {

//remove char that we dont want in an url

$url = preg_replace('`[\t]+`', '', $url);

$host = parse_url($url, PHP_URL_HOST);

if($host != null) {

//no special char in domain name

if(!preg_match('`^[a-z0-9._-]+$`i', $host)) { $err = true; }

//no double dot in domain name

if(!$err && mb_strpos($host, '..') !== false) { $err = true; }

//domain name

if(!$err && !preg_match('`[a-z0-9_-]{1,63}\.[a-z.]{2,10}$`i', $host)) { $err = true; }

//local dev for http://localhost

//if($err && preg_match('`^[a-z0-9_-]{1,63}$`i', $host)) { $err = false; }

//more strict controls

if(!$err) {

$xpl = explode('.', $host);

foreach($xpl as $v) {

//label not more long than 63 char

if(mb_strlen($v) > 63) { $err = true; break; }

//label must start with a letter

//if(preg_match('`^[0-9]+`', $v)) { $err = true; break; }

//label with underscore is normally not valid

//if(mb_strpos($v, '_') !== false) { $err = true; break; }

}

}

//ip

if($err && preg_match('`^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$`', $host)) { $err = false; }

//its enough, and not so restricted for the future, if you really want to ctrl an url, you have to request it

}

//bad host

else{ $err = true; }

}

//url have been modified

if($strict && $str !== $url) {

$err = true;

}

if($err) { $url = false; }

else{ return true; }

return false;

}

function filter_string($str, &$string=false, $strict=false) {

$str = trim($str);

$string = safe_char($str);//filter_var() cannot do that, so no php_filter_string()

//string have been modified

if($strict && $str !== $string) {

return false;

}

return true;

}

如果您发现了注入/错误或对其进行了优化,请与我们分享...

测试自制的filter_url()结果:

//i writted the result from filter_url() in each comment

$arr = array(

'https://url.com',//https://url.com

'http://url.com',//http://url.com

'http://url.com/test',//http://url.com/test

'http://url.com/test.php?param=a\'b \"c*&plus=1',//http://url.com/test.php?param=a'b \"c*&plus=1

'http://url.com/\'t"e*s t',//http://url.com/'t"e*s t

'http://urlcom',//FALSE

'http://urlcom/url.com',//FALSE

'http://url.com\test',//FALSE

'http://url.com\'"*',//FALSE

'http://url.c\'"*',//FALSE

'http://url.\'"*',//FALSE

'',//FALSE

'u',//FALSE

'u.co',//http://u.co

'http://',//FALSE

'http://u',//FALSE

'http://u.c',//FALSE

'http://u.co',//http://u.co

'http://ur.co',//http://ur.co

'http://www.url.com',//http://www.url.com

'http://www.url',//http://www.url

'http://url_url.com',//http://url_url.com

'http://www.thislabelistoolongthislabelistoolongthislabelistoolongthislabelistoolong.com',//FALSE

'http://localhost',//FALSE

'http://4url.com',//http://4url.com

'http://sub.sub.url.com',//http://sub.sub.url.com

'http://l.s.s.url.com',//http://l.s.s.url.com

'http://127.0.0.1',//http://127.0.0.1

'http://127.0.0.1.2',//FALSE

'http://127.0.0',//FALSE

'http://127.0.0.1/filter/',//http://127.0.0.1/filter/

'http://127.0.0.url',//http://127.0.0.url

'http://127.url',//http://127.url

'http://url.127',//FALSE

'http://u27.c27',//FALSE

'http://u27.com',//http://u27.com

'http://127.0.0.1:80/filter/',//http://127.0.0.1:80/filter/

'http://127.0.0.1.2:80/filter/',//FALSE

'http://1278.0.0.1.2:80/filter/',//FALSE

'ftps://127.0.0.1:80/filter/',//ftps://127.0.0.1:80/filter/

'ftp://url.com',//ftp://url.com

'javascript://comment%0Aalert(1)',//FALSE

'javascript://url.com',//FALSE

'www.url.com',//http://www.url.com

'http://url..com',//FALSE

'http://url.com..com',//FALSE

'http://url.com/te..st',//http://url.com/te..st

'http://url.com/test?param=%0D%0A%61%62',//http://url.com/test?param=%0D%0A%61%62

'http://url.com/'."\r\n".'multiline',//http://url.com/

'http://url.com/'."\n".'multiline',//http://url.com/

'http://url.com/xy; >>',//http://url.com/xy;

'http://url.com/two>text',//http://url.com/text

'http://url.com/two>text',//http://url.com/text

'http://url.com/">alert(cookie)',//http://url.com/"

'http://url.com/%0D%0Aalert(cookie)',//http://url.com/%0D%0A

'http://url.com/%0D%0Aalert(cookie)path/',//http://url.com/%0D%0A

'http://url.com/txt',//http://url.com/txt

'http://url.com/text',//http://url.com/spacetext

'http://url.com/txt',//http://url.com/txt

'http://url.com/%3Ctag%3Cone%3Etwo%3Etext%3Cthree%3E',//http://url.com/%3Ctag%3Cone%3Etwo%3Etext%3Cthree%3E

'http://url.com/%0D%0A%3Cscript%3Ealert(cookie)%3C/script%3E',//http://url.com/%0D%0A%3Cscript%3Ealert(cookie)%3C/script%3E

'http://url.com/canbenice%0D%0A%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%63%6F%6F%6B%69%65%29%3C%2F%73%63%72%69%70%74%3E',//http://url.com/canbenice%0D%0A%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%63%6F%6F%6B%69%65%29%3C%2F%73%63%72%69%70%74%3E

//'http://url.co�m/charctrl',//http://url.com/charctrl

);

$charctrl = '';

$i = 0;

while($i < 32) {

if($i!==9 && $i!==10 && $i!==13) {

$charctrl .= chr($i);

}

$i++;

}

$charctrl .= chr(127);

$arr[] = 'http://url.co'.$charctrl.'m/charctrl';

echo '

';

foreach($arr as $v) {

echo $v.' => ';

if(filter_url($v, $url)) { echo $url; }else{ echo 'FALSE'; }

echo "\r\n";

}

echo '

';

echo "\r\n\r\n".'
'."\r\n\r\n";

echo '

';

foreach($arr as $v) {

echo $v.' => ';

if(php_filter_url($v, $url)) { echo $url; }else{ echo 'FALSE'; }

echo "\r\n";

}

echo '

';

filter_var()解决方案: 很抱歉,我不知道这些filter_var()函数...该函数名称有点含糊,但是正确使用后最终还是安全的,因此请小心选择正确的ID /标记。

FILTER_VALIDATE_URL并不是要保护您免受注入,它只是控制它是否可以是网址。

显示var时,必须应用FILTER_SANITIZE_STRING来防止XSS。

function php_filter_url($str, &$url=false, $strict=false) {

$err = true;

$str = trim($str);

$url = $str;

//protect against multiline injection

if(preg_match('`^([^\r\n]*)`', $url, $match)) { $url = $match[1]; }

//add this because FILTER_VALIDATE_URL accept others scheme

if(!preg_match('`^(http|ftp)[s]?://.+`i', $url)) {

//reject other scheme

if($url !== '' && mb_strpos($url, '://') === false) {

//maybe case "www.url.com" so try add an http scheme

$url = 'http://'.$url;

$err = false;

}

}

else{ $err = false; }

if(!$err) {

$url = filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_HOST_REQUIRED);

if(!$url) { $err = true; }

}

if(!$err) {

$url = filter_var($url, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);

if(!$url) { $err = true; }

}

//url have been modified

if($strict && $str !== $url) {

$err = true;

}

if($err) { $url = false; }

else{ return true; }

return false;

}

我提到很抱歉我的“异国情调”缩进,我一点都不喜欢“官方”,试图回溯,但是不可能...所以我可以理解您对我的看法:D

测试filter_var()结果,别名php_filter_url():

我让您尝试自己测试url,有一些“ false”匹配,但是看起来可能还不错,除了可能会出现以下结果:

http:// urlcom

http://url..com

http://url.comalert(cookie)

http://127.0.0.1.2

Bench: filter_url()比php_filter_url()慢大约5倍,而我们不能在不丢失易于阅读的脚本的情况下进行更多优化。但是,这并不是戏剧性的替补。(PHP 5.4)

最佳解决方案: 如果需要处理filter_var()无法处理的情况,请使用自制解决方案。最后,即使编写得很好且经过验证的URL可能是错误的URL……您必须要求它真正知道。当有人尝试注入某些东西时,我怀疑它包含的是真实信息,因此这些“ url.comalert(cookie)”最终将无用,自制版本尝试将其清除以释放空间,并将注入信息记录到日志中。嗯,我只是认为也许我们不必在检测到注入的情况下验证vars。

关于表单: 由于无法安全地验证javascript(客户端)中的输入,因此,您必须处理php返回的最终错误,以确保在javascript中该怎么做。

您的代码示例不太适合这种情况,因为您通常需要使用xml响应而不是实际的文本响应来正确验证“ XHTML的技术”中的javascript信息。(它需要更多的代码/理解)

因此,为简单起见,但也很正确,您可以选择以下替代方法:

.field {

font-weight:bolder;

border:2px gray solid;

color:black;

}

.fieldError {

border:2px red solid;

color:red;

}

function getXhr() {

var xhr = false;

try{

xhr = new XMLHttpRequest();

}catch (e){

try{

xhr = new XDomainRequest();

}catch (e){

try{

xhr = new ActiveXObject('Msxml2.XMLHTTP');

}catch (e){

try{

xhr = new ActiveXObject('Microsoft.XMLHTTP');

}catch (e){

alert('Your browser is not compatible with XML request');

}

}

}

}

return xhr;

}

function encodeUrl(str) {

if(encodeURIComponent) { str = encodeURIComponent(str); }

else if(escape) { str = escape(str); }

//sure not any = and &

str = str.replace(/=/gi, "%3D");

str = str.replace(/&/gi, "%26");

return str;

}

function getNodeText(tag, content) {

var regex = new RegExp('(.*?)'+tag+'>', 'g');

var match = regex.exec(content);

return match[1];

}

function safeWrite(str) {

str = str.replace(/

str = str.replace(/>/g, '>');

str = str.replace(/\"/g, '"');

str = str.replace(/\'/g, ''');

return str;

}

function ajaxPost() {

var err = false;

var errMsg = 'Invalid form';

//init obj

var dlink = document.getElementById("dlink");

var firstname = document.getElementById("firstname");

//reinit input class

dlink.className = "field";

firstname.className = "field";

//test input dlink

if(!dlink.value.match(/^http[s]?:\/\/.+/gi)) {

dlink.className = "field fieldError";

err = true;

}

//test input firstname

if(firstname.value == '') {

firstname.className = "field fieldError";

err = true;

}

//return directly on error

if(err) {

document.getElementById("status").innerHTML = errMsg;

return false;

}

//create our XMLHttpRequest object

var xhr = getXhr();

//create some variables we need to send to our PHP file

var url = "my_parse_file.php";

var param = "dlink="+encodeUrl(dlink.value)+"&firstname="+encodeUrl(firstname.value);

xhr.open("POST", url, true);

//set content type header information for sending url encoded variables in the request

xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

//access the onreadystatechange event for the XMLHttpRequest object

xhr.onreadystatechange = function() {

if(xhr.readyState == 4 && xhr.status == 200) {

//alert(xhr.responseText);

//make our own tiny parser, and get all the response infos

var dlinkText = getNodeText("dlink", xhr.responseText);

var dlinkErr = getNodeText("dlinkErr", xhr.responseText);

var firstnameText = getNodeText("firstname", xhr.responseText);

var firstnameErr = getNodeText("firstnameErr", xhr.responseText);

//update var for a more secure/easy int type handle

dlinkErr = parseInt(dlinkErr, 10);

firstnameErr = parseInt(firstnameErr, 10);

//handle the real error returned by php

if(dlinkErr !== 0) {

dlink.className = "field fieldError";

err = true;

}

if(firstnameErr !== 0) {

firstname.className = "field fieldError";

err = true;

}

//form fail

if(err) { document.getElementById("status").innerHTML = errMsg; }

//form pass all the test, we recontrol with safeWrite() that there is no code injection

else{

var success = 'Thank you '+safeWrite(firstnameText)+'! the url is '+safeWrite(dlinkText);

document.getElementById("status").innerHTML = success;

}

}

}

//send the data to PHP now... and wait for response to update the status div

xhr.send(param);//actually execute the request

document.getElementById("status").innerHTML = "processing...";

}

Ajax Post to PHP and Get Return Data

dlink :

firstname :

my_parse_file.php

//force to refresh the cache of the browser

header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');

header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');

header('Cache-Control: no-store, no-cache, must-revalidate');

header('Cache-Control: post-check=0, pre-check=0', false);

header('Pragma: no-cache');

//include our filter functions

include './filter.php';

//init vars

$output = '';

$dlink_err = 0;

$firstname_err = 0;

//control $_POST

if(!isset($_POST['dlink'])) { $_POST['dlink'] = ''; $dlink_err = 1; }//trim is done inside filter functions

if(!isset($_POST['firstname'])) { $_POST['firstname'] = ''; $firstname_err = 1; }

//control/validate dlink is like a valid url, and clean the code injection try

if(!filter_url($_POST['dlink'], $dlink)) { $dlink_err = 1; }

//if(!php_filter_url($_POST['dlink'], $dlink)) { $dlink_err = 1; }//not well cleaned

//control firstname, only remove unwelcome charaters from the string, it can return false only if you use the $strict arg

if(!filter_string($_POST['firstname'], $firstname)) { $firstname_err = 1; }

//validate firstname is not empty

if($firstname === '') { $firstname_err = 1; }

//prepare the response, and protect against injection (XSS) with the help of safe_write()

$output .= ''.safe_write($dlink).'

'.$dlink_err.'

'.safe_write($firstname).'

'.$firstname_err.'';

echo $output;

?>

关于“无效/非标准html标签”的第一个注释一点儿不清楚,它们是HTML5自2015年以来的有效新标签属性,但是如果您使用它,则您的网站将与不支持的“旧”客户端不兼容此“新” HTML5。因此,要创建一个肯定在世界范围内兼容的网站,您必须使用HTML4,更确切地说是使用2000年以来的XHTML 1.0。

这段代码中还有最后一件不好的事情,如果停用了javascript,则该表单不是函数形式的。通常,创建网站的正确方法是使它在没有javascript的情况下(至少具有主要的前端功能)正常工作,然后才添加javascript层。

因此,以我的观点,您采取了相反的方法,所以我建议您首先通过创建简单的php表单+验证来重新启动,然后再添加js层。

避免编写双重验证的技巧是在两个位置重用相同的php文件验证,第一个在简单php表单的标头中,第二个在ajax请求中使用(因此,在我们的示例中,此验证文件为my_parse_file.php,但是需要对其进行修改以处理发布者)。我没有写这个解决方案,因为它不能真正回答使用ajax的问题,而我们已经处于临界点...:D

SOa上的一句话: “兼容的Worldwideweb”就像是在这些时代严重消亡,所以,请大家使它在创建兼容的网站时得以生存:)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值