perishablepress.com Open in urlscan Pro
69.16.192.217  Public Scan

URL: https://perishablepress.com/stop-using-unsafe-characters-in-urls/
Submission: On November 05 via manual from US — Scanned from US

Form analysis 4 forms found in the DOM

GET https://perishablepress.com/

<form method="get" class="search" action="https://perishablepress.com/" onsubmit="location.href='https://perishablepress.com/search/'+encodeURIComponent(this.s.value).replace(/%20/g,'+');return false;">
  <label for="s-32" class="h">Search</label>
  <input id="s-32" name="s" type="search" title="Search" maxlength="100" value="" placeholder="Type &amp; press enter to search..">
</form>

POST https://perishablepress.com/wp/wp-comments-post.php

<form action="https://perishablepress.com/wp/wp-comments-post.php" method="post" id="commentform" class="comment-form" novalidate="">
  <div class="comment-policy t2">
    <p>Name and email required. Email kept private. Basic markup allowed. Please wrap any small/single-line code snippets with <code>&lt;code&gt;</code> tags. Wrap any long/multi-line snippets with <code>&lt;pre&gt;&lt;code&gt;</code> tags. For more
      info, check out the <a target="_blank" href="/comment-policy/" title="Perishable Press Comment Policy">Comment Policy</a> and <a target="_blank" href="/privacy.html" title="Perishable Press Privacy Policy">Privacy Policy</a>.</p>
    <p class="comment-feed"><a target="_blank" href="https://perishablepress.com/stop-using-unsafe-characters-in-urls/feed/" title="Subscribe via RSS feed">Subscribe to comments on this post</a></p>
  </div>
  <div class="comment-field"><label for="author">Name</label><input id="author" name="author" type="text" value="" placeholder="Enter your name"></div>
  <div class="comment-field"><label for="email">Email</label><input id="email" name="email" type="email" value="" placeholder="Enter your email"></div>
  <div class="comment-field"><label for="url">Website</label><input id="url" name="url" type="url" value="" placeholder="Enter your website"></div>
  <div class="comment-field"><label for="comment">Comment</label><textarea id="comment" name="comment" placeholder="Enter your comment"></textarea></div>
  <p class="form-submit"><input name="submit" type="submit" id="submit" class="submit" value="Post Comment"> <input type="hidden" name="comment_post_ID" value="15055" id="comment_post_ID">
    <input type="hidden" name="comment_parent" id="comment_parent" value="0">
  </p>
</form>

POST https://perishablepress.us11.list-manage.com/subscribe/post?u=3b1eb5693738305478b07e6c4&id=a5e4fc9f37

<form action="https://perishablepress.us11.list-manage.com/subscribe/post?u=3b1eb5693738305478b07e6c4&amp;id=a5e4fc9f37" method="post" target="_blank" novalidate="">
  <div class="t1">Newsletter</div>
  <div class="t2">Get news, updates, deals &amp; tips via email.</div>
  <label for="mce-EMAIL-48" class="h">Enter your email</label>
  <input id="mce-EMAIL-48" name="EMAIL" type="email" placeholder="Enter your email" required="">
  <input type="text" name="b_3b1eb5693738305478b07e6c4_a5e4fc9f37" tabindex="-1" value="" aria-hidden="true" style="position:absolute;left:-9999em;">
  <input type="submit" name="subscribe" value="Subscribe">
  <div class="t3">Email kept private. Easy unsubscribe anytime.</div>
</form>

POST https://perishablepress.us11.list-manage.com/subscribe/post?u=3b1eb5693738305478b07e6c4&id=a5e4fc9f37

<form action="https://perishablepress.us11.list-manage.com/subscribe/post?u=3b1eb5693738305478b07e6c4&amp;id=a5e4fc9f37" method="post" target="_blank" novalidate="">
  <div class="t1">Perishable Press Newsletter</div>
  <div class="t2">Get news, updates, deals &amp; tips via email.</div>
  <label for="mce-EMAIL-91" class="h">Enter your email</label>
  <input id="mce-EMAIL-91" name="EMAIL" type="email" placeholder="Enter your email" required="">
  <input type="text" name="b_3b1eb5693738305478b07e6c4_a5e4fc9f37" tabindex="-1" value="" aria-hidden="true" style="position:absolute;left:-9999em;">
  <input type="submit" name="subscribe" value="Subscribe">
  <div class="t3">Your email will remain private. Easy unsubscribe anytime.</div>
</form>

Text Content

Main Menu Night Mode
 * Books
 * Plugins
 * Search

Save 25% on Wizard’s SQL for WP w/ code: WIZARDSQL
Search
Perishable Press
Web Dev + WordPress + Security
.htaccess made easy: Improve site performance and security.
Related Posts
 * Block Tough Proxies
 * They’re Scanning for Your Backup Files
 * 7G Firewall: September 2020 Update
 * WordPress Block Proxy Visits
 * 4 Ways to Make a WordPress Site Private Access Only

