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

推荐订阅源

博客园 - 【当耐特】
WordPress大学
WordPress大学
T
The Exploit Database - CXSecurity.com
博客园_首页
MyScale Blog
MyScale Blog
The Cloudflare Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
美团技术团队
Stack Overflow Blog
Stack Overflow Blog
博客园 - 聂微东
M
MIT News - Artificial intelligence
Microsoft Security Blog
Microsoft Security Blog
F
Full Disclosure
V
V2EX
博客园 - Franky
博客园 - 三生石上(FineUI控件)
Hugging Face - Blog
Hugging Face - Blog
P
Proofpoint News Feed
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
SecWiki News
SecWiki News
N
Netflix TechBlog - Medium
S
Secure Thoughts
酷 壳 – CoolShell
酷 壳 – CoolShell
Hacker News: Ask HN
Hacker News: Ask HN
爱范儿
爱范儿
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Webroot Blog
Webroot Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Martin Fowler
Martin Fowler
PCI Perspectives
PCI Perspectives
S
Security @ Cisco Blogs
Recorded Future
Recorded Future
Help Net Security
Help Net Security
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
AI
AI
Microsoft Azure Blog
Microsoft Azure Blog
K
Kaspersky official blog
G
GRAHAM CLULEY
H
Hackread – Cybersecurity News, Data Breaches, AI and More
C
CERT Recently Published Vulnerability Notes
U
Unit 42
T
Tor Project blog
Cloudbric
Cloudbric
Hacker News - Newest:
Hacker News - Newest: "LLM"
MongoDB | Blog
MongoDB | Blog
GbyAI
GbyAI
T
The Blog of Author Tim Ferriss
Security Latest
Security Latest
N
News and Events Feed by Topic
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO

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>'