安全 别用 raw 和 html_safe

Rei · 发布于 2014年1月05日 · 最后由 rennyallen 回复于 2017年1月13日 · 15431 次阅读
1
本帖已被设为精华帖!

刚才修复了 Ruby China 一处潜在漏洞:

https://github.com/ruby-china/ruby-china/commit/78f7cb4a73fe5972a534e01a2ef7b7353ef5fe00

起因都是 raw,它和 html_safe 是同义的。我发现很多人都误解了这两个 helper 的用法,再强调一次它的意思是:

我要裸奔!

Rails 框架本身做了很多安全措施,在默认情况下,template 里的所有字符串都会被过滤:

<%= danger_string %> <!-- 安全 -->

这段代码是安全的,但是这段代码:

<%= raw danger_string %> <!-- 危险 -->

就告诉模板系统关掉了安全过滤,这是非常危险的。通常谈到 raw 的时候都因为要输出 html 内容,这时候应该用 sanitize,这是一个基于白名单的过滤方法:

<%= sanitize danger_string %> <!-- 只要不开危险的标签属性名单就安全 -->

sanitize 可以在方法级别和全局级别设置白名单标签和属性,详细可以看文档 http://api.rubyonrails.org/classes/ActionView/Helpers/SanitizeHelper.html

总结:如果你不知道自己知不知道自己在干什么,别用 raw 和 html_safe,用 sanitize。

补充1:helper 里面也要避免 raw,避免在 helper 拼接 HTML 补充2:sanitize 要放在字符串处理链的末尾

共收到 53 条回复
3253

我也要裸奔。

96

有攻击实例么?话说这里的body_html不是都在markdown转换成html的时候已经是过滤过了么,不能算是直接由用户生成的吧……

96

#3楼 @jasl 目测你那个没有CSS白名单 ...

1

#4楼 @aptx4869 markdown 的过滤漏了一些,毕竟它不是专门做过滤的。

96

我说怎么这么快就修复了,还在想怎么主动触发呢

1107

#5楼 @bhuztez 用的黑名单 - -

96

#8楼 @jasl 感觉用正则表达式不牢靠啊

96

#6楼 @Rei 这样应该在保存body_html之前先过滤一遍就行了吧,就不用每次显示都调用一次sanitize了,有点浪费cpu的感觉……

96

#10楼 @aptx4869

看这里的9楼
http://ruby-china.org/topics/16628, 修复之前,点了就可以触发红心,而且传cookie给外网。上面已有四个红心。

1

#10楼 @aptx4869 有片段缓存,其实 body_html 我觉得都不用。

1107

#9楼 @bhuztez 不过style是String,所以只能用字符串的方式来搞,除非搞个parser给他弄成ast类似的形式

96

#13楼 @jasl 我就是找了个CSS解析库去过滤的 ...

1107

#14楼 @bhuztez 来分享下?

1

#13楼 @jasl #16楼 @bhuztez 允许 style 属性会导致怎样攻击?

96

#17楼 @Rei 至少 url() 可以随便插入个地址啥的,别的方法应该还有很多,一下子想不起来

1107

#17楼 @Rei 另外我印象里Rails的Sanitize是基于字符串方式的过滤,所以有可能会漏掉,sanitize那种gem是利用nokogiri把html搞成dom再做过滤,相对而言更加稳妥

21楼 已删除
1

#7楼 @hhuai 如果发现漏洞第一时间邮件管理员,我会很感激你的。

96

#23楼 @Rei 我还准备pull request上来的,都改好了的话,就没然后了。

227

确切的说是别对 用户输入的内容 用 raw 和 html_safe

1

#25楼 @chechaoyang 有人会觉得自己已经处理过了所以安全了,我总是为所有需要输出 HTML 的内容加 sanitize,除非是 SiteConfig 这种只有管理员输入、可能带有 javascript 的内容。

227

#26楼 @Rei 嗯,是的,应该这样。必须基于白名单来做 sanitize,XSS 的手段很多都在大家的认识之外,而且还会产生新的攻击方式,所以如果输出的内容需要支持更多的标签和属性,用一个专用的 gem 来做净化很有必要。这里有一份清单 https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet

2880

我也不用 raw 和 html_safe, 我直接用 <%== ......

9162

#28楼 @luikore 我也一直用== …听Rei这么一说还真不知道==等于哪个…

2880

#30楼 @Rei 嗯嗯, 最喜欢神原猴子了

另外大部分 rails helper 都被加过 html_safe, <%= sanitize ... %> 相当于 <%== sanitize ... %>, <%= form_for ... %> 相当于 <%== form_for ... %> ... 效果一样但 == 执行快一点...

2880

我觉得 html_safe 是个产生反效果的东西, 反而把 helper 搞得很复杂不容易看出来到底是不是安全了. 更喜欢裸 sinatra 这种没 html_safe 的, 出问题搜 == 就可以.

而 rails 出了问题你要 ==, rawhtml_safe 搜三遍...

1

#32楼 @luikore 我觉得不复杂啊,要输出 HTML 就用 sanitize,几乎不用 == raw html_safe。Rails 2 就是默认不 escape,当时爆了什么漏洞然后默认加上 h 了。

9162

#33楼 @Rei 感觉防不胜防…不如慢慢打补丁…

1107

Don't watch the animate labeled Boku It's just like yoooooo♂ THREE♂IT‘S THREEEEEEEEEE♂

10978

會造成怎樣的安全問題呢?

7360
  1. 要显示富文本,必须采用白名单机制。
  2. 可以试试这个:https://github.com/rgrove/sanitize
8807

很容易被script攻击,我之前就是裸奔,被裸打后,采用Sanitize...

40楼 已删除
9484

不过我现在仍然在用raw觉得挺好使的嘛

10978

#37楼 @Rei 感謝Rei!

4906

#42楼 @lonely21475 唉 同学 你进来了吗?

4769

#29楼 @cassiuschen ==(两个等于好什么意思啊?),

9162

#46楼 @liangbin661831 就是raw输出,字符串里任何内容不转义

10784

@Rei 我看到home/twitter.html.erb里还是<%= raw SiteConfig.twitter_page_html %>

1

#48楼 @gsky 这块内容是管理员控制的,为了插入 javascript 需要用 raw。

96

讨论很激烈啊。

有些页面,要由管理员在富文本框编辑内容的,似乎也只能用 html_safe了吧。

96

我觉得还有一个小遗憾,sanitize 会将不安全的标签砍掉,这样是安全了,但是仅仅只要这些不安全的标签不解析,保持原样输出的话,就不使了。

1

#3楼 @jasl WoW,我现在才理解你说的内容。 👍

1107

#52楼 @rei 嘿嘿

60a8f6

html_safe,用这个也不合适么?

26688

看完这篇文章又涨姿势了👍

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册