+ More related posts »


(PLEASE) STOP USING UNSAFE CHARACTERS IN URLS

♦ Posted by Jeff Starr in Security
Updated May 31, 2022 • 26 comments

Just as there are specifications for designing with CSS, HTML, and JavaScript,
there are specifications for working with URIs/URLs. The Internet Engineering
Task Force (IETF) clearly defines these specifications in RFC 3986: Uniform
Resource Identifier (URI): Generic Syntax. Within that document, there are
guidelines regarding which characters may be used safely within URIs. This post
summarizes the information, and encourages developers to understand and
implement accordingly.



FYI: URL is a specific type of URI. Learn more »


TABLE OF CONTENTS

 * About the RFC 3986 Specification
 * Character Encoding Chart
 * More about Character Types
   * Reserved Characters
   * Unreserved Characters
   * Usafe Characters
   * ASCII Characters
 * URLs in HTML and JavaScript
 * Unsafe Characters in WordPress
 * A Dangerous Trend
 * URLs and Firewall Security
 * WordPress and 5G Blacklist
 * Take-home Message


ABOUT THE RFC 3986 SPECIFICATION

The specifications for Uniform Resource Identifiers (URIs) and more specifically
Uniform Resource Locators (URLs) provide a safe, consistent way to request,
identify, and resolve resources on the Internet. As clearly stated in RFC 3986:

> A Uniform Resource Identifier (URI) is a compact sequence of characters that
> identifies an abstract or physical resource. This specification defines the
> generic URI syntax and a process for resolving URI references that might be in
> relative form, along with guidelines and security considerations for the use
> of URIs on the Internet. The URI syntax defines a grammar that is a superset
> of all valid URIs, allowing an implementation to parse the common components
> of a URI reference without knowing the scheme-specific requirements of every
> possible identifier.

Thanks to the brilliant work of experts such as Tim Berners-Lee, Roy Fielding,
Larry Masinter, and Mark McCahill, developers have a safe, consistent protocol
for working with URIs/URLs on the Web. It is important that we adhere to these
specifications when developing software, plugins, apps, and the like. Failing to
do so introduces potential security vulnerabilities which may be exploited by
nefarious individuals and malicious scripts.


CHARACTER ENCODING CHART

To help promote the cause of Web Standards and adhering to specifications, here
is a quick reference chart explaining which characters are “safe” and which
characters should be encoded in URLs.

Classification Included characters Encoding required? Safe characters
Alphanumerics [0-9a-zA-Z] and unreserved characters. Also reserved characters
when used for their reserved purposes (e.g., question mark used to denote a
query string) NO Unreserved characters - . _ ~ (does not include blank space) NO
Reserved characters : / ? # [ ] @ ! $ & ' ( ) * + , ; = (does not include blank
space) YES1 Unsafe characters Includes the blank/empty space and " < > % { } | \
^ ` YES ASCII Control characters Includes the ISO-8859-1 (ISO-Latin) character
ranges 00-1F hex (0-31 decimal) and 7F (127 decimal) YES Non-ASCII characters
Includes the entire “top half” of the ISO-Latin set 80-FF hex (128-255 decimal)
YES All other characters Any character(s) not mentioned above should be
percent-encoded. YES

1 Reserved characters only need encoded when not used for their defined,
reserved purposes.
FYI: As with the specifications, the above chart is a work in progress and
subject to change. If you have any suggestions to improve it, please let me
know.

The above chart is a summary of which characters need to be encoded in
URIs/URLs, based on the current specification RFC 3986. Web developers should be
mindful when working with URLs in their applications and implementations.


MORE ABOUT CHARACTER TYPES

Here is some further discussion about each of the various character types:
Reserved Characters, Unreserved Characters, Unsafe Characters, and ASCII
Characters.


RESERVED CHARACTERS

More information about “reserved” characters from RFC 3986:

URIs include components and subcomponents that are delimited by characters in
the “reserved” set. These characters are called “reserved” because they may (or
may not) be defined as delimiters by the generic syntax, by each scheme-specific
syntax, or by the implementation-specific syntax of a URI’s dereferencing
algorithm. If data for a URI component would conflict with a reserved
character’s purpose as a delimiter, then the conflicting data must be
percent-encoded before the URI is formed.

reserved    = gen-delims / sub-delims

gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"

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

The purpose of reserved characters is to provide a set of delimiting characters
that are distinguishable from other data within a URI. URIs that differ in the
replacement of a reserved character with its corresponding percent-encoded octet
are not equivalent. Percent-encoding a reserved character, or decoding a
percent-encoded octet that corresponds to a reserved character, will change how
the URI is interpreted by most applications. Thus, characters in the reserved
set are protected from normalization and are therefore safe to be used by
scheme-specific and producer-specific algorithms for delimiting data
subcomponents within a URI. […]

