友好网址的安全字符[关闭]


168

我需要创建一个包含文章的网站,并且要为其提供友好的网址,例如带有以下内容的页面的网址

标题:文章测试

应该变成:http://www.example.com/articles/article_test

当然,我需要从标题中删除一些字符,例如?#,但是我不确定要删除哪些字符。

有人可以告诉我哪些字符可以安全保存吗?


有一个类似的问题,在这里。检查一下,您可能还会在这里找到一些有用的答案(其中有很多)。
Rook 2009年

Answers:


210

引用RFC 3986的 2.3节:

“在URI中允许但没有保留用途的字符称为未保留字符。这些字符包括大写和小写字母,十进制数字,连字符,句点,下划线和波浪号。”

ALPHA  DIGIT  "-" / "." / "_" / "~"

请注意,RFC 3986列出的保留标点符号比旧版RFC 2396少


@Skip Head,“字符”是否包含拉丁编码字符,如çõ
Mohamad

6
@Mohamad:不,仅ASCII,尽管对UTF-8的支持越来越好。
Dietrich Epp

@Dietrich Epp,谢谢。我想URL是否用于装饰和SEO都无关紧要,例如:www.mysite.com/
postId]

1
@Mohamad:此处的最后一部分将被更改为post-title-with-%C3%A7-and-%C3%B5,但仍会在用户的位置栏中显示为post-title-with-ç-and-õ
Dietrich Epp

7
您的读者是葡萄牙语,因此请使用葡萄牙语字符。
Dietrich Epp

107

您需要注意两组字符:保留不安全

