http://www.sufeinet.com/plugin.php?id=keke_group

苏飞论坛

 找回密码
 马上注册

QQ登录

只需一步,快速开始

分布式系统框架(V2.0) 轻松承载百亿数据,千万流量!讨论专区 - 源码下载 - 官方教程

HttpHelper爬虫框架(V2.7-含.netcore) HttpHelper官方出品,爬虫框架讨论区 - 源码下载 - 在线测试和代码生成

HttpHelper爬虫类(V2.0) 开源的爬虫类,支持多种模式和属性 源码 - 代码生成器 - 讨论区 - 教程- 例子

查看: 4050|回复: 0

[Asp.Net] URL中,查询字符串与HTML实体冲突,可能带来的问题

[复制链接]
发表于 2012-9-28 16:41:19 | 显示全部楼层 |阅读模式
问题相关信息(我不放在最前面,似乎有些朋友会找不到的样子.)IE10+, Safari5.17+, Firefox4.0+,Opera12+, Chrome7+ 已经按新标准实现. 所以就没有这个问题了.
参考标准 : http://www.w3.org/html/ig/zh/wiki/HTML5/tokenization  新标准明确提到,如果实体后面遇到的不是;且下一个是= 那么就不处理的.就是为了解决这个坑爹的问题的.
我们来看demo :
[code=html]<a href="http://www.baidu.com?a=1&#174;=2&#174;_a=3" >悲剧</a>[/code]
部分浏览器(对应上面已经按新标准实现的版本之下的,各个浏览器.)
点上面的链接, 会自动把  &#174; 转意成&#174; (部分浏览器会自动对转意后的字符进行编码) .  
这个bug.的本质,就是当HTML中出现相关HTML实体(HTML character entity)时.就自动转意处理了. 所以理论上, 用脚本,动态创建的资源则没有这个问题,比如 new Image().src = 'http://www.baidu.com?a=1&#174;=2'; 甚至动态创建的iframe.亦如此.
IE9- 有两个问题比其他浏览器更严重:
1. 用脚本跳转当前页比如location.href = xxx,或 location.replace(xxx) .又或者是调用window.open(xxx);如果查询字符串中包含这些html实体, 仍然会触发这个问题...
2. ,参见标准, 你会知道实体+"其他字符"   ,    "其他字符中",哪些与实体连接在一起,是没有这个问题的. 比如 &#174;a  , &#174;1     其中a, 1 与 &#174; 连接就不会有这种问题,从标准角度,甚至是  &#174;_a 也不应有问题. 但是IE9-又一次打败了我们.  至于其他特殊字符如 # ~ 等.在各个浏览器中表现各异. 考虑我们在设计字段名时,不大可能出现那些字符.我们也不再纠结其他浏览器在此处实现的差异.
所以,理论上,这个问题应该是后端的同学,在输出html时.更加要注意的问题.  而前端同学,要注意的则是跳转或弹窗时的url中是否有相关的字段包含一个无分号即为html实体的情况.
至于IE为啥这么特殊...我也没想明白...
那么,无论后端同学也好,前端同学也罢,我们可能更改已经定好的字段成本比较高.  所以其实最妥善的办法,应该是这样子: (感谢 @辰光未然 的提醒.
[code=csharp]var fixURL = function (url) {
    return url.replace(/&/g,'&');
};
//使用fixURL 去替换url中的&.然后再输出给html, 或者跳转链接,又或者弹窗... 当然,前端的同学在js代码中之所以要这样做.主要是受IE的拖累[/code]
那么大概,很多HTML 实体都会出问题:
http://www.whatwg.org/specs/web-apps/current-work/multipage/named-character-references.html#named-character-references
这个表里, 没有分号结尾的,都是隐患...  也就是下面这106个: (感谢 @kenny 提供的最新的list 地址. 我花了点时间写了个脚本.把需要处理的,都抓了出来.)
我们可以用下面这个脚本来帮忙做检测 :
[HTML] 纯文本查看 复制代码
var checkURL = function () {    var list = [ //106
            'á',
            'á',
            '&#194;',
            'a',
            '′',
            '&#198;',
            '&#230;',
            'à',
            'à',
            '&',
            '&',
            '&#197;',
            '&#229;',
            '&#195;',
            '&#227;',
            '&#196;',
            '&#228;',
            '|',
            '&#199;',
            '&#231;',
            '&#184;',
            '¢',
            '&#169;',
            '&#169;',
            '¤',
            '°',
            '÷',
            'é',
            'é',
            'ê',
            'ê',
            'è',
            'è',
            'D',
            'e',
            '&#203;',
            '&#235;',
            '&#189;',
            '&#188;',
            '&#190;',
            '>',
            '>',
            'í',
            'í',
            '&#206;',
            '&#238;',
            '&#161;',
            'ì',
            'ì',
            '&#191;',
            '&#207;',
            '&#239;',
            '&#171;',
            '<',
            '<',
            'ˉ',
            'μ',
            '·',
            ' ',
            '&#172;',
            '&#209;',
            '&#241;',
            'ó',
            'ó',
            '&#212;',
            '&#244;',
            'ò',
            'ò',
            'a',
            'o',
            '&#216;',
            '&#248;',
            '&#213;',
            '&#245;',
            '&#214;',
            '&#246;',
            '&#182;',
            '±',
            '£',
            '"',
            '"',
            '&#187;',
            '&#174;',
            '&#174;',
            '§',
            '-',
            '1',
            '2',
            '3',
            '&#223;',
            'T',
            't',
            '×',
            'ú',
            'ú',
            '&#219;',
            '&#251;',
            'ù',
            'ù',
            '¨',
            'ü',
            'ü',
            'Y',
            'y',
            '¥',
            '&#255;'
        ];
        
    return function (url) {
        var l = list;
        var i = l.length;
        var matchIndex;
        var current;
        var nextchar;
        var errors = [];
        for (i = l.length; i--;){
            matchIndex = url.indexOf(l);
            current = l;
            if(matchIndex > -1){
                if((current === '&' || current === '&') && url.charAt(matchIndex + 4) === ';'){
                    //如果是 & 或 & 我们就认为是故意要输出 & ,比如是一个调用fixURL方法修正过的URL.里面的& 会被我们替换为 amp;
                    //所以,我们要跳过它,去检查后面.
                    continue;
                }
                nextchar = url.charAt(matchIndex + current.length);
                if(!/[a-z,A-Z,0-9]/.test(nextchar)){
                    //此处我们只要发现任意一个 ,如 &#174;后面紧随字符不在 a-z,A-Z,0-9范围内.就算有问题.
                    //这样处理实际和标准的细节以及浏览器实现有细微差异. 但是本着任何浏览器来跑case,都能发现潜在威胁的原则.和实现复杂度的考虑.
                    // 我们姑且粗暴的这样处理了. 似乎还不错.
                     
                    errors.push(current + nextchar);
                }
            }
        }
        if(errors.length){
            throw Error('contains : \n' + errors.join('\n'));
        }
    };
}();

test case 1:
[HTML] 纯文本查看 复制代码
var url  = '//www.baidu.com?a=1&=2<=3&#174;=4';          
document.onclick = function () { //IE9-好了.证明我们的修正是ok的了.
      window.open(fixURL(url))
};

test case 2:
[HTML] 纯文本查看 复制代码
var url  = '//www.baidu.com?a=1&=2<=3&#174;=4';    
  try{
      checkURL(url);
  }catch(e){
      alert(e.message)
  }[



1. 开通SVIP会员,免费下载本站所有源码,不限次数据,不限时间
2. 加官方QQ群,加官方微信群获取更多资源和帮助
3. 找站长苏飞做网站、商城、CRM、小程序、App、爬虫相关、项目外包等点这里
您需要登录后才可以回帖 登录 | 马上注册

本版积分规则

QQ|手机版|小黑屋|手机版|联系我们|关于我们|广告合作|苏飞论坛 ( 豫ICP备18043678号-2)

GMT+8, 2024-11-15 18:17

© 2014-2021

快速回复 返回顶部 返回列表