XSS过滤

XSS过滤封装用法

封装到app01/form.py文件中进行验证

from django.forms import Form,widgets,fields

class ArticleForm(Form):
    title = fields.CharField(max_length=64)
    content = fields.CharField(
        widget=widgets.Textarea(attrs={'id':'i1'}))

    #此处为xss验证
    def clean_content(self):
        old = self.cleaned_data['content']
        from utils.xss import xss
        return xss(old)
app01/form.py
CONTENT=''
def create_article(request,site):
    from app01.form import ArticleForm
    if request.method == 'GET':
        obj = ArticleForm()
        return render(request,'creat_article.html',{'site':site})
    else:
        obj = ArticleForm(request.POST)
        if obj.is_valid():
            content = obj.cleaned_data['content']
            global CONTENT      #这里记得要设置全局变量
            CONTENT = content
            return HttpResponse('上传成功')

# 查看文章内容,只是简单的
def see(request):
    return render(request,'see.html',{'CONTENT':CONTENT})
app01/views
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>$Title$</title>
</head>
<body>
<h3>发布文章</h3>
<form action="/background/{{ site }}/create_article.html" method="POST">
    {% csrf_token %}
    文章标题<input type="text">
    <textarea name="content" id="i1" cols="30" rows="10"></textarea>
    <input type="submit" value="提交"  style="margin-left: 35%">
</form>

<script src="/static/kindeditor-4.1.10/kindeditor-all.js"></script>
<script>
    // KindEditor 上传的瞬间,帮你生成iframe+form进行伪Ajax操作
    KindEditor.create('#i1',{
        width:'1000px',
        height:'500px',
        resizeType:2,   // 默认是否可以拖动改变高度和宽带,0,1,2,其中默认是2,可以拖动改变宽度和高度。
        uploadJson:'/upload_img.html', // 上传文件位置,注意不能写目录/static/files...类似这种,识别不了。要写url
        // 注意:上传文件时,是以POST请求提交的,但是要写上{% csrf_token %},上面表单中写的上传文件时没法用到,要配置
        extraFileUploadParams:{'csrfmiddlewaretoken':"{{ csrf_token }}"}

    })
</script>
</body>
</html>
creat_article.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>$Title$</title>
</head>
<body>
{{ CONTENT|safe }}
</body>
</html>
see.html
from bs4 import BeautifulSoup
def xss(old):
    soup = BeautifulSoup(old,'html.parser')
    tags = soup.find_all()
    vaild_tag = {'p':['class','id'],'img':['src'],'div':['class']}
    for tag in tags:
        if tag.name not in vaild_tag:
            tag.decompose()
        if tag.attrs:
            for k in list(tag.attrs.keys()):
                if k not in vaild_tag[tag.name]:
                    del tag.attrs[k]
    comment_str=soup.decode()
    return comment_str
utils/xss.py
url(r'^background/(\w+)/create_article.html$', views.create_article),
url(r'^see.html', views.see),   
urls

下面是xss.py内容的注释 

# 通过beautifulsoup4 模块可以避免写正则表达式来完成过滤上传文件中的恶意攻击
from bs4 import BeautifulSoup
content = """
<p id='i1' a='123' b='999'>
    <script>alert(123)</script>
</p>

<p id='i2'>
    <div>
        <p>asdfasdf</p>
    </div>
    <img id='i3' src="/static/imgs\1.jpg" alt="" />
</p>
"""
soup = BeautifulSoup(content,'html.parser')     # parser为beautifulsoup4 模块的内置解析块,将html解析成对象
tag = soup.find(name='img')     # 获取的是img标签,name= 标签名
# print(tag)  #<img alt="" id="i3" src="/static/imgs.jpg"/>  ,为字符串??
tag = soup.find(name='p')   #获取的是 p 标签及 p 标签内的子内容
# print(tag)  #<p a="123" b="999" id="i1"><script>alert(123)</script></p>
v = soup.find(name='p',attrs={'id':'i2','name':''})     # 也可以通过id 和 name 获取,条件是且的关系
# print(v)    #<p id='i2'><div><p>asdfasdf</p></div><img id='i3' src="/static/imgs\1.jpg" alt="" /></p>
# 以上find 获取的都是选中的内容和其内部包含的子内容,且获取的是字符串类型
#find_all 获取的是列表类型,列表里是对象
v = soup.find_all(name='p')
# print(v)   #递归找到所有的标签,步骤:找第一个父类,父类和子类中符合的取出来,然后再把子类符合的标签取出来。子类符合的标签可能被取出来很多次
#[<p a="123" b="999" id="i1"><script>alert(123)</script></p>, <p id="i2"><div><p>asdfasdf</p></div><img alt="" id="i3" src="/static/imgs.jpg"/></p>, <p>asdfasdf</p>]

#以下为过滤部分
vaild_tag = ['p','img','div']   #白名单,设置白名单不设黑名单的原因是xss攻击的方式多种多样,而且不断更新
tags = soup.find_all()
for tag in tags:
    if tag.name not in vaild_tag:
        # tag.clear()     # tag.clear()只是把tag标签的内容删掉,标签本身不被删掉
        tag.decompose()     #删除的是标签内的内容和标签本身
print(soup)  #soup是对象,要拿到过滤后的结果,需要decode下
comment_str=soup.decode()   #comment_str 这是拿到最终被过滤后的结果

#白名单也可以设置为字典格式,标签部分属性设置为白名单
vaild_tag = {'p':['class','id'],'img':['src'],'div':['class']}
for tag in tags:
    if tag.name not in vaild_tag:
        tag.decompose()
    if tag.attrs:
        for k in list(tag.attrs.keys()):
            if k not in vaild_tag[tag.name]:
                del tag.attrs[k]
comment_str=soup.decode()    #将soup对象转换成字符串,encode()将soup对象转换成字节
xss.py注释

 

posted @ 2016-08-21 15:55  许二哈哈哈  阅读(240)  评论(0编辑  收藏  举报