安全 别用 raw 和 html_safe

Rei · 发布于 2014年1月05日 · 最后由 rennyallen 回复于 2017年1月13日 · 14642 次阅读
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 条回复
96
bhuztez · #1 · 2014年1月05日

...

3253
cisolarix · #2 · 2014年1月05日

我也要裸奔。

96
aptx4869 · #4 · 2014年1月05日

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

96
bhuztez · #5 · 2014年1月05日

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

1
Rei · #6 · 2014年1月05日

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

96
hhuai · #7 · 2014年1月05日

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

1107
jasl · #8 · 2014年1月05日

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

96
bhuztez · #9 · 2014年1月05日

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

96
aptx4869 · #10 · 2014年1月05日

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

96
hhuai · #11 · 2014年1月05日

#10楼 @aptx4869

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

1
Rei · #12 · 2014年1月05日

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

1107
jasl · #13 · 2014年1月05日

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

96
bhuztez · #14 · 2014年1月05日

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

1107
jasl · #15 · 2014年1月05日

#14楼 @bhuztez 来分享下?

96
bhuztez · #16 · 2014年1月05日
1
Rei · #17 · 2014年1月05日

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

96
bhuztez · #18 · 2014年1月05日

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

1107
jasl · #20 · 2014年1月05日 1 个赞

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

21楼 已删除
1
Rei · #23 · 2014年1月05日

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

96
hhuai · #24 · 2014年1月05日

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

227
chechaoyang · #25 · 2014年1月05日 1 个赞

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

1
Rei · #26 · 2014年1月05日

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

227
chechaoyang · #27 · 2014年1月05日 1 个赞

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

2880
luikore · #28 · 2014年1月05日 1 个赞

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

9162
cassiuschen · #29 · 2014年1月07日

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

2880
luikore · #31 · 2014年1月07日

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

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

2880
luikore · #32 · 2014年1月07日 1 个赞

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

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

1
Rei · #33 · 2014年1月07日

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

9162
cassiuschen · #34 · 2014年1月07日

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

1107
jasl · #35 · 2014年1月08日

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

10978
emerson · #36 · 2014年1月09日

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

7360
sakura79 · #38 · 2014年1月13日
  1. 要显示富文本,必须采用白名单机制。
  2. 可以试试这个:https://github.com/rgrove/sanitize
8807
tsaikoga · #39 · 2014年2月13日

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

40楼 已删除
7245
raymondos · #41 · 2014年2月26日
9484
lonely21475 · #42 · 2014年2月27日

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

10978
emerson · #43 · 2014年4月16日

#37楼 @Rei 感謝Rei!

4906
wudixiaotie · #44 · 2014年9月23日

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

9484
lonely21475 · #45 · 2014年9月23日
4769
liangbin661831 · #46 · 2015年1月16日

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

9162
cassiuschen · #47 · 2015年1月16日

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

10784
gsky · #48 · 2015年1月26日

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

1
Rei · #49 · 2015年1月26日

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

96
feng88724 · #50 · 2015年4月25日

讨论很激烈啊。

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

96
liukai · #51 · 2015年10月28日

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

1
Rei · #52 · 2016年1月17日

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

1107
jasl · #53 · 2016年1月18日

#52楼 @rei 嘿嘿

25144
msl12 · #54 · 2016年9月21日

html_safe,用这个也不合适么?

26688
rennyallen · #55 · 2017年1月13日

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

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