If a reserved character is found in a URI component and no delimiting role is
known for that character, then it must be interpreted as representing the data
octet corresponding to that character’s encoding in US-ASCII.


UNRESERVED CHARACTERS

More information about “unreserved” characters from RFC 3986:

Characters that are allowed in a URI but do not have a reserved purpose are
called unreserved. These include uppercase and lowercase letters, decimal
digits, hyphen, period, underscore, and tilde.

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

URIs that differ in the replacement of an unreserved character with its
corresponding percent-encoded US-ASCII octet are equivalent: they identify the
same resource. However, URI comparison implementations do not always perform
normalization prior to comparison (see Normalization and Comparison). For
consistency, percent-encoded octets in the ranges of ALPHA (%41–%5A and
%61–%7A), DIGIT (%30–%39), hyphen (%2D), period (%2E), underscore (%5F), or
tilde (%7E) should not be created by URI producers and, when found in a URI,
should be decoded to their corresponding unreserved characters by URI
normalizers.


USAFE CHARACTERS

More about “unsafe” characters from RFC 1738. Note that RFC 1738 is now
obsolete, however the information remains useful in the general sense, and is
shared below for educational and reference purposes.

Characters can be unsafe for a number of reasons. The space character is unsafe
because significant spaces may disappear and insignificant spaces may be
introduced when URLs are transcribed or typeset or subjected to the treatment of
word-processing programs. The characters < and > are unsafe because they are
used as the delimiters around URLs in free text; the quote mark (") is used to
delimit URLs in some systems. The character # is unsafe and should always be
encoded because it is used in World Wide Web and in other systems to delimit a
URL from a fragment/anchor identifier that might follow it. The character % is
unsafe because it is used for encodings of other characters. Other characters
are unsafe because gateways and other transport agents are known to sometimes
modify such characters. These characters are {, }, |, \, ^, ~, [, ], and `.

All unsafe characters must always be encoded within a URL. For example, the
character # must be encoded within URLs even in systems that do not normally
deal with fragment or anchor identifiers, so that if the URL is copied into
another system that does use them, it will not be necessary to change the URL
encoding.

Again, the above “unsafe character” information is from RFC 1738, which is
obsoleted and replaced by RFC 3986. For example, the tilde ~ character is now an
unreserved character and does not need to be encoded. Likewise with the #
hashtag (octothorp) character, it now is a reserved character and does not need
to be encoded unless used for non-reserved purposes. If in doubt, follow the RFC
3986.


ASCII CHARACTERS

More information about ASCII characters from W3C Internationalization:

Currently Web addresses are typically expressed using Uniform Resource
Identifiers or URIs. The URI syntax defined in RFC 3986 STD 66 (Uniform Resource
Identifier (URI): Generic Syntax) essentially restricts Web addresses to a small
number of characters: basically, just upper and lower case letters of the
English alphabet, European numerals and a small number of symbols.

The original reason for this was to aid in transcription and usability, both in
computer systems and in non-computer communications, to avoid clashes with
characters used conventionally as delimiters around URIs, and to facilitate
entry using those input facilities available to most Internet users.

User’s expectations and use of the Internet have moved on since then, and there
is now a growing need to enable use of characters from any language in Web
addresses. A Web address in your own language and alphabet is easier to create,
memorize, transcribe, interpret, guess, and relate to. It is also important for
brand recognition. This, in turn, is better for business, better for finding
things, and better for communicating. In short, better for the Web.

Imagine, for example, that all web addresses had to be written in Japanese
katakana, as shown in the example below. How easy would it be for you, if you
weren’t Japanese, to recognize the content or owner of the site, or type the
address in your browser, or write the URI down on notepaper, etc.?

http://ヒキワリ.ナットウ.ニホン

There have been several developments recently that begin to make this possible.
[…] Learn more at w3.org »


URLS IN HTML AND JAVASCRIPT

In earlier versions of HTML, the entire range of the ISO-8859-1 (ISO-Latin)
character set may be used in documents. Since HTML4, the entire Unicode
character set may also be used. In HTTP, however, the range of allowed
characters is expressly limited to only a subset of the US-ASCII character set
(see the Character Encoding Chart for details).

So, when writing HTML, ISO and Unicode characters may be used everywhere in the
document except where URLs are referenced*. This includes the following
elements:

<a>, <applet>, <area>, <base>, <bgsound>, <body>,
<embed>, <form>, <frame>, <iframe>, <img>, <input>, <link>,
<object>, <script>, <table>, <td>, <th>, <tr>

* Update: As Mathias explains, “it’s perfectly okay to leave those symbols
unencoded, as browsers will take care of them as per the URL parsing algorithm
in the HTML spec.”

As flexible as HTML is in terms of which characters may be used, there are
strict limits to which characters may be used when referencing URLs. This
limitation applies not only to URLs used in HTML, but also to URLs referenced in
any coding language (e.g., JavaScript, PHP, Perl, etc.).


UNSAFE CHARACTERS IN WORDPRESS

Note: Things have changed a lot with WordPress and URI specification. So the
following information may be outdated, but the example serves to illustrate how
developers should be mindful of specification when crafting URIs in
applications.

In version 3.5, WordPress uses improper, unencoded URLs to enqueue JavaScript
libraries. Specifically, in the WP Admin area, various URLs are called using
square brackets [ ], which are classified as unsafe characters. Here is an
example:

http://example.com/wp-admin/load-scripts.php?c=1&load[]=swfobject,jquery,utils&ver=3.5

Also affecting the WordPress Admin, here is an example of unsafe characters in
URLs, pointed out in this comment:

http://test.site/wp-admin/post.php?t=1347548645469?t=1347548651124?t=1347548656685?t=1347548662469?t=1347548672300?t=1347548681615?

“Special-use” specifies that the question mark “?” is reserved for the
denotation of a query string, but must be encoded for any other purpose.
Unfortunately, WordPress is including multiple unencoded question marks for URLs
involved with its “preview” functionality. In other words, in any URL, the first
question mark “?” may be unencoded to denote the query string, but subsequent
“?” must be encoded.

These errors may not be a huge deal, but they increase potential vulnerability
and certainly should be fixed in the next WP update. Likewise, future versions
of WordPress should keep URI/URL specifications in mind and verify that all URLs
are properly encoded.


A DANGEROUS TREND

Note: Things have changed a lot with Google and URI specification. So the
following information may be outdated, but the example serves to illustrate how
developers should be mindful of specification when crafting URIs in
applications.

WordPress isn’t the only popular piece of software that is not following
specification; rather, we’re seeing a disturbing trend wherein big companies
such as Google are including unsafe characters in their URLs. Here is a recently
reported example:

http://blog.sergeys.us/beer?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed:+SergeySus+(Sergey+Sus+Photography+%C2%BB+Blog)&utm_content=Google+Reader

Notice the unencoded colon : character? Apparently Google is including them in
URLs for FeedBurner and Google Reader. Hopefully this is just an oversight that
will be corrected in a future update.

For more examples of unsafe characters in popular apps and plugins, scan through
some of the comments left on my 5G, 6G (beta), and BBQ plugin.


URLS AND FIREWALL SECURITY

For the record, the 5G Blacklist, 6G Firewall (beta) — and all of my firewalls
for that matter — are built on the foundation of IETF specifications. As
explained in detail here and here, the .htaccess rules used in my G-series
firewalls are designed to block malicious URL requests such as those that
contain unsafe characters. Other firewall/security plugins and scripts operate
in similar fashion, using standards and specifications to determine which URLs
are potentially dangerous.

> Developers, please stop using unsafe characters in URLs.

Many WAF firewalls and security applications rely on pattern-recognition to help
protect their sites against threatening activity, but such security measures
fail when developers ignore specification and include unencoded unsafe
characters in URLs. Worse, by introducing inconsistency into the system,
noncompliant scripts pose a potential security risk and open the doors to
attacks.


WORDPRESS AND 5G BLACKLIST

Note: This section contains outdated information. WordPress now is way beyond
version 3.5, and the URI specification has changed considerably. Also, the 5G
Blacklist is superseded by the 6G and 7G Firewall. And 8G is in the works :)

As mentioned, WordPress 3.5 includes unencoded square brackets in various URLs
in the Admin area. As explained, the 5G Blacklist blocks such unsafe characters
to help users secure their WP-powered sites. Thus, if you’re running both
WordPress and 5G, there will be an issue wherein certain URL requests are denied
with a “403 – Forbidden” response.

So, until WordPress can get things fixed up, here is how to modify the 5G
Blacklist (don’t even think about modifying any WP core files) to “allow” those
unsafe URLs to pass through the firewall.

STEP 1

In the 5G Blacklist, locate this section of code:

# 5G:[QUERY STRINGS]
<ifModule mod_rewrite.c>
 RewriteEngine On
 RewriteBase /
 RewriteCond %{QUERY_STRING} (environ|localhost|mosconfig|scanner) [NC,OR]
 RewriteCond %{QUERY_STRING} (menu|mod|path|tag)\=\.?/? [NC,OR]
 RewriteCond %{QUERY_STRING} boot\.ini  [NC,OR]
 RewriteCond %{QUERY_STRING} echo.*kae  [NC,OR]
 RewriteCond %{QUERY_STRING} etc/passwd [NC,OR]
 RewriteCond %{QUERY_STRING} \=\\%27$   [NC,OR]
 RewriteCond %{QUERY_STRING} \=\\\'$    [NC,OR]
 RewriteCond %{QUERY_STRING} \.\./      [NC,OR]
 RewriteCond %{QUERY_STRING} \?         [NC,OR]
 RewriteCond %{QUERY_STRING} \:         [NC,OR]
 RewriteCond %{QUERY_STRING} \[         [NC,OR]
 RewriteCond %{QUERY_STRING} \]         [NC]
 RewriteRule .* - [F]
</ifModule>

STEP 2

Replace that entire block of code with this revised version that excludes the
rules that block the unsafe characters:

# 5G:[QUERY STRINGS]
<ifModule mod_rewrite.c>
 RewriteEngine On
 RewriteBase /
 RewriteCond %{QUERY_STRING} (environ|localhost|mosconfig|scanner) [NC,OR]
 RewriteCond %{QUERY_STRING} (menu|mod|path|tag)\=\.?/? [NC,OR]
 RewriteCond %{QUERY_STRING} boot\.ini  [NC,OR]
 RewriteCond %{QUERY_STRING} echo.*kae  [NC,OR]
 RewriteCond %{QUERY_STRING} etc/passwd [NC,OR]
 RewriteCond %{QUERY_STRING} \=\\%27$   [NC,OR]
 RewriteCond %{QUERY_STRING} \=\\\'$    [NC,OR]
 RewriteCond %{QUERY_STRING} \.\./      [NC,OR]
 RewriteCond %{QUERY_STRING} \?         [NC,OR]
 RewriteCond %{QUERY_STRING} \:         [NC]
 RewriteRule .* - [F]
</ifModule>

Done. No further edits should be required, unless you’ve made any of your own
modifications.


TAKE-HOME MESSAGE

When developing for the Web, adherence to standards and protocols is important.
By taking the time to properly encode your URLs, you eliminate inconsistency,
eliminate vulnerabilities, facilitate extensibility, and ensure proper
functionality. Hopefully this article serves as a reminder and helps clear up
any confusion about which characters need encoded and why it’s so important to
do so.



blacklist http tips url
About the Author
Jeff Starr = Creative thinker. Passionate about free and open Web.
Digging Into WordPress: Take your WordPress skills to the next level.
← Next Post
Protection for WordPress Pingback Vulnerability
Previous Post →
Printed .htaccess books


26 RESPONSES TO “(PLEASE) STOP USING UNSAFE CHARACTERS IN URLS”

 1.  emrah 2012/12/31 7:49 pm • Reply
     
     this post is racist. web is evolving, and there are enough space for other
     charsets. Not only English chars.
     
     * Jeff Starr 2012/12/31 8:23 pm • Post Author • Reply
       
       Wow, interesting opinion, emrah. Thanks for chiming in with that.
       
       I should add the post merely strives to explain existing specifications
       (and why they’re important), it makes no value judgments one way or
       another regarding which character sets are better/worse than others.
       Totally not the point here.
       
       And I’m pretty sure that UTF-8 includes non-english characters as well,
       so no need to start accusing anything/anyone of being “racist”. Sheesh.
       
       * emrah 2013/01/01 8:15 am
         
         ok i was kidding with a little truth. UTF-8 is fine enough.
       
         
       * Jeff Starr 2013/01/01 11:43 pm • Post Author
         
         That’s good to know.. I was genuinely concerned about you ;)
       
         
       * Mathias Bynens 2013/01/03 6:09 am
         
         Minor nitpick: UTF-8 is a character encoding, so technically there is
         no such thing as “UTF-8 characters”. You probably meant to say “Unicode
         symbols”.
       
         
       * Jeff Starr 2013/01/03 5:49 pm • Post Author
         
         Yes that is what I meant to say, thanks Mathias.
       
         
       
     
 2.  Paul 2013/01/01 7:16 am • Reply
     
     Admirably thorough article. Let’s hope Google is reading.

     
 3.  Mathias Bynens 2013/01/02 4:18 am • Reply
     
     > The specifications for Uniform Resource Identifiers (URIs) and more
     > specifically Uniform Resource Locators (URLs) provide a safe, consistent
     > way to request, identify, and resolve resources on the Internet. As
     > clearly stated in RFC3986: […]
     
     If only that were true. Sadly, RFC3986 doesn’t match reality. That’s why
     Anne van Kesteren has been working on a URL spec based on existing
     implementations.
     
     > In HTTP, however, the range of allowed characters is expressly limited to
     > only a subset of the US-ASCII character set […] So, when writing HTML,
     > ISO and Unicode characters may be used everywhere in the document except
     > where URLs are referenced.
     
     That’s not true at all. HTML != HTTP. <a href=☺>…</a> is perfectly valid
     HTML. It’s up to browsers to resolve special characters to their
     percent-encoded escape sequences as needed before any HTTP requests are
     made to the URL. For more information, see the URL parsing algorithm in the
     HTML spec (404 link removed 2014/07/20).
     
     Also, in a blog post on special characters in URLs, you might want to
     mention Punycode.
     
     * Jeff Starr 2013/01/02 6:41 pm • Post Author • Reply
       
       Great feedback, Mathias, thank you. The new spec looks ambitious and
       promising. It will be interesting to watch as things unfold in 2013.
       
       For your second point, I guess I’m confused.. researching this topic on
       the Web, I came across numerous sources, including this article, which
       seem to contradict what you’re saying here.. Also, not all HTTP requests
       are initiated by browsers, especially those involving unsafe characters,
       which are usually transmitted via script, command line, etc. The main
       point of the article is that unsafe characters should not be present in
       the URL, according to the referenced specifications. A smiley face may be
       perfectly valid HTML, but it needs to be encoded to be safe for HTTP.
       
       Then again, my expertise is admittedly limited in this area, so any
       further infos are most welcome.
       
       * Mathias Bynens 2013/01/03 6:04 am
         
         Hey Jeff, thanks for the reply! I’ll try to explain what I meant
         exactly, in case it was unclear.
         
         I fail to see where that article contradicts anything I’m saying.
         You’re right that those special characters shouldn’t be used without
         encoding them in URLs as far as HTTP and RFC3986 are concerned — but
         contrary to what you’re saying here, in HTML it’s perfectly okay to
         leave those symbols unencoded, as browsers will take care of them as
         per the URL parsing algorithm in the HTML spec.
       
         
       * Jeff Starr 2013/01/03 6:17 pm • Post Author
         
         Ah, that makes sense, thanks for explaining. I went ahead and added a
         note in that section of the article to clarify.
         
         Question: where in the spec does it explain how browsers should handle
         unsafe and reserved characters? For example, if I have an HTML document
         that references a URL containing, say, square brackets (classified as
         “unsafe”):
         
         http://example.com/wp-admin/load-scripts.php?c=1&load[]=swfobject,jquery,utils&ver=3.5
         
         As mentioned, the issue with WordPress is that browsers aren’t encoding
         the square brackets that are included in some URLs. Similarly with
         Google, there are additional question marks (“reserved” characters)
         included in URLs that aren’t getting encoded. It would be great to hear
         your thoughts on what’s happening (or not) with this issue.
       
         
       
     
 4.  Yael K. Miller 2013/01/02 10:42 am • Reply
     
     Thanks for writing this post — I had no idea that an URL itself could be
     unsafe.
     
     Google also uses “?” when you create goal-specific URLs in Google
     Analytics.
     
     And Amazon loves making long URLs when you’re searching on amazon.com
     Example (my business partner’s books):
     http://www.amazon.com/s/ref=nb_sb_noss_1?url=search-alias%3Ddigital-text&field-keywords=Phyllis+Zimbler+Miller
     
     (Although, I could be wrong: when ? or % is displayed does that mean it’s
     always un-encoded or is Firefox displaying encoded characters as
     un-encoded?)
     
     Ok, so where can I find the information to encode these unsafe characters?
     
     * Jeff Starr 2013/01/02 6:53 pm • Post Author • Reply
       
       Hi Yael, thanks for the feedback. Just to be clear, the first instance of
       “?” in a URL denotes a query string and is valid; it’s only subsequent
       instances of “?” that need encoding. Also, the Amazon URL you mention
       looks valid, and technically there is nothing wrong with “long” URLs
       (although they can be unwieldy to work with).
       
       As Mathias mentions in the previous comment, it’s up to browsers to
       properly encode/escape URLs before sending the request, but I’m not sure
       if that’s always the case.
       
       And to encode unsafe characters, any online URL decoder/encoder should do
       the job, for example this one. There are various conversion charts also
       available online. If I have time, I’ll try posting an article about this.
       
       * Yael K. Miller 2013/01/03 10:18 am
         
         Thanks.
       
         
       
     
 5.  Maxi 2013/01/07 2:16 am • Reply
     
     You
     Are
     Brilliant!
     
     thanks for sharing 5G and this solution to my newly 403 problems

     
 6.  Sean Ellingham 2013/01/16 9:13 am • Reply
     
     Unless I’m reading the RFCs wrongly (or misinterpreting your post), saying
     that all reserved characters must always be encoded is incorrect. For
     example, in an HTTP URL (at least as far as I can tell), the reserved
     characters “;”, “:”, “@”, “&” and “=” are perfectly acceptable in the path
     and query string without being encoded – see page 17 of RFC1738.
     
     * Jeff Starr 2013/01/16 2:56 pm • Post Author • Reply
       
       > saying that all reserved characters must always be encoded is
       > incorrect.
       
       I don’t think I say that anywhere in the article, so if there is some
       confusion please let me know so I may clarify.
       
       Also, page 17 of RFC1738 refers to “ip based protocols”, which use the
       reserved characters according to their specifically defined reserved
       purpose. At least, that’s how I currently understand the RFC, please
       advise if I am misguided.
       
       * Sean Ellingham 2013/01/16 3:46 pm
         
         True, it’s not said directly, but when I read the article that was the
         impression I received. I believe the culprit is the quick reference
         chart, which says encoding is required for everything except safe
         characters.
         
         The particular part of page 17 of RFC1738 I was referring to was this
         section:
         
         ; HTTP
         
         httpurl = "http://" hostport [ "/" hpath [ "?" search ]]
         hpath = hsegment *[ "/" hsegment ]
         hsegment = *[ uchar | ";" | ":" | "@" | "&" | "=" ]
         search = *[ uchar | ";" | ":" | "@" | "&" | "=" ]
         
         My understanding of that (with the definitions around it) was that
         those five reserved characters were allowed as is in the path and query
         string. Then again, that’s just my interpretation – I’m not making any
         claims that I’m an expert in this area, so I’ll gladly defer to better
         judgement. These RFCs aren’t exactly the easiest things to get your
         head around!
       
         
       * Jeff Starr 2013/01/16 4:13 pm • Post Author
         
         Thanks for clarifying, I’ve updated the chart with a note about
         encoding of reserved characters.
         
         For RFC, page 3 states:
         
         “Thus, only alphanumerics, the special characters “$-_.+!*'(),”, and
         reserved characters used for their reserved purposes may be used
         unencoded within a URL.”
         
         I think the information you reference on p17 is showing that reserved
         characters are acceptable if used according to definition (i.e., p3).
         
         But you are correct that the RFCs are not the easiest thing to
         understand. And like you, I’m no expert in this area so if anything is
         incorrect I’ll be glad to revise accordingly.
       
         
       * Sean Ellingham 2013/01/16 4:48 pm
         
         Hmm, I obviously missed that line on page 3 – that sentence does seem
         fairly conclusive. What is confusing me though is that the definitions
         for the schemes listed on pages 17 onwards seem to conflict with that,
         by implying that the reserved characters can potentially be used in
         certain other parts of a URL. Using HTTP as an example, if the
         definitions are expanded, it seems to say that a path can comprise
         multiple “/” delimited sections, where a section comprises any number
         of: unreserved characters, escape sequences, or the “:”, “;”, “@”, “&”
         or “=” characters – it is because these characters are explicitly
         listed, combined with the following statement on page 8, that I believe
         them to be valid.
         
         Within the and components, “/”, “;”, “?” are
         reserved. The “/” character may be used within HTTP to designate a
         hierarchical structure.
         
         However, it is worth considering that (if my interpretation is correct)
         whilst RFC1738 seems to allow unencoded “&” and “=” in the query
         string, we would expect these to be ‘reserved’ as we are used to their
         use in application/x-www-form-urlencoded style form submissions –
         although I don’t know where that encoding of key/value pairs is
         specified (I believe it might be in the HTML specification, although
         I’m not sure).
       
         
       * Sean Ellingham 2013/01/16 4:51 pm
         
         Oops, the quote from page 8 got eaten as I forgot to replace the angle
         brackets with the HTML entities – need to get to bed! Here’s what it
         should have said:
         
         “Within the <path> and <searchpart> components, “/”, “;”, “?” are
         reserved. The “/” character may be used within HTTP to designate a
         hierarchical structure.”
       
         
       
     
 7.  Riva 2013/01/27 12:23 pm • Reply
     
     Really liked what you had to say in your post, (Please) Stop Using Unsafe
     Characters in URLs : Perishable Press, thanks for the good read!
     — Riva
     
     http://www.terrazoa.com

     
 8.  P. Don 2013/01/31 10:15 am • Reply
     
     I checked RFC 1738 since I was having a problem with commas in request
     strings triggering 403s using the 5G .htaccess.
     
     It appears that commas are fine, defined as “extra” characters (see the BNF
     section), one of the allowable sets of unreserved characters (alpha | digit
     | safe | extra). There is a comma in your initial list of safe characters
     in the OP, but it’s ambiguous whether it’s in the list or just punctuation.
     The comma does not seem to belong in the Reserved list.

     
 9.  Tim 2013/04/16 7:52 am • Reply
     
     very interesting. I recently developed a search interface that included
     arrays of checkboxes and used the get method so that searches could be
     saved. I wonder if my technique is using unsafe characters or if this is
     acceptable:
     
     the options[] field is added as a url parameter like this:
     
     ?options%5B%5D=large&options%5B%5D=medium

     
 10. G. C. 2022/05/31 11:39 am • Reply
     
     Just so you are aware:
     
     Classifying sub-delims as “unsafe” is inaccurate.
     
     Sub-delimiters are a class for which frameworks and projects that involve
     URL parsing algorithms are the target. Specifically, from rfc 3986:
     
     A subset of the reserved characters (gen-delims) is used as delimiters of
     the generic URI components described in Section 3. A component’s ABNF
     syntax rule will not use the reserved or gen-delims rule names directly;
     instead, each tax rule lists the characters allowed within that component
     (i.e., not delimiting it), and any of those characters that are also in the
     reserved set are “reserved” for use as subcomponent delimiters within the
     component.
     
     Only the most common subcomponents are defined by this specification; other
     subcomponents may be defined by a URI scheme’s specification, or by the
     implementation-specific syntax of a URI’s dereferencing algorithm, provided
     that such subcomponents are delimited by characters in the reserved set
     allowed within that component.
     
     URI producing applications should percent-encode data octets that
     correspond to characters in the reserved set unless these characters are
     specifically allowed by the URI scheme to represent data in that component.
     If a reserved character is found in a URI component and no delimiting role
     is known for that character, then it must be interpreted as representing
     the data octet corresponding to that character’s encoding in US-ASCII.
     
     Simply they are safe for their intended use, as delimiters, and should
     otherwise be percent encoded.
     
     For framework and library devs like me the distinction is kind of
     important.

     
 11. Joe 2022/10/09 12:22 am • Reply
     
     First; you should understand that “unsafe characters” no longer exists in
     the current standard as a character class, since you mention it. However
     you then go on to say it is still useful — no, that’s incorrect. It is now
     wrong information.
     
     RFC 1738 is not just obsolete, it is deprecated.
     
     When you echo 1738’s verbiage about gen-delims and sub-delims, you are
     repeating the very misconception which caused the standard to be revised.
     
     {, }, |, \, ^, ~, [, ]
     These are not unsafe characters.
     
     Example: It is safe to use [ ] { } in URLs
     It is non-standard to use them in resource names.
     If you are writing a URL dereferencing algorithm, or USING such an
     algorithm, these characters are reserved FOR YOU
     
     gen-delims = “:” “[” / “]” “@”
     
     sub-delims = “!” / “$” / “&” / “‘” / “(” / “)”
     / “*” / “+” / “,” / “;” / “=”
     
     During the host portions and query portion, rules are stricter, however
     during the path component
     []@:;,=()!*+
     
     Each of these characters are reserved for URL systems to create semantics
     with, so that you may know no resource names are conflicting with your DSL
     syntax.

     


LEAVE A REPLY CANCEL

Name and email required. Email kept private. Basic markup allowed. Please wrap
any small/single-line code snippets with <code> tags. Wrap any long/multi-line
snippets with <pre><code> tags. For more info, check out the Comment Policy and
Privacy Policy.

Subscribe to comments on this post

Name
Email
Website
Comment



Welcome
Perishable Press is operated by Jeff Starr, a professional web developer and
book author with two decades of experience. Here you will find posts about web
development, WordPress, security, and more »
Digging Into WordPress: Take your WordPress skills to the next level.
Thoughts
Upgraded iMac to Ventura. Disabled "unsend mail" feature and found some (now)
hidden wallpaper settings. Overall smooth upgrade.
( $this ) is bloat. ($this) is better.
The Legend of Zelda: Tears of the Kingdom coming May 12, 2023. Absolutely
pumped.
Favorite thing for breakfast is a tall glass of cold water. Hits the spot every
time.
Fall is my favorite season :)
Still a few days left before “Unlimited” pro licenses are no longer available.
Getting back into it after a nice mini vacation. Time to ramp up and get busy.
+ More thoughts »
Newsletter
Get news, updates, deals & tips via email.
Enter your email
Email kept private. Easy unsubscribe anytime.
Topics
 * WordPress
 * Security
 * .htaccess
 * JavaScript
 * HTML
 * PHP
 * CSS
 * SEO
 * more »

 * websites
 * plugins
 * blacklist
 * apache
 * tutorials
 * code
 * ux
 * mod_rewrite
 * optimization
 * design
 * links
 * spam
 * markup
 * server
 * hacks
 * more »

Perishable Press Newsletter
Get news, updates, deals & tips via email.
Enter your email
Your email will remain private. Easy unsubscribe anytime.
Find me on the social medias
 * Twitter
 * YouTube
 * LinkedIn
 * Tumblr
 * Facebook
 * Instagram
 * WordPress

Around the site
 * Online Dev Tools
 * About Perishable Press
 * Perishable Press Archives
 * Contact Perishable Press
 * Welcome to Dungeon!

WordPress help
 * Wizard’s SQL Recipes (eBook)
 * The Tao of WordPress (eBook)
 * Digging Into WordPress (eBook)
 * Develop WordPress themes (eBook)
 * Develop WordPress plugins (video tutorials)
 * WordPress on shared hosting (video tutorials)

Favorite projects
 * .htaccess made easy
 * Code Snippets
 * Blackhole Pro
 * BBQ Pro
 * USP Pro

© 2004–2022 Perishable Press • Yes Theme by Monzilla Media • Built w/ shapeSpace
• Sitemap • Policy • RSS • John 3:16