通过Javascript输出JSON内容时,我应该在服务器端还是客户端转义HTML?

ale*_*exw 13 javascript xss json escaping

我有一个应用程序,它包含一个用PHP编写的服务器端REST API,以及一些客户端Javascript,它使用这个API并使用它生成的JSON来呈现页面.所以,一个非常典型的设置.

REST API提供的数据是"不可信的",因为它从数据库中获取用户提供的内容.因此,例如,它可能会获取如下内容:

{
    "message": "<script>alert("Gotcha!")</script>"
}
Run Code Online (Sandbox Code Playgroud)

显然,如果我的客户端代码直接将其呈现到页面的DOM中,我就创建了一个XSS漏洞.因此,此内容需要首先进行HTML转义.

问题是,在输出不受信任的内容时,我应该逃避服务器端或客户端的内容吗?即,我的API应该返回原始内容,然后使客户端Javascript代码有责任转义特殊字符,或者我的API应该返回"安全"内容:

{
    "message": "&lt;script&gt;alert(&#039;Gotcha!&#039;);&lt;\/script&gt;"
}
Run Code Online (Sandbox Code Playgroud)

那已经逃脱了?

一方面,似乎客户端不应该担心来自我的服务器的不安全数据.另一方面,有人可能会争辩说,当我们确切地知道如何使用数据时,应该在最后一刻尽可能地转义输出.

哪种方法是正确的?

注意:有很多关于处理输入的问题,是的,我知道客户端代码总是可以被操作.这个问题是关于输出数据我的服务器,可能不值得信赖.

更新:我调查了其他人在做什么,似乎有些REST API倾向于发送"不安全"的JSON.Gitter的API实际上发送了两个,这是一个有趣的想法:

[
    {
        "id":"560ab5d0081f3a9c044d709e",
        "text":"testing the API: <script>alert('hey')</script>",
        "html":"testing the API: &lt;script&gt;alert(&#39;hey&#39;)&lt;/script&gt;",
        "sent":"2015-09-29T16:01:19.999Z",
        "fromUser":{
            ...
        },"unread":false,
        "readBy":0,
        "urls":[],
        "mentions":[],
        "issues":[],
        "meta":[],
        "v":1
    }
]
Run Code Online (Sandbox Code Playgroud)

请注意,他们在text密钥中发送原始内容,然后在密钥中发送HTML转义版本html.IMO,这不是一个坏主意.

我已经接受了答案,但我不相信这是一个干枯的问题.我想鼓励进一步讨论这个主题.

The*_*est 16

仅在客户端逃脱.

在客户端进行转义的原因是安全性:服务器的输出是客户端的输入,因此客户端不应该信任它.如果您认为输入已经被转义,那么您可能会通过例如恶意反向代理打开客户端攻击.这与您应该始终在服务器端验证输入的原因没有太大区别,即使您还包括客户端验证.

不在服务器端逃避的原因是关注点分离:服务器不应该假设客户端打算将数据呈现为HTML.服务器的输出应尽可能与媒体无关(当然,考虑到JSON和数据结构的约束),以便客户端可以最轻松地将其转换为所需的任何格式.