惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Vercel News
Vercel News
T
Tor Project blog
博客园_首页
F
Fortinet All Blogs
V
V2EX
雷峰网
雷峰网
Microsoft Azure Blog
Microsoft Azure Blog
Y
Y Combinator Blog
博客园 - 【当耐特】
Jina AI
Jina AI
Google DeepMind News
Google DeepMind News
人人都是产品经理
人人都是产品经理
B
Blog RSS Feed
Engineering at Meta
Engineering at Meta
Spread Privacy
Spread Privacy
C
Cyber Attacks, Cyber Crime and Cyber Security
The Cloudflare Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Apple Machine Learning Research
Apple Machine Learning Research
V2EX - 技术
V2EX - 技术
Latest news
Latest news
L
LINUX DO - 最新话题
IT之家
IT之家
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
博客园 - 叶小钗
博客园 - Franky
I
InfoQ
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
量子位
博客园 - 聂微东
MyScale Blog
MyScale Blog
S
Security @ Cisco Blogs
Hacker News - Newest:
Hacker News - Newest: "LLM"
小众软件
小众软件
S
Secure Thoughts
D
Darknet – Hacking Tools, Hacker News & Cyber Security
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
N
News | PayPal Newsroom
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
B
Blog
Google DeepMind News
Google DeepMind News
J
Java Code Geeks
有赞技术团队
有赞技术团队
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
Vulnerabilities – Threatpost
T
Tailwind CSS Blog
L
Lohrmann on Cybersecurity
T
Troy Hunt's Blog
美团技术团队

Sophie Alpert

There are no lossless transformations of natural-language text Deconstructing “services” I don’t want AI agents controlling my laptop Materialized views are obviously useful TODOs aren’t for doing Everyone is wrong about that Slack flowchart Hire me to empower and upskill your eng team How React Changed the Web Forever: A Documentary Fast and maintainable patterns for fetching from a database React Conf: “Building a Custom React Renderer” Why review code? Metrics by proxy Yak shaving and fixing Voice React Conf: “React Today and Tomorrow” Why we host conference talk dry runs React Podcast: Inside React Type errors with inference need stacks Observable programming React 16: an API-compatible rewrite Hi, I’m trans. Initializing on the main thread using dispatch_once A near-perfect oninput shim for IE 8 and 9 Using React to speed up the Khan Academy question editor What I did at Khan Academy, 2012 edition Rolling back to an old revision in Mercurial (like git reset)
Preventing XSS attacks when embedding JSON in HTML
Sophie Alpert · 2012-08-03 · via Sophie Alpert

At Khan Academy, we recently took the time to go through our 200+ Jinja2 templates and turn on autoescape to reduce the likelihood of falling prey to an XSS attack. This gave us an excuse to audit all of our pages for injection holes: Here’s one hole Jamie Wong pointed out that you might run into when using Ruby’s .to_json or Python’s json.dumps.

Suppose you’re writing a web app and you want to pass down an untrusted string username from the server to your client-side JavaScript code. If you create a Rails template that looks like the following, are you safe from XSS attacks?

<script>
    Profile.init({
        username: <%=raw username.to_json %>
    });
</script>

(Here we use raw because we don’t want HTML entities in the JavaScript code.) Though we’re not exactly including unescaped HTML, there’s a subtle injection bug here that has to do with how browsers parse <script> tags.

The HTML spec says:

Markup and entities must be treated as raw text and passed to the application as is. The first occurrence of the character sequence ”</” (end-tag open delimiter) is treated as terminating the end of the element’s content.

Where’s the security hole? Consider if username was set to:

</script><script>evil()</script>

This will give us the following HTML:

<script>
    Profile.init({
        username: "</script><script>evil()</script>"
    });
</script>

Though the first <script> tag doesn’t contain valid JavaScript, it doesn’t matter — the second script tag will be read and so evil() will be executed.

So what’s the fix? In addition to the common character escapes \", \\, \b, \f, \n, \r, \t, and \uXXXX, the JSON spec states that \/ will be interpreted as a literal slash. That is, in a JSON string literal, you can add a backslash before a slash character without otherwise changing the string. To prevent against this hole, you should replace every occurrence of </ in your JSON with <\/ so that the <script> tag remains open. (The characters < and / are valid only within a string literal so the replacement can’t affect anything else.)

Regardless of which language you use, you’ll probably want to make a helper function to encapsulate this logic:

# Ruby
def jsonify(obj)
  obj.to_json.gsub('</', '<\/')
end
# Python
def jsonify(obj):
    return json.dumps(obj).replace('</', '<\\/')

As long as you always remember to use the jsonify wrapper instead of the built-in JSON serialization, you should be safe from this particular attack.


Update (2018/03/10): Replacing </ with <\/ works for JSON but isn’t necessarily correct when run over arbitrary JavaScript. Imagine the (nonsensical but valid) code let x = foo < /bar/;. When minified, you’ll end up with </ adjacent but since the / starts a regex, it isn’t correct to add a backslash.

Instead, Erling Ellingsen and I concluded that escaping the “s” in script is a safe, general solution, since the same escaping (\u0073) is valid in all the places a letter can appear: strings, regexes, and JS identifiers. The following should work:

# Ruby
def scriptify(code)
  escaped = code.gsub(/(?<=<\/)s(?=cript)/i) { |m| "\\u%04x" % m.ord }
  "<script>#{escaped}</script>"
end
# Python
def scriptify(code):
    escaped = re.sub(
        r'(?<=</)s(?=cript)',
        lambda m: f'\\u{ord(m.group(0)):04x}',
        code, flags=re.I)
    return f'<script>{escaped}</script>'