ruby中的双等号==问题详解
前两天在写代码的时候,突然收到警告说项目代码中存在XSS漏洞,遂立即根据报告的URL排查页面代码,虽然很快就修复了,而且同样问题的讨论两年前就有了,一般来说相对有经验的同学也应该都知道这个点,但是还是觉得有必要写出来,再次提醒一下其他小伙伴,避免踩坑。
问题根源
其中,在找到的漏洞出现的地方,都存在类似以下这样的slim代码:
inputclass='xxx'value==params[:account]
问题就出在双等号==上,因为在slim跟ERB模板(其他模板比如HAML之类的就不清楚了)中,双等号其实是Rails的raw这个helper方法的缩写
Toinsertsomethingverbatimusetherawhelperratherthancallinghtml_safe: <%=raw@cms.current_template%><%#inserts@cms.current_templateasis%> or,equivalently,use<%==: <%==@cms.current_template%><%#inserts@cms.current_templateasis%>
也就是说上面的代码等同于:
inputclass='xxx'value=raw(params[:account])
其中raw方法在Rails文档中的解释是这样子的:
Thismethodoutputswithoutescapingastring.Sinceescapingtagsisnowdefault,thiscanbeusedwhenyoudon'twantRailstoautomaticallyescapetags.Thisisnotrecommendedifthedataiscomingfromtheuser'sinput.
大概意思就是,这个方法将会跳过对传入的字符串进行标签过滤以及其他处理,直接将字符串输出到HTML中。
所以到现在原因就很清晰了,因为不小心在代码里多加了一个等号,变成了双等号,导致将会直接把用户的输入输出到待渲染的HTML中,在不自知的情况下留下了XSS漏洞。于是乎,修复方案仅需去掉一个等号即可:
inputclass='xxx'value=params[:account]
这样,Rails就能继续自动过滤输入的:account的参数并且自动过滤恶意内容了。
raw、String#html_safe以及<%==%>
在查看raw方法的文档时,顺便看了其源码,极其简单,只有一行:
#Fileactionview/lib/action_view/helpers/output_safety_helper.rb,line16 defraw(stringish) stringish.to_s.html_safe end
raw只是先确保将stringish参数转化为字符串,然后调用了String#html_safe方法而已。而且在String#html_safe的文档中,同样反复强调慎重使用这两个方法:
ItwillbeinsertedintoHTMLwithnoadditionalescapingperformed.Itisyourresponsibiltytoensurethatthestringcontainsnomaliciouscontent.Thismethodisequivalenttotherawhelperinviews.
所以,可以总结一下,以下三种写法的代码都是等价的,都是不安全的:
inputclass='xxx'value==params[:account] inputclass='xxx'value=raw(params[:account]) inputclass='xxx'value=params[:account].html_safe
那在切实需要输出包含HTML内容比如富文本编辑器编辑的内容时,如何保证安全?
方案很简单,只需要使用文档中推荐的sanitizehelper方法:
Itisrecommendedthatyouusesanitizeinsteadofthismethod(html_safe). (#sanitize)SanitizesHTMLinput,strippingalltagsandattributesthataren'twhitelisted.
或者使用一些其他第三方的gem用来做过滤处理。
总结
- 不要使用双等号缩写的方式,以避免其他人(比如项目里的Rails新手)在不了解的情况下照着滥用;
- 尽可能不用rawhelper或者String#html_safe方法,尽可能使用#sanitize;
- 多借助工具进行自动扫描,比如brakeman,能够快速高效检测出包括XSS漏洞在内的多种安全隐患。