从我看过的所有内容来看,在用户输入内容上转义html(为了防止XSS)的惯例似乎是在渲染内容时执行此操作。大多数模板语言似乎默认都是这样做的,我遇到像this stackoverflow answer这样的东西,认为这个逻辑是表示层的工作。
所以我的问题是,为什么会这样呢?对我来说,在输入(即表单或模型验证)上逃避似乎更干净,因此您可以假设数据库中的任何内容都可以安全地显示在页面上,原因如下:
各种输出格式 - 对于现代网络应用程序,您可能正在使用服务器端html呈现,使用ajax / JSON的javascript Web应用程序和接收JSON的移动应用程序(可能或可能没有一些webview,可能是javascript应用程序或服务器呈现的HTML)。所以你必须处理遍布各地的html。但是输入将总是在保存到db之前被实例化为模型(并经过验证),并且您的模型都可以从相同的基类继承。
你必须小心输入以防止代码注入攻击(授予这通常是抽象到ORM或db游标,但仍然),所以为什么不担心html在这里逃避所以你不要我不得不担心与输出有关的任何安全问题吗?
我很想听听关于为什么html在页面渲染上转义是首选的论点
答案 0 :(得分:33)
除了已经写过的内容:
正是因为您有各种输出格式,并且无法保证所有格式都需要HTML转义。如果您通过JSON API提供数据,则无法了解客户端是否需要HTML页面或文本输出(例如电子邮件)。你为什么要强迫你的客户忘记“Jack & Jill
”获得“Jack& Jill”?
默认情况下,您的数据已损坏。
当有人搜索'amp'的关键字时,他们会获得“Jack& Jill”。为什么?因为您的数据已损坏。
假设其中一个输入是一个网址:http://example.com/?x=1&y=2
。您要解析此URL,并提取y
参数(如果存在)。这种方法无声地失败,因为您的网址已损坏为http://example.com/?x=1&y=2
。
这只是一个错误的层 - HTML相关的东西不应该与原始的HTTP处理混在一起。数据库不应存储与一种可能的输出格式相关的内容。
XSS和SQL注入不是唯一的安全问题,您处理的每个输出都存在问题 - 例如文件系统(认为像'.php'这样的扩展导致Web服务器执行代码)和SMTP(想想换行符),以及任意数量的其他人。认为你可以“处理输入的安全性然后忘记它”会降低安全性。相反,您应该将转义委托给不信任其输入数据的特定后端。
您不应该在“遍布各处”进行HTML转义。对于需要它的每个输出,你应该完全一次 - 就像任何后端的转义一样。对于SQL,你应该做SQL转义一次,同样适用于SMTP等。通常,你不会做任何转义 - 你将使用一个库为你处理它。
如果您使用合理的框架/库,这并不难。我从不在我的网络应用程序中手动应用SQL / SMTP / HTML转义,而且我从未遇到过XSS / SQL注入漏洞。如果您构建网页的方法要求您记住应用转义或最终导致漏洞,那么您做错了。
在表单/ http输入级别执行转义并不能确保安全,因为没有任何保证数据不会从其他路由进入您的数据库或系统。您必须手动确保系统的所有输入都应用HTML转义。
您可能会说您没有其他输入,但如果您的系统增长会怎么样?回去改变你的决定往往为时已晚,因为此时你已经获得了大量数据,并且可能与外部接口具有兼容性,例如:需要担心的公共API,它们都希望数据被HTML转义。
即使是系统的网络输入也不安全,因为通常你会应用另一层编码,例如:您可能需要在某些入口点使用base64编码输入。您的自动HTML转义将错过该数据中编码的任何HTML。因此,您必须再次执行HTML转义 ,并记住这样做,并记录您已完成的工作。
我在这里扩展了这些:http://lukeplant.me.uk/blog/posts/why-escape-on-input-is-a-bad-idea/
答案 1 :(得分:20)
不要将输出的卫生与验证混淆。
虽然<script>alert(1);</script>
是一个完全有效的用户名,但在网站上显示前必须先将其转义。
是的,有“表示逻辑”这样的东西,它与“域业务逻辑”无关。表示逻辑是表示层处理的内容。特别是View
个实例。在一个写得很好的MVC中, Views 是完整的对象(与RoR试图告诉你的内容相反),当在Web上下文中应用时,它会兼顾多个模板。
不同的输出格式应由不同的视图处理。管理HTML,XML,JSON和其他格式的规则和限制在每种情况下都是不同的。
您始终需要存储原始输入(如果您不使用预准备语句,请进行清理以避免注入),因为某些人可能需要在某些时候对其进行编辑。
存储原始和xss安全的“公共”版本是浪费。如果你想存储已清理的输出,因为每次都需要太多的资源来清理它,那么你已经在错误的树上撒尿了。当您使用缓存而不是污染数据库时,就是这种情况。