保留的字符是:

  • 连字号(“&”)
  • 美元(“ $”)
  • 加号(“ +”)
  • 逗号(“,”)
  • 正斜杠(“ /”)
  • 冒号(“:”)
  • 分号(“;”)
  • 等于(“ =”)
  • 问号(“?”)
  • “在”符号(“ @”)
  • 英镑(“#”)。

通常认为不安全的字符是:

  • 空间 (” ”)
  • 小于和大于(“ <>”)
  • 打开和关闭方括号(“ []”)
  • 打开和关闭大括号(“ {}”)
  • 管道(“ |”)
  • 反斜杠(“ \”)
  • 脱字号(“ ^”)
  • 百分 (”%”)

我可能忘记了一个或多个,这导致我回荡了卡尔五世的回答。从长远来看,最好使用允许字符的“白名单”,然后对字符串进行编码,而不是尝试与服务器和系统不允许的字符保持同步。


#是保留的字符,用于特定页面上的书签,通过使一个HTML元素具有匹配的name-attribute或id-attribute(sans- #symbol)来创建。
TheLonelyGhost 2014年

谢谢-我已经更新了答案。
Gary.Ray 2014年

问号在此处显示为保留和不安全-我认为它只是保留,但我可能不正确
Jonathan Basile 2015年

6
其他人似乎不同意波浪号~是不安全的。你确定是吗?
2015年

3
如果处理英语以外的其他语言,白名单就不太好。Unicode的OK代码点太多。因此,将不安全的黑名单列入正则表达式可能是最容易实现的。
Patanjali 2015年

41

最好只保留一些字符(白名单),而不要删除某些字符(黑名单)。

从技术上讲,只要您正确编码,就可以允许任何字符。但是,为回答问题的实质,您只应允许使用以下字符:

  1. 小写字母(将大写转换为小写)
  2. 数字,0到9
  3. 破折号-或下划线_
  4. 蒂尔德〜

其他所有内容都有潜在的特殊含义。例如,您可能认为可以使用+,但是可以将其替换为空格。&也很危险,尤其是在使用某些重写规则的情况下。

与其他评论一样,请查看标准和规格以获取完整的详细信息。


15
我今天发现,对于URL安全的Base64编码器来说,使用字符是一个错误的选择,因为在极少数情况下,编码数据可能会产生两个连续的点(“ ..”),这在它指向父目录。
2011年

5
@pohl:这只是一个问题,如果您的URL被用作代码中的文件路径,或者在您的代码中,或者您的Web服务器在将请求转发到脚本之前实际上试图将URL映射到文件(不幸的是很常见)。
安德烈·卡伦

4
实际上,在我们的例子中,将其用作文件路径是可以的,因为在UNIX文件中,文件名中可以​​包含多个甚至连续的点。对于我们来说,问题出在一个名为Site Scope的监视工具中,该工具存在错误(也许是天真的正则表达式),并且正在报告虚假的停机时间。对于我们来说,我们陷入了Site Scope的旧版本中,管理团队拒绝支付升级费用,并且一个非常重要的客户将Site Scope(不等同)写入其合同中。诚然,大多数人不会在我的鞋子里找到自己。
pohl 2011年

8
谢天谢地,有人发布了一份列表,却没有太多的麻烦。至于点(。)-如@pohl所说,请勿使用它!这是IIS上另一种奇怪的情况(不知道其他Web服务器上是否会发生这种情况):如果它在URL的末尾,则很可能会出现404错误(它将尝试搜索[/ pagename]
。page

34

永远安全

这些是安全的(理论上/规格上),基本上除了域名之外的任何地方。
对未列出的任何内容进行百分比编码,您可以开始使用。

    A-Z a-z 0-9 - . _ ~ ( ) ' ! * : @ , ;

有时很安全

仅在特定的URL组件中使用时才安全;小心使用。

    Paths:     + & =
    Queries:   ? /
    Fragments: ? / # + & =
    

从不安全

根据URI规范(RFC 3986),所有其他字符必须进行百分比编码。这包括:

    <space> <control-characters> <extended-ascii> <unicode>
    % < > [ ] { } | \ ^
    

如果要考虑最大兼容性,请将字符集限制为AZ az 0-9-_。
(仅对文件扩展名使用句点)。

注意上下文

即使根据规范有效,根据上下文,URL仍然可能是“不安全的”。例如,包含无效文件名字符的file:/// URL,或者在不用作分隔符时,包含“?”,“ =“和“&”的查询组件。正确处理这些情况通常取决于您的脚本,并且可以解决,但这是需要牢记的。


您能否提供第二份索赔的任何来源(“有时安全”)?特别是,我认为您说=对查询不安全是错误的。例如,FIQL接受等号并将其自身描述为“ URI友好的”和“已优化并打算在查询组件中使用”。在我的解释中,RFC 3986明确允许查询中使用“ =”,“&”,“ +”和其他。
DanielM

@DanielM“?”,“ =”和“&”在每个规范的查询中均有效,尽管实际上它们广泛用于解析查询中的名称/值对。因此,它们作为名称/值本身的一部分可能是不安全的。这是否构成“不安全”可能是一个见解。
比霍尔

根据要求提供一些资料。(1)RFC 3986,第3.4节:“ [...]查询组件通常用于以'键=值'对的形式携带识别信息[...](2)WhatWG URL Spec,第。6.2:“构造和字符串化URLSearchParams对象非常简单:[...] params.toString() // "key=730d67"”(3)PHP手册,http-build-query:“生成URL编码的查询字符串。[...]上面的示例将输出:0=foo&1=bar[...]“(4)J. Starr,易腐出版社:“构建网页时,通常需要添加需要参数化查询字符串的链接。”
比霍尔

@Beejor:我正在构建一个URL,并且我使用'-'和';' 施工期间。它不是Web应用程序,而是移动应用程序。不是Web开发人员,因此,如果在Path属性中使用上述两个字符,我会安全吗?docs.microsoft.com/en-us/dotnet/api/…–
karsnen

1
@karsnen这些是有效的URL字符。尽管如果用于引用本地文件系统上的路径,请记住某些系统不允许文件名中的某些字符。例如,“ file:/// path / to / my:file.ext”在Mac上将无效。
比尤尔

17

查看RFC3986-统一资源标识符(URI):通用语法,您的问题围绕URI 的路径部分展开。

    foo://example.com:8042/over/there?name=ferret#nose
     \_/   \______________/\_________/ \_________/ \__/
      |           |            |            |        |
   scheme     authority       path        query   fragment
      |   _____________________|__
     / \ /                        \
     urn:example:animal:ferret:nose

援引第3.3节,对于URI有效字符segment的类型的pchar

pchar =保留/ pct编码/ sub-delims /“:” /“ @”

分解为:

ALPHA / DIGIT / "-" / "." / "_" / "~"

pct-encoded

"!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="

":" / "@"

或者换句话说:你可以使用任何(非控制- )字符从ASCII表中除外 /?#[]

RFC1738-统一资源定位符(URL)支持这种理解。


2
这是理论上正确答案的一个很好的例子,当将其应用于我们实际生活的现实世界时会导致麻烦。确实,这些字符中的大多数在大多数情况下不会引起问题。但是在现实世界中存在诸如代理,路由器,网关,中继等之类的东西,所有这些东西都“喜欢”以无视理论标准的方式检查URL并与之交互。为了避免这些陷阱,您几乎只能转义除字母数字,破折号,下划线和句号以外的所有内容。
deltamind106

1
@ deltamind106您能否提供示例和/或参考来阐明根据RFC哪些字符实际上是安全的?我更愿意在回答中坚持标准支持的事实,如果您能指出我可能忽略的任何事实,我很乐意更新我的回答。
Philzen 2015年

2
@ deltamind106我建议我们尝试使产品遵循标准,而不是告诉开发人员不要这样做。我认为您应该提出警告,但如有必要,我们应该尽力向供应商报告违规情况。
罗坦

@Philzen:我正在构建一个URL,并且我使用了'-'和';' 施工期间。它不是Web应用程序,而是移动应用程序。不是Web开发人员,因此,如果在Path属性中使用上述两个字符,我会安全吗?docs.microsoft.com/en-us/dotnet/api/…–
karsnen

1
@karsnen当然可以,-并且;很安全,这就是我的答案和RFC明确指出的内容。
Philzen

12

未保留= ALPHA / DIGIT /“-” /“。/“ _” /“〜”


3
“ ALPHA”不是暗指“ DIGIT”吗?我假设ALPHA是“字母数字”的缩写,字母数字表示大写,小写和数字。
吕克

11
实际上,字母并不意味着字母数字。字母和数字是2个不同的事物,字母数字是这些事物的组合。他本可以这样写答案:ALPHANUMERIC /“-” /“。/“ _” /“〜”
MacroMan

1
RFC 3986中“未保留”的ABNF表示法将它们分开列出。
Patanjali 2015年

11

从您描述的上下文中,我怀疑您实际上要制作的是所谓的“ SEO子弹”。这些最佳的最佳实践是:

  1. 转换为小写
  2. 将az和0-9以外的整个字符序列转换为一个连字符(-)(非下划线)
  3. 从网址中删除“停用词”,即无法有意义地索引的词,例如“ a”,“ an”和“ the”;谷歌“停用词”获得广泛的列表

因此,举例来说,一篇标题为“!@%$ *表示在漫画中发誓的用法”的文章将获得“用法-代表-发誓的漫画”字样。


从网址中删除这些“停用词”真的是一种好方法吗?搜索引擎会因此而惩罚网站吗?
Paulo

一般认为,搜索引擎只会识别URL的某些部分和/或降低其后半部分的重要性,因此,通过删除停用词,您可以最大程度地增加嵌入URL的关键字数量实际排名。
混乱

1
@chaos如果考虑到以下因素,您是否仍然建议删除StopWord:seobythesea.com/2008/08/google-stopword-patent另外,您能否推荐一个好的停用词列表?这是我到目前为止找到的最好的列表-link-assistant.com/seo-stop-words.html
nikib3ro 2012年

@ kape123对我来说,这似乎不是一个很好的清单。“ c”和“ d”是编程语言,其他许多单词也很有意义。我可能会只删除基本的:a和and在with上。
mpen


6

从SEO角度来看,连字符比下划线更可取。转换为小写字母,删除所有撇号,然后用单个连字符替换所有非字母数字字符串。从头到尾修剪多余的连字符。


3

我遇到了类似的问题,我想拥有漂亮的网址,并得出结论,我必须在网址中仅允许使用字母,数字,-和_。很好,然后我写了一些不错的正则表达式,我意识到它可以识别所有UTF8字符,而不是.NET中的字母,因此被搞砸了。这似乎是.NET正则表达式引擎的已知问题。所以我得到了这个解决方案:

private static string GetTitleForUrlDisplay(string title)
{
    if (!string.IsNullOrEmpty(title))
    {
        return Regex.Replace(Regex.Replace(title, @"[^A-Za-z0-9_-]", new MatchEvaluator(CharacterTester)).Replace(' ', '-').TrimStart('-').TrimEnd('-'), "[-]+", "-").ToLower();
    }
    return string.Empty;
}


/// <summary>
/// All characters that do not match the patter, will get to this method, i.e. useful for unicode chars, because
/// .NET impl of regext do not handle unicode chars. So we use char.IsLetterOrDigit() which works nicely and we 
/// return what we approve and return - for everything else.
/// </summary>
/// <param name="m"></param>
/// <returns></returns>
private static string CharacterTester(Match m)
{
    string x = m.ToString();
    if (x.Length > 0 && char.IsLetterOrDigit(x[0]))
    {
        return x.ToLower();
    }
    else
    {
        return "-";
    }
}

3
.NET正则表达式实际上很好地支持unicode。您必须对所有字母使用Unicode字符类,例如\ p {L}。请参阅msdn.microsoft.com/en-us/library/20bw873z.aspx#CategoryOrBlock
TheCycoONE 2013年

1

当我通过ajax / php将值返回到某个网址,然后该页面再次读取该网址时,我发现将我的网址编码为一个安全的网址非常有用。

PHP输出带有url编码器的特殊字符&

//PHP returning the sucess info of ajax request
echo "".str_replace('&','%26',$_POST['name'])." category was changed";

//javascript sending the value to url
window.location.href='time.php?return=updated&val='+msg;

//javascript/php executing the function printing the value of the url,
//now with the text normally lost in space because of the reserved & character.

setTimeout("infoApp('updated','<?php echo $_GET['val'];?>');",360);

希望有人发现我的小代码摘录有用!:)



-4

3至50个字符。可以包含小写字母,数字和特殊字符-点(。),破折号(-),下划线(_)和速率(@)。


4
任何为参考?
dakab '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.