CTFCryto01-URL编码

URL编码

  • URL编码,也称为百分号编码,是一种用于在URL(统一资源定位符)中传输特殊字符的编码方式
  • 当 URL 路径或者查询参数中,带有中文或者特殊字符的时候,就需要对 URL 进行编码(采用十六进制编码格式)。URL 编码的原则是使用安全字符去表示那些不安全的字符
  • 安全字符:指的是没有特殊用途或者特殊意义的字符

应用场景

  • 浏览器地址栏:用户在输入含有特殊字符的URL时,浏览器会自动进行URL编码
  • 表单数据提交:通过GET或POST方法提交表单时,数据中的特殊字符会被编码,以确保传输的正确性
  • API请求:在RESTful API中,URL编码用于传递参数,确保参数值中包含的特殊字符不会破坏URL结构
  • 文件传输:在文件名中包含特殊字符时,URL编码用于正确传输文件路径。

URL结构分解

  • URL 中规定了一些具有特殊意义的字符,常被用来分隔两个不同的 URL 组件,这些字符被称为保留字符
    • 冒号:用于分隔协议和主机组件,斜杠用于分隔主机和路径
    • ?:用于分隔路径和查询参数等
    • =:用于表示查询参数中的键值对
    • &:用于分隔查询多个键值对
    • 其余常用的保留字符有:/ . … # @ $ + ; %
  • http://example.com:8080/path/to/index.php?param1=value1&param2=value2#section
    • 协议:http://(或https://)
    • 域名:example.com
    • 端口::8080(默认HTTP端口80、HTTPS端口443可省略)
    • 路径:/path/to/index.php(服务器上的文件路径)
    • 查询参数(查询字符串):?param1=value1&param2=value2
      • 路径和查询字符串之间使用问号?隔开
    • 片段标识:#section(页面内锚点)

编码原理

  • 使用百分号(%)后跟随两个十六进制数字来表示该字符的ASCII码。通过这种方式,任何字符都可以被安全地包含在URL中

编码规则

  • 保留字符编码:将所有保留字符转换为其ASCII码对应的百分号编码。例如,空格( )的ASCII码是32,对应的十六进制是20,因此空格在URL中表示为%20
  • 非ASCII字符编码:对于URL中包含的非ASCII字符(如中文字符),首先将其转换为UTF-8编码的字节序列,然后将每个字节转换为百分号编码。例如,中文字符“你”的UTF-8编码为E4 BD A0,对应的URL编码为%E4%BD%A0
  • 非保留字符不编码:非保留字符可以直接使用,不需要进行编码

哪些字符需要编码

  • URL 之所以需要编码,是因为 URL 中的某些字符会引起歧义,比如 URL 查询参数中包含了”&”或者”%”就会造成服务器解析错误
  • URL 的编码格式采用的是 ASCII 码而非 Unicode 格式,这表明 URL 中不允许包含任何非 ASCII 字符(比如中文),否则就会造成 URL 解析错误。
  • URL 编码协议规定(RFC3986 协议):URL 中只允许使用 ASCII 字符集可以显示的字符(安全字符/非保留字符)
    • 英文字母、数字、和- _ . ~这 6 个特殊字符
    • 当在 URL 中使用不属于 ASCII 字符集的字符时,就要使用特殊的符号对该字符进行编码,比如空格需要用%20来表示
  • 除了无法显示的字符需要编码外,还需要对 URL 中的部分保留字符和不安全字符进行编码
    • 示例:!, *, ', (, ), ;, :, @, &, =, +, $, ,, /, ?, #, [, ], <, >, ", ", {, }, |, , ^等

URL特殊字符编码

字符 含义 十六进制值编码
+ URL 中 + 号表示空格 %2B
空格 URL中的空格可以编码为 + 号或者 %20 %20
/ 分隔目录和子目录 %2F
? 分隔实际的 URL 和参数 %3F
% 指定特殊字符 %25
# 表示书签 %23
& URL 中指定的参数间的分隔符 %26
= URL 中指定参数的值 %3D

Python实现编码与解码

  • Python 的标准库urllib.parse模块中提供了用来编码和解码的方法,分别是 urlencode() 与 unquote() 方法。
    • urlencode():该方法实现了对 url 地址的编码操作
    • quote():该方法实现了对 url 地址的编码操作
    • unquote():该方法将编码后的 url 地址进行还原,被称为解码
    • 注意:quote() 只能对字符串编码,而 urlencode() 可以直接对查询字符串字典进行编码
#导入parse模块
from urllib import parse
#构建查询字符串字典
query_string = {
'wd' : '爬虫'
}
#调用parse模块的urlencode()进行编码
result = parse.urlencode(query_string)
#使用format函数格式化字符串,拼接url地址
url = 'http://www.baidu.com/s?{}'.format(result)
print(url)

#注意url的书写格式,和 urlencode存在不同
url = 'http://www.baidu.com/s?wd={}'
word = input('请输入要搜索的内容:')
#quote()只能对字符串进行编码
query_string = parse.quote(word)
print(url.format(query_string))

urllib.parse.urlencode({'key':'value'}) #字典
urllib.parse.quote(string) #字符串

string = '%E7%88%AC%E8%99%AB'
result = parse.unquote(string)
print(result)

URL解码

浏览器解码逻辑详解

  • 自动解码的触发条件:
    • 仅对合法编码序列解码:若输入形如%XX(X为十六进制字符),浏览器会尝试解码。
    • 非编码字符保留原样:例如%zz(非法编码)会被直接发送。
  • 双重编码的递归解码:
    • 浏览器仅解码一次:不会递归解码多次。
    • 输入%2525 → 解码为%25,不会继续解码为%。
  • 安全字符的特殊处理
    • 部分浏览器优化:对某些安全字符(如字母)的编码可能自动解码
    • 输入%41 → 发送时可能直接转为A
  • 利用:
    • 绕过路径遍历过滤
    • XSS绕过关键字过滤

浏览器解码策略

浏览器 双重编码处理 安全字符编码处理
Chrome 解码一次(发送单层编码) 可能自动解码为明文
Firefox 解码一次(发送单层编码) 保留编码形式
Safari 同Chrome 同Chrome
Edge 同Chrome 同Chrome

posted @ 2025-02-14 22:36  micryfotctf  阅读(2)  评论(0编辑  收藏  举报