前端编辑器传来的数据, BeautifulSoup 防止 xss 攻击,为了解析 script 缺得到了 <script> 此题怎解, 555

2019-08-06 00:57:11 +08:00
 wyzerg
[这是前端的内容:]
<h1>hello</h1>
<span>123</span>
<h1>hello</h1>
<span>123</span>
<h1>hello</h1><span>123</span>
<script>alert(123)</script>
<script>alert(123)</script>
<script>alert(123)</script>




[后端解析到的是:]
<pre><span style="color:#6a8759;">&lt;h1&gt;hello&lt;/h1&gt;&lt;span&gt;123&lt;/span&gt; </span><span style="color:#6a8759;">&lt;h1&gt;hello&lt;/h1&gt;&lt;span&gt;123&lt;/span&gt; </span><span style="color:#6a8759;"> </span><span style="color:#6a8759;">&lt;h1&gt;hello&lt;/h1&gt;&lt;span&gt;123&lt;/span&gt; </span><span style="color:#6a8759;"> </span><span style="color:#6a8759;"> </span><span style="color:#6a8759;">&lt;script&gt;alert(123)&lt;/script&gt; </span><span style="color:#6a8759;">&lt;script&gt;alert(123)&lt;/script&gt; </span><span style="color:#6a8759;">&lt;script&gt;alert(123)&lt;/script&gt;</span></pre>


[后端代码是:]
if request.method=="POST":
title=request.POST.get('title')

content=request.POST.get("content")
#拿到标签字符串
soup = BeautifulSoup(content, "html.parser",fromEncoding="UTF-8")
#先过滤:
for tag in soup.find_all():
if tag.name == "script" : #####问题出在这里,哪怕我换成”&lt;/script&gt;“,也匹配不到这里的 if
print("script--------->",tag.name) #####所以压根走不到这里,我懵了,555 怎样变回 script 呀??
tag.decompose() # 从 soup 里吧这个 script 的 tag 删除掉


desc = soup.text[0:150] #对文本进行截断 #######这里就变回了 script,怎么让前面的就变回 script ??
2064 次点击
所在节点    Python
13 条回复
ysc3839
2019-08-06 01:44:13 +08:00
为什么要解析后删除掉?直接转换成 HTML entity (例如 &lt;),确保不会当成 html 代码就行了。
starsriver
2019-08-06 02:02:16 +08:00
entity 转换一句话的事情。

以及转换完加反斜杠才是正确做法吧。
locoz
2019-08-06 08:23:27 +08:00
这不就是个 html encode 吗,decode 回去就是正常的样子了啊
Leigg
2019-08-06 09:21:45 +08:00
xss 的解决方案就是将斜杠括号引号全部转义。
wyzerg
2019-08-06 14:10:36 +08:00
@Leigg
@ysc3839
@locoz
@starsriver
谢谢非常感谢,我用
@ysc3839 方法试了下,用这个解决了
import html
content=request.POST.get("content")
content = html.unescape(content)
soup = BeautifulSoup(content, "html.parser")

----------------
html.unescape 这个方法就是把转义的 script 标签( &lt;script&gt; ),再反转义回来( <script> )
这样 for 循环,for tag in soup.find_all():就能拿到正规的<script>标签了,然后避免 xss 就把他 decompose() 删除掉就可以了,非常感谢
ysc3839
2019-08-06 14:47:27 +08:00
@wyzerg 我还是认为你没必要删除。你要实现的是把这段代码直接作为 html 代码插入页面中吗?那我还可以用 img onerror 来执行脚本,办法多了去了。最终会变成猫鼠游戏。
wyzerg
2019-08-06 15:44:54 +08:00
@ysc3839 老哥,那比如博客园,csdn 那种,放代码进去就是你的办法吗,你的意思是,&lt;script&gt; 获取到了,不转 script 了,那我存数据库就是&lt;script&gt; ,那前端调用呢?我应该模板用 safe 吧,这么说我有点懵了😂
no1xsyzy
2019-08-06 15:53:15 +08:00
额你这是拿 contenteditable="true" 做编辑器?
不要转换啊,<safeHTML>"&lt;" 直接传给前端不会含可执行的标签的。
no1xsyzy
2019-08-06 16:00:27 +08:00
那你这个样子做,如果我要给别人展示一段 HTML 代码怎么做?我如何包括一个 script 标签?
如果你指望的是像各个免费邮箱的 “纯文本编辑” 或者说 “ HTML 代码编辑” 的话,邮箱们其实有比较完善的处理方案,还要把所有的 @on(.*) 给换成 @on_$1 等(混杂了 XPath 和 RegExp 有点诡异,就这么看吧),但你不知道哪天 W3C 弄出一个新的标准使得某个奇怪的地方突然变成可以执行代码的了,又是 XSS。
如果要富文本,BBcode、Markdown、有限 HTML (仅 font h[1-6] br 等特定的) 哪个方案不行?非要自己做过滤?
wyzerg
2019-08-06 16:10:45 +08:00
@no1xsyzy 嗯嗯 我解释下哈
前端我用的是 KindEditor 做编辑器,在正常输入: <span>123</span> <script>alert(123)</script>
然后 post 请求发给后端
后端 request.POST 拿到数据
查看这条数据是变成了: </span>123<span style="color:#6a8759;"> &lt;script&gt;alert(123)&lt;/script&gt;
如果为了展示给前端,用模板语法{{ article_obj.content|safe }}:显示:<span>123</span> 效果
所以把 script 过滤掉了。。。
no1xsyzy
2019-08-06 18:20:43 +08:00
@wyzerg 我还是没明白你需要什么效果?
如果我想要写一段关于网页和 JavaScript 技术的文字如下:
```
<template>
<div>
{{foo}}
</div>
</template>

<script>
export default {
data(){return {foo:"bar"}}
}
</script>
```
我该如何写?
是不是用户永远不被允许写下包含 "<script>" 的文字了?
wyzerg
2019-08-07 17:14:02 +08:00
@no1xsyzy 是的,我是这个方法过滤掉 script -,-
no1xsyzy
2019-08-07 18:45:19 +08:00
@wyzerg 也就是说你拒绝了非常多技术性内容?
你甚至不希望写下格式化的文字,那么为什么不直接 textarea 解决呢?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/589358

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX