[{"data":1,"prerenderedAt":244},["ShallowReactive",2],{"tag-xss-1":3},{"title":4,"articles":5,"hot_article":29,"month_arch":92,"total":240,"cover":241},"xss - 独孤影的博客",[6,19],{"id":7,"title":8,"uri":8,"author":9,"tags":10,"created_at":16,"view_count":17,"content":18},26,"xss攻击最终应对方案","duguying",[11,12,13,14,15],"markdown","epiceditor","xss","后端","过滤","2014-12-16 14:54:42",3802,"\u003Cp>今天终于解决了xss这个潜在的问题，编辑器使用的是Markdown编辑器EpicEditor，\u003Cspan style=\"line-height: 23px;\">EpicEditor是一款Markdown编辑器，或者说是一款可以自己定制的编辑器。后台Markdown解析器用的是&quot;github.com\u002Frussross\u002Fblackfriday&quot;，后台代码\u003C\u002Fspan>\u003C\u002Fp>\u003Cpre class=\"brush:go;toolbar:false\">func&nbsp;Markdown2HTML(content&nbsp;string)&nbsp;string&nbsp;{\n\tcontent&nbsp;=&nbsp;html.EscapeString(content)\n\toutput&nbsp;:=&nbsp;blackfriday.MarkdownCommon([]byte(content))\n\treturn&nbsp;string(output)\n}\u003C\u002Fpre>\u003Cp>\u003Cspan style=\"line-height: 23px;\">\u003C\u002Fspan>直接将markdown语法的串解析为html语法的串，后台还设置了一个markdown解析api后面待用，api的controller代码如下\u003C\u002Fp>\u003Cpre class=\"brush:go;toolbar:false\">\u002F\u002F&nbsp;parse&nbsp;markdown\ntype&nbsp;MarkdownController&nbsp;struct&nbsp;{\n\tcontrollers.BaseController\n}\n\nfunc&nbsp;(this&nbsp;*MarkdownController)&nbsp;Get()&nbsp;{\n\tthis.Data[&quot;json&quot;]&nbsp;=&nbsp;map[string]interface{}{\n\t\t&quot;result&quot;:&nbsp;false,\n\t\t&quot;msg&quot;:&nbsp;&nbsp;&nbsp;&nbsp;&quot;only&nbsp;post&nbsp;method&nbsp;support&quot;,\n\t\t&quot;refer&quot;:&nbsp;&nbsp;nil,\n\t}\n\n\tthis.ServeJson()\n}\n\nfunc&nbsp;(this&nbsp;*MarkdownController)&nbsp;Post()&nbsp;{\n\tcontent&nbsp;:=&nbsp;this.GetString(&quot;content&quot;)\n\n\tlog.Blueln(content)\n\trst&nbsp;:=&nbsp;utils.Markdown2HTML(content)\n\n\tthis.Data[&quot;json&quot;]&nbsp;=&nbsp;map[string]interface{}{\n\t\t&quot;result&quot;:&nbsp;&nbsp;true,\n\t\t&quot;msg&quot;:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;success&quot;,\n\t\t&quot;preview&quot;:&nbsp;rst,\n\t\t&quot;refer&quot;:&nbsp;&nbsp;&nbsp;nil,\n\t}\n\n\tthis.ServeJson()\n}\u003C\u002Fpre>\u003Cp>前端将串传给后端，这个串期望是纯markdown的，因此如果其中夹杂着有html语法，html将会被转义，之后返回带有解析后的html串。\u003C\u002Fp>\u003Cp>前端的EpicEditor默认是能够解析Markdown和兼容HTML的，甚至不过滤js(\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FOscarGodson\u002FEpicEditor\u002Fissues\u002F351\" target=\"_blank\" title=\"https:\u002F\u002Fgithub.com\u002FOscarGodson\u002FEpicEditor\u002Fissues\u002F351\">这个问题\u003C\u002Fa>我已经向项目作者反馈过，他决定之后会给其添加选项以禁用js)，由于我\u003Ca href=\"http:\u002F\u002Fduguying.net\u002Farticle\u002FXSS%E6%94%BB%E5%87%BB%E5%BA%94%E5%AF%B9%E6%96%B9%E6%A1%88\" target=\"_blank\" title=\"http:\u002F\u002Fduguying.net\u002Farticle\u002FXSS%E6%94%BB%E5%87%BB%E5%BA%94%E5%AF%B9%E6%96%B9%E6%A1%88\">之前的文章\u003C\u002Fa>提到css都会给用户机会造成页面混乱，而\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fmicrocosm-cc\u002Fbluemonday\" target=\"_blank\" title=\"https:\u002F\u002Fgithub.com\u002Fmicrocosm-cc\u002Fbluemonday\">我所找到的过滤器\u003C\u002Fa>只支持xss过滤，即只过滤js不过滤css，并且那个过滤器有一个依赖包在墙外，这将会是很蛋疼，所以决定使用markdown，是纯markdown。EpicEditor是兼容html的，因此不满足我的需求，于是我问EpicEditor的作者是否有禁用html的选项（\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FOscarGodson\u002FEpicEditor\u002Fissues\u002F352\" target=\"_blank\" title=\"https:\u002F\u002Fgithub.com\u002FOscarGodson\u002FEpicEditor\u002Fissues\u002F352\">传送\u003C\u002Fa>），他告诉我EpicEditor不负责解析的，解析器可以自己定制，EpicEditor默认使用的解析器是\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fchjj\u002Fmarked\" target=\"_blank\" title=\"https:\u002F\u002Fgithub.com\u002Fchjj\u002Fmarked\">markd\u003C\u002Fa>解析器，然后给了我一个\u003Ca href=\"https:\u002F\u002Fgithub.com\u002FOscarGodson\u002FEpicEditor#custom-parsers\" target=\"_blank\" title=\"https:\u002F\u002Fgithub.com\u002FOscarGodson\u002FEpicEditor#custom-parsers\">页面\u003C\u002Fa>，其上有定制解析器的demo\u003C\u002Fp>\u003Cpre class=\"brush:js;toolbar:false\">var&nbsp;editor&nbsp;=&nbsp;new&nbsp;EpicEditor({\n&nbsp;&nbsp;parser:&nbsp;function&nbsp;(str)&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;blacklist&nbsp;=&nbsp;[&#39;foo&#39;,&nbsp;&#39;bar&#39;,&nbsp;&#39;baz&#39;];\n&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;str.split(&#39;&nbsp;&#39;).map(function&nbsp;(word)&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\u002F\u002F&nbsp;If&nbsp;the&nbsp;word&nbsp;exists,&nbsp;replace&nbsp;with&nbsp;asterisks\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(blacklist.indexOf(word)&nbsp;&gt;&nbsp;-1)&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&#39;****&#39;\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;word;\n&nbsp;&nbsp;&nbsp;&nbsp;}).join(&#39;&nbsp;&#39;);\n&nbsp;&nbsp;}\n}).load();\u003C\u002Fpre>\u003Cp>自己重做一个解析器？看一下markd项目的代码有多少吧，重做工作量太大。仔细分析上面的代码发现parser是一个函数，它的作用是这样的，传入原串，返回解析后的串。这回我之前留的api起作用了，自己实现的parser函数如下\u003C\u002Fp>\u003Cpre class=\"brush:js;toolbar:false\">parser:&nbsp;function&nbsp;(str)&nbsp;{\n\tvar&nbsp;rst&nbsp;=&nbsp;$.ajax({\n\t\tasync:&nbsp;false,\n\t\ttype:&nbsp;&quot;post&quot;,\n\t\turl:&nbsp;&quot;\u002Fapi\u002Fmarkdown\u002Fpreview&quot;,\n\t\tdata:&nbsp;{&quot;content&quot;:&nbsp;str},\n\t\tdataType:&quot;json&quot;,\n\n\t}).responseText;\n\tvar&nbsp;json&nbsp;=&nbsp;eval(&#39;(&#39;+rst+&#39;)&#39;)\n\tconsole.log(json);\n\treturn&nbsp;json.preview;\n},\u003C\u002Fpre>\u003Cp>是的，我将原数据传给服务器去解析，得到结果，这样还有一个好处就是保证了解析器的一致性，即最终结果与编辑器preview结果是一致的。当然这也是有一些缺点的，那就是给服务器增加了负担，不过我觉得这是值得的。最后附上编辑器工作的截图\u003Cbr\u002F>\u003C\u002Fp>\u003Cp>\u003Cimg src=\"\u002F\u002Fduguying.oss-cn-qingdao.aliyuncs.com\u002F2014\u002F12\u002F16\u002Fepiceditor_back_end_anti_xss.png\" title=\"\" alt=\"epiceditor_back_end_anti_xss.png\"\u002F>\u003C\u002Fp>\u003Cp>问题能够得以解决应当感谢各个开源项目以及其作者的无私奉献，还有他们的热心答疑，取之于开源用之于开源，Goj也会是一个开源项目，愿早日完成。\u003C\u002Fp>",{"id":20,"title":21,"uri":21,"author":9,"tags":22,"created_at":26,"view_count":27,"content":28},24,"XSS攻击应对方案",[23,24,25],"XSS","攻击","跨站脚本攻击","2014-12-14 19:39:48",6822,"\u003Cp>XSS(Cross Site Scripting)，跨站脚本攻击，简单来说就是用户获取到了页面脚本执行的权限，够获取到JS脚本执行权限后能干的事情很多，比如盗取session id，从而实现登录帐号从而获取账户相关信息。\u003Cbr\u002F>\u003C\u002Fp>\u003Cp>XSS攻击一般都是出现在有富文本提交的表单中，用户可以在提交的富文本中按以下各种方法插入JavaScript脚本：\u003C\u002Fp>\u003Cpre class=\"brush:html;toolbar:false\">&lt;script&gt;alert(&quot;hacked!&quot;);&lt;\u002Fscript&gt;\u003C\u002Fpre>\u003Cpre class=\"brush:html;toolbar:false\">&lt;img&nbsp;src=&quot;.\u002F&quot;&nbsp;onerror=&quot;alert(&#39;hacked!&#39;);&quot;&gt;\u003C\u002Fpre>\u003Cpre class=\"brush:html;toolbar:false\">&lt;a&nbsp;href=&quot;javascript:alert(&#39;hacked!&#39;)&quot;&gt;foo&lt;\u002Fa&gt;\u003C\u002Fpre>\u003Cpre class=\"brush:html;toolbar:false\">&lt;style&gt;\ndiv{\n&nbsp;&nbsp;background:&nbsp;url(&quot;javascript:alert(&#39;hacked!&#39;);&quot;);\n}\n&lt;\u002Fstyle&gt;\u003C\u002Fpre>\u003Cp>以及其他的各种方法在页面执行Js脚本，当然黑客执行脚本的目的并不是为了弹窗装逼，而是读取当前用户的cookies，从而获取session id，达到非法登录用户账户的目的，简单来说就是不要密码盗号。\u003Cbr\u002F>\u003C\u002Fp>\u003Cp>嵌入式web页面富文本编辑器很多，例如ueditor等，有人以为防范XSS攻击是这些编辑器的事情，事实上XSS攻击并不是这些编辑器能够阻止得了的，因为黑客是可以绕过编辑器提交表单的，所以防范XSS攻击的重点是后台字符串过滤，将非法的串过滤掉，当然还有另外一种办法，那就是使用第三方替代标签，如UBB标签(discuz中使用的就是这个)、Markdown等，不直接使用HTML系列的标签由其他标签转换为HTML，从而达到防止非法注入脚本的目的。\u003C\u002Fp>\u003Cp>事实上富文本提交攻击防范远不止XSS这些，XSS主要是指Js脚本的攻击，可是有一种不致命却很糟糕的攻击却是被忽略了，那就是css脚本扰乱界面布局，事实上这应该算是纯粹的捣乱，可是却也能够严重的影响到页面的美观以及用户的正常使用，开源中国就曾经被大家用这种方法玩坏过。\u003C\u002Fp>\u003Cpre class=\"brush:html;toolbar:false\">&lt;div&nbsp;style=&quot;display:block;position:fixed;width:100%;height:100%;background-color:red;&quot;&gt;&lt;\u002Fdiv&gt;\u003C\u002Fpre>\u003Cp>上面的代码便可以让整个网页变成红色。\u003Cbr\u002F>\u003C\u002Fp>\u003Cp>因此，我个人认为html富文本的过滤不仅仅是简单的Js过滤，应当连css一起过滤掉。或者干脆使用第三方标签UBB等。\u003C\u002Fp>",{"title":30,"list":31},"最热文章",[32,38,44,50,56,62,68,74,80,86],{"id":33,"title":34,"uri":35,"author":9,"created_at":36,"view_count":37},28,"docker容器目录与主机目录同步","\u002Farticle\u002Fdocker容器目录与主机目录同步","2014-12-31 12:34:08",15570,{"id":39,"title":40,"uri":41,"author":9,"created_at":42,"view_count":43},21,"beego中使用fis","\u002Farticle\u002Fbeego中使用fis","2014-12-03 10:47:56",9250,{"id":45,"title":46,"uri":47,"author":9,"created_at":48,"view_count":49},20,"用github登录，oauth开发","\u002Farticle\u002F用github登录，oauth开发","2014-11-23 13:33:37",9113,{"id":51,"title":52,"uri":53,"author":9,"created_at":54,"view_count":55},18,"windows服务注册工具nssm","\u002Farticle\u002Fwindows服务注册工具nssm","2014-10-31 21:34:39",9047,{"id":57,"title":58,"uri":59,"author":9,"created_at":60,"view_count":61},49,"用latex排版中文书籍","\u002Farticle\u002F用latex排版中文书籍","2016-10-31 11:12:02",8634,{"id":63,"title":64,"uri":65,"author":9,"created_at":66,"view_count":67},19,"texlive中文书签乱码","\u002Farticle\u002Ftexlive中文书签乱码","2014-11-15 02:54:01",8461,{"id":69,"title":70,"uri":71,"author":9,"created_at":72,"view_count":73},6,"Windows上的软件包管理器chocolatey","\u002Farticle\u002FWindows上的软件包管理器chocolatey","2014-08-10 15:55:22",8009,{"id":75,"title":76,"uri":77,"author":9,"created_at":78,"view_count":79},3,"利用开源和免费资源搭建CI环境","\u002Farticle\u002F利用开源和免费资源搭建CI环境","2014-07-04 16:54:58",7732,{"id":81,"title":82,"uri":83,"author":9,"created_at":84,"view_count":85},16,"php-fpm网站目录权限配置","\u002Farticle\u002Fphp-fpm网站目录权限配置","2014-10-18 01:36:10",7274,{"id":87,"title":88,"uri":89,"author":9,"created_at":90,"view_count":91},27,"sublime text 2插件开发，外部修改文件无法重新加载","\u002Farticle\u002Fsublime text 2插件开发，外部修改文件无法重新加载","2014-12-26 20:24:13",7054,{"title":93,"list":94},"按月归档",[95,99,102,105,108,111,114,118,122,125,128,131,135,138,141,145,148,151,154,158,161,164,167,170,173,176,179,182,185,188,191,194,197,200,203,206,209,212,215,218,222,225,228,231,234,237],{"title":96,"uri":97,"view_count":98},"2026年7月","\u002Farchive\u002F2026\u002F7\u002F1","[1]",{"title":100,"uri":101,"view_count":98},"2026年1月","\u002Farchive\u002F2026\u002F1\u002F1",{"title":103,"uri":104,"view_count":98},"2025年4月","\u002Farchive\u002F2025\u002F4\u002F1",{"title":106,"uri":107,"view_count":98},"2024年6月","\u002Farchive\u002F2024\u002F6\u002F1",{"title":109,"uri":110,"view_count":98},"2024年5月","\u002Farchive\u002F2024\u002F5\u002F1",{"title":112,"uri":113,"view_count":98},"2024年4月","\u002Farchive\u002F2024\u002F4\u002F1",{"title":115,"uri":116,"view_count":117},"2023年12月","\u002Farchive\u002F2023\u002F12\u002F1","[6]",{"title":119,"uri":120,"view_count":121},"2023年11月","\u002Farchive\u002F2023\u002F11\u002F1","[2]",{"title":123,"uri":124,"view_count":98},"2023年10月","\u002Farchive\u002F2023\u002F10\u002F1",{"title":126,"uri":127,"view_count":98},"2023年7月","\u002Farchive\u002F2023\u002F7\u002F1",{"title":129,"uri":130,"view_count":121},"2023年6月","\u002Farchive\u002F2023\u002F6\u002F1",{"title":132,"uri":133,"view_count":134},"2023年5月","\u002Farchive\u002F2023\u002F5\u002F1","[3]",{"title":136,"uri":137,"view_count":121},"2023年4月","\u002Farchive\u002F2023\u002F4\u002F1",{"title":139,"uri":140,"view_count":121},"2023年3月","\u002Farchive\u002F2023\u002F3\u002F1",{"title":142,"uri":143,"view_count":144},"2023年2月","\u002Farchive\u002F2023\u002F2\u002F1","[5]",{"title":146,"uri":147,"view_count":98},"2023年1月","\u002Farchive\u002F2023\u002F1\u002F1",{"title":149,"uri":150,"view_count":121},"2022年12月","\u002Farchive\u002F2022\u002F12\u002F1",{"title":152,"uri":153,"view_count":144},"2022年11月","\u002Farchive\u002F2022\u002F11\u002F1",{"title":155,"uri":156,"view_count":157},"2022年10月","\u002Farchive\u002F2022\u002F10\u002F1","[4]",{"title":159,"uri":160,"view_count":117},"2022年9月","\u002Farchive\u002F2022\u002F9\u002F1",{"title":162,"uri":163,"view_count":144},"2022年8月","\u002Farchive\u002F2022\u002F8\u002F1",{"title":165,"uri":166,"view_count":98},"2019年7月","\u002Farchive\u002F2019\u002F7\u002F1",{"title":168,"uri":169,"view_count":98},"2019年2月","\u002Farchive\u002F2019\u002F2\u002F1",{"title":171,"uri":172,"view_count":98},"2018年9月","\u002Farchive\u002F2018\u002F9\u002F1",{"title":174,"uri":175,"view_count":98},"2018年8月","\u002Farchive\u002F2018\u002F8\u002F1",{"title":177,"uri":178,"view_count":98},"2017年11月","\u002Farchive\u002F2017\u002F11\u002F1",{"title":180,"uri":181,"view_count":98},"2017年8月","\u002Farchive\u002F2017\u002F8\u002F1",{"title":183,"uri":184,"view_count":98},"2017年5月","\u002Farchive\u002F2017\u002F5\u002F1",{"title":186,"uri":187,"view_count":98},"2017年4月","\u002Farchive\u002F2017\u002F4\u002F1",{"title":189,"uri":190,"view_count":98},"2016年11月","\u002Farchive\u002F2016\u002F11\u002F1",{"title":192,"uri":193,"view_count":98},"2016年10月","\u002Farchive\u002F2016\u002F10\u002F1",{"title":195,"uri":196,"view_count":121},"2016年9月","\u002Farchive\u002F2016\u002F9\u002F1",{"title":198,"uri":199,"view_count":98},"2016年8月","\u002Farchive\u002F2016\u002F8\u002F1",{"title":201,"uri":202,"view_count":121},"2016年7月","\u002Farchive\u002F2016\u002F7\u002F1",{"title":204,"uri":205,"view_count":144},"2016年6月","\u002Farchive\u002F2016\u002F6\u002F1",{"title":207,"uri":208,"view_count":98},"2015年12月","\u002Farchive\u002F2015\u002F12\u002F1",{"title":210,"uri":211,"view_count":98},"2015年10月","\u002Farchive\u002F2015\u002F10\u002F1",{"title":213,"uri":214,"view_count":121},"2015年2月","\u002Farchive\u002F2015\u002F2\u002F1",{"title":216,"uri":217,"view_count":98},"2015年1月","\u002Farchive\u002F2015\u002F1\u002F1",{"title":219,"uri":220,"view_count":221},"2014年12月","\u002Farchive\u002F2014\u002F12\u002F1","[8]",{"title":223,"uri":224,"view_count":121},"2014年11月","\u002Farchive\u002F2014\u002F11\u002F1",{"title":226,"uri":227,"view_count":144},"2014年10月","\u002Farchive\u002F2014\u002F10\u002F1",{"title":229,"uri":230,"view_count":134},"2014年9月","\u002Farchive\u002F2014\u002F9\u002F1",{"title":232,"uri":233,"view_count":134},"2014年8月","\u002Farchive\u002F2014\u002F8\u002F1",{"title":235,"uri":236,"view_count":134},"2014年7月","\u002Farchive\u002F2014\u002F7\u002F1",{"title":238,"uri":239,"view_count":121},"2013年9月","\u002Farchive\u002F2013\u002F9\u002F1",2,{"url":242,"title":243},"https:\u002F\u002Fimage.duguying.net\u002F2022\u002F09\u002Fij6x8o4s.webp","老家 摄于2020年秋",1790062269098]