XSS 与路径穿越 · 网络安全入门
一个评论框,怎么能在别人的浏览器里运行代码?
课程目录为什么需要它
网站时时刻刻都在把一个人的文字展示给别人看:评论、昵称、文件名。如果这些文字被当成代码或路径来处理,一个访客就能攻击所有其他访客,甚至读到服务器上的文件。这一课讲两个经典案例:跨站脚本(XSS)和路径穿越。
直觉理解
浏览器把页面当作 HTML 来读。如果一条评论里有 <script>...</script>,而你把它原样放进页面,浏览器就会执行它:在每个访客的浏览器里,带着他们的登录 Cookie 执行。
修复办法是输出时转义:把 < 变成 <,> 变成 >,让浏览器把这些字符显示出来,而不是照着执行。Python 的 html.escape 就是干这个的。
文件名也有同样的问题。../ 表示「往上一级目录」,所以 ../../etc/passwd 能爬出你的上传目录。先把路径规范化(把每个 .. 都算掉),再检查它是不是还在允许的目录里。
两种情况都一样:优先用允许清单(只接受你预期的东西),而不是阻止清单(只拒绝你想到的东西)。
定义
跨站脚本(XSS)
An attack where text supplied by a user is shown as HTML, so a script inside it runs in other users' browsers.一种攻击:用户提供的文字被当成 HTML 显示,里面的脚本就在其他用户的浏览器里运行。
路径穿越
An attack where a file name such as `../../secret` makes a program open a file outside the folder it meant to use.一种攻击:像 `../../secret` 这样的文件名,让程序打开了原本目录之外的文件。
示例
输出时转义
动手试试第一行是粗心的页面会生成的内容;第二行放进 HTML 是安全的。
import html
comment = '<script>steal(document.cookie)</script>'
print("<p>" + comment + "</p>")
print("<p>" + html.escape(comment) + "</p>")
print(html.escape('Tom & "Jerry"'))- L3原样放进去:浏览器会执行 steal(...)。
- L4转义之后:浏览器只显示文字,不执行任何东西。
- L5
&和引号也会被转义,放进属性里也安全。
爬出目录
动手试试os.path.normpath 会把每个 .. 都算掉。然后检查结果是否还在 BASE 里面。
import os
BASE = "/srv/files"
def resolve(name):
return os.path.normpath(os.path.join(BASE, name))
for name in ["report.pdf", "../../etc/passwd", "img/../logo.png"]:
path = resolve(name)
print(path, path.startswith(BASE + "/"))- L5把目录和文件名拼起来,再把点号算掉。
- L9正常文件留在里面:True。
/srv/files/report.pdf True - L9
../../爬到了最顶层:检查拦住了它。/etc/passwd False - L9
..只要没出去就没问题。/srv/files/logo.png True
常见错误
只靠阻止清单
删掉 <script> 远远不够:<img src=x onerror=...> 也能执行代码,类似的标签还有很多。输出时全部转义,比去找危险词靠谱。
前缀检查少了斜杠
path.startswith("/srv/files") 也会放过 /srv/files_backup/secret。要检查目录名后面再加 /。
小测验
1. 这段代码会输出什么?
import html
print(html.escape("<b>hi</b>"))查看答案
答案:A
每个 < 都变成 <,每个 > 都变成 >。浏览器会把它显示成字面上的 <b>hi</b>。
2. 注册表单要填用户名。下面哪条规则是允许清单?
查看答案
答案:B
允许清单精确描述了什么会被接受。其他一切,包括没人想到的攻击,都会被拒绝。
动手练习
3 道练习,分三层:先预测程序的输出,再按新需求改程序,最后从零写一个。代码在浏览器里运行,提交马上判题。
- 预测输出它指向哪里?
准确写出这段程序的输出。
- 改需求转义评论
render(name, text)把两个值直接拼进去,生成一条评论的 HTML。修改它,让名字和内容都用html.escape转义。 - 从零写安全的文件路径
给下载页面写一个函数
safe_path(name)。把name拼到BASE后面并规范化,然后:- 如果它在
BASE里面(以BASE + "/"开头),返回完整路径 - 否则返回
None
- 如果它在
本课术语
| 术语 | 中文 | 英文定义 |
|---|---|---|
| Cross-site scripting (XSS) | 跨站脚本(XSS) | Running an attacker's script in other users' browsers through unescaped text. |
| Escaping | 转义 | Replacing special characters such as < with safe codes such as <. |
| Path traversal | 路径穿越 | Using ../ in a file name to reach files outside the intended folder. |
| Normalise a path | 规范化路径 | Resolve . and .. so the path shows where it really points. |