关于如何对 WMD 编辑器生成的 Markdown 进行服务器端清理以确保生成的 HTML 不包含恶意脚本,如下所示:
<img onload="alert('haha');"
src="http://www.google.com/intl/en_ALL/images/srpr/logo1w.png" />
但我也没有找到堵住客户端漏洞的好方法。当然,客户端验证不能替代服务器上的清理验证,因为任何人都可以假装是客户端并向您发送令人讨厌的 Markdown。而且,如果您在服务器上删除 HTML,攻击者将无法保存错误的 HTML,这样其他人以后就无法看到它,并且他们的 cookie 被盗或 session 被错误的脚本劫持。因此,有一个有效的案例表明,在 WMD 预览 Pane 中执行无脚本规则可能也不值得。
但想象一下,攻击者找到了一种将恶意 Markdown 放到服务器上的方法(例如,来自另一个站点的受损提要,或者在修复 XSS 错误之前添加的内容)。在将 markdown 翻译成 HTML 时应用的服务器端白名单通常会阻止向用户显示该错误的 Markdown。但是,如果攻击者可以让某人编辑页面(例如,通过发布另一个条目说恶意条目有一个损坏的链接并要求某人修复它),那么任何编辑该页面的人都会劫持他们的 cookie。诚然,这是一个极端案例,但它仍然值得防御。
此外,允许客户端预览窗口允许与您的服务器允许的不同的 HTML 可能不是一个好主意。
Stack Overflow 团队通过更改 WMD 填补了这个漏洞。他们是怎么做到的?
[注意:我已经解决了这个问题,但它需要一些棘手的 JavaScript 调试,所以我在这里回答我自己的问题以帮助可能想要做同样事情的其他人]。
最佳答案
一个可能的修复是在 wmd.js 中的 pushPreviewHtml() 方法中。这是来自 Stack Overflow version of WMD on GitHub 的原始代码:
if (wmd.panels.preview) {
wmd.panels.preview.innerHTML = text;
}
您可以将其替换为一些清理代码。这是 Stack Overflow 使用的代码的改编版 in response to this post ,它限制为标签白名单,对于 IMG 和 A 元素,限制为属性白名单(并且也以特定顺序!)。请参阅元堆栈溢出帖子 What HTML tags are allowed on Stack Overflow, Server Fault, and Super User? 有关白名单的更多信息。
注意:这段代码当然可以改进,例如允许以任何顺序列入白名单的属性。它还不允许 mailto: URL,这在 Internet 站点上可能是一件好事,但在您自己的 Intranet 站点上它可能不是最好的方法。
if (wmd.panels.preview) {
// Original WMD code allowed JavaScript injection, like this:
// <img src="http://www.google.com/intl/en_ALL/images/srpr/logo1w.png" onload="alert('haha');"/>
// Now, we first ensure elements (and attributes of IMG and A elements) are in a whitelist,
// and if not in whitelist, replace with blanks in preview to prevent XSS attacks
// when editing malicious Markdown.
var okTags = /^(<\/?(b|blockquote|code|del|dd|dl|dt|em|h1|h2|h3|i|kbd|li|ol|p|pre|s|sup|sub|strong|strike|ul)>|<(br|hr)\s?\/?>)$/i;
var okLinks = /^(<a\shref="(\#\d+|(https?|ftp):\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+)"(\stitle="[^"<>]+")?\s?>|<\/a>)$/i;
var okImg = /^(<img\ssrc="https?:(\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+)"(\swidth="\d{1,3}")?(\sheight="\d{1,3}")?(\salt="[^"<>]*")?(\stitle="[^"<>]*")?\s?\/?>)$/i;
text = text.replace(/<[^<>]*>?/gi, function (tag) {
return (tag.match(okTags) || tag.match(okLinks) || tag.match(okImg)) ? tag : ""
})
wmd.panels.preview.innerHTML = text; // Original code
}
另请注意,此修复不在 Stack Overflow version of WMD on GitHub 中-- 很明显,更改是稍后进行的,并没有重新 checkin GitHub。
更新:为了避免破坏在您输入 URL 时自动创建超链接的功能,您还需要对 showdown.js 进行更改,如下所示:
原代码:
var _DoAutoLinks = function(text) {
text = text.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,"<a href=\"$1\">$1</a>");
// Email addresses: <address@domain.foo>
/*
text = text.replace(/
<
(?:mailto:)?
(
[-.\w]+
\@
[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+
)
>
/gi, _DoAutoLinks_callback());
*/
text = text.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,
function(wholeMatch,m1) {
return _EncodeEmailAddress( _UnescapeSpecialChars(m1) );
}
);
return text;
}
固定代码:
var _DoAutoLinks = function(text) {
// use simplified format for links, to enable whitelisting link attributes
text = text.replace(/(^|\s)(https?|ftp)(:\/\/[-A-Z0-9+&@#\/%?=~_|\[\]\(\)!:,\.;]*[-A-Z0-9+&@#\/%=~_|\[\]])($|\W)/gi, "$1<$2$3>$4");
text = text.replace(/<((https?|ftp):[^'">\s]+)>/gi, '<a href="$1">$1</a>');
return text;
}
关于javascript - 将 WMD 编辑器的预览 HTML 与服务器端 HTML 验证对齐(例如,没有嵌入的 JavaScript 代码),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2837593/
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has
我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这
所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择