CSRF攻击和防护

Posted Flask学习笔记

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CSRF攻击和防护相关的知识,希望对你有一定的参考价值。

CSRF攻击和防护

前期我们的项目中都是显示的关闭CSRF的.

# config.py

# 显式关闭CSRF
WTF_CSRF_ENABLED = False

但是CSRF攻击确实客观上存在的,现在我们来讨论一下CSRF

1.什么是CSRF

CSRF跨站请求伪造,这是一种利用cookie每次请求都会带上的特性的攻击.

简单来说,攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件,发消息,盗取你的账号,添加系统管理员,甚至于购买商品,虚拟货币转账转账等.

比如如下攻击:

csrf

当然这需要攻击者研究确切的API 来操作,并且需要用户在登陆mybank.com后访问邪恶网站,尽管概率比较低,但是这种攻击却广泛存在.

2.攻击实例(mybank.com)

利用Flask实现www.mybank.comwww.evel-website.com 网站,模拟CSRF攻击过程.

先实现第一个网站www.mybank.com

代码参考https://github.com/ningwenyan/demo_code/tree/master/flask_demo_code/T23

1.实现网站的基本框架

www.mybank.com 要实现如下功能

www.mybank.com
 ├── base.html       # 网站模板
 ├── index.html        # 网站首页
 ├── login.html        # 登陆页面
 ├── personal.html     # 查看个人信息和余额情况
 ├── regist.html            # 注册页面
 ├── save_money.html    # 存钱页面
 ├── logout.html    # 退出页面
 └── transfer.html              # 转账页面

基本实现网站的GET请求都能访问到页面.

# app.py
from flask import Flask
import config
from flask import render_template,views

app = Flask(__name__)
app.config.from_object(config)

# 首页
@app.route('/')
def index():
    return render_template('index.html')

# 注册页
class RegisterView(views.MethodView):
    def get(self):
        return render_template('register.html')
    def post(self):
        pass

# 登录页
class LoginView(views.MethodView):
    def get(self):
        return render_template('login.html')
    def post(self):
        pass

# 个人信息页面
@app.route('/personal/')
def personal():
    return render_template('personal.html')

# 存钱页面
class SaveMoneyView(views.MethodView):
    def get(self):
        return render_template('savemoney.html')
    def post(self):
        pass

# 转账页面
class TransferView(views.MethodView):
    def get(self):
        return render_template('transfer.html')
    def post(self):
        pass

# 退出
@app.route('/logout/')
def logout():
    return render_template('index.html')

# 注册URL
app.add_url_rule('/login/', view_func=LoginView.as_view('login'))
app.add_url_rule('/register/',view_func=RegisterView.as_view('register'))
app.add_url_rule('/savemoney/',view_func=SaveMoneyView.as_view('savemoney'))
app.add_url_rule('/transfer/',view_func=TransferView.as_view('transfer'))

if __name__ == '__main__':
    app.run()

搭建基本的html页面,这里把以前的知识串联一下,使用base.html模板来支撑所有的页面.

2.前端页面

使用jinja渲染页面

1.base.html

主要是用来搭建轮廓

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>
        <!-- 此处填写页面标题 -->
        {% block block_title %}
        {% endblock block_title %}
    </title>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/base.css') }}">
    <script src="{{ url_for('static', filename='js/jquery.min.js') }}"></script>
    <!-- 此处用于填写各个javascript脚本 -->
    {% block block_script %} 
    {% endblock block_script %}
</head>

<body>
    <!-- 页面主内容 -->
    <div class="outer_container">
        <div class="log">
            <img src="{{ url_for('static',filename='images/10002.png') }}" alt="log">
        </div>
        {# 导航栏#}
        <div class="navigation">
            <ul>
                <li><a href="{{ url_for('index') }}">首页</a></li>
                <li><a href="{{ url_for('login') }}">登录</a></li>
                <li><a href="{{ url_for('personal') }}">个人信息</a></li>
                <li><a href="{{ url_for('register') }}">注册</a></li>
                <li><a href="{{ url_for('savemoney') }}">存钱</a></li>
                <li><a href="{{ url_for('transfer') }}">转账</a></li>
                <li><a href="{{ url_for('logout') }}">退出</a></li>
            </ul>
        </div>
        {% block block_get %} 
        {% endblock %}
        <form action="" method="post">
            {% block block_post %}
            {% endblock %}
        </form>
        <footer>欢迎您来到智商银行</footer>
    </div>
</body>

</html>

页面的css文件如下(根据自己的需求去修改)

body{
    margin0;
}
.outer_container{
    width1007px;
    height1100px;
    /*居中对齐*/
    margin0 auto;
    border1px solid gray;
    position: relative;

}
.log{
    width960px;
    height80px;
    /*居中对齐*/
    margin0 auto;

}
.navigation{
    width960px;
    height40px;
    /*居中对齐*/
    margin0 auto;
}
.navigation ul{
    width960px;
    background-color#55a8ea;
    /* 清除点 */
    list-style: none;
    /* 清除默认Padding */
    padding0px;
    /* 设置居中 */
    margin0 0;
    /* 清除间隙 */
    font-size0px;
    position: relative;
}
.navigation ul li{
    /* 转化行内块元素 */
    display: inline-block;
    width137px;
    height40px;
    /* 设置居中 */
    text-align: center;
    line-height40px;
}
.navigation ul li a{
    display: inline-block;
    font-size14px;
    font-family"YaHei Consolas Hybrid";
    color#fff;
    text-decoration: none;
}
.navigation ul li:hover{
    background-color#00619f;
}

.in_container{
    width600px;
    height500px;
    border1px solid gray;
    margin30px auto;
}
.in_h2{
    font-family"YaHei Consolas Hybrid";
    color: black;
    text-align: center;
}
.in_box{
    height40px;
    width398px;
    border1px solid gray;
    overflow: hidden;
    text-align: center;
    margin10px 100px;
}
.in_img{
    width40px;
    display: inline-block;
    float: left;
    margin10px 2px;;
}
.in_input_1{
    width354px;
    display: inline-block;
    float: left;
}
.in_input_1 input{
    height40px;
    width354px;
    font-size17px;

}
.in_lifetime{
    height36px;
    width360px;
    font-family"YaHei Consolas Hybrid";
    font-size16px;
    color: black;
    margin10px 100px;
}
.in_submit{
    height50px;
    width398px;
    margin5px auto;
    text-align: center;
}
.in_submit input{
    height50px;
    width390px;
    background-color#55a8ea;
    font-family"YaHei Consolas Hybrid";
    font-size22px;
    color: white;

}

.in_input_2{
    width400px;
    height56px;
    overflow: hidden;
    font-family"YaHei Consolas Hybrid";
    font-size14px;
    color: black;
    margin10px 100px;
}
.in_input_2 label{
    display: inline-block;
    width60px;
    float: left;
}
.in_input_2 input{
    display: inline-block;
    width330px;
    float: left;
}
.in_input_2 span{
    font-size12px;
    color#999;
}
.in_trans{
    width80px;
    display: inline-block;
    float: left;
    margin10px 2px;;
}
.in_input_3{
    width314px;
    height40px;
    display: inline-block;
    float: right;
    text-align: center;
    line-height40px;
}
.in_input_3 input{
    width314px;
    height40px;
    font-family"YaHei Consolas Hybrid";
    font-size17px;
    color: black;

}
footer{
    width100%;
    position: absolute;
    bottom0;
    text-align: center;
    font-family"YaHei Consolas Hybrid";
    font-size24px;
    color: aqua;
    border-top1px solid #55a8ea;
}

jQuery文件需要自己去下载任意版本.图片可以使用使用我的图片(参考代码示例),搭建出基本的框架,如果需要修改,需要自己去修改.

2.其他页面

参考示例代码,都是基本的html

3.目录结构

整个目录结构如下

❯ tree
.
├── app.py
├── config.py
├── static
│   ├── css
│   │   └── base.css
│   ├── images
│   │   ├── 10001.png
│   │   ├── 10002.png
│   │   ├── 10003.png
│   │   ├── ico-password.png
│   │   └── ico-user.png
│   └── js
│       └── jquery.min.js
└── templates
    ├── base.html
    ├── index.html
    ├── login.html
    ├── personal.html
    ├── register.html
    ├── savemoney.html
    └── transfer.html
4.运行效果

保证整个项目运行的时候能够自由的切换到各个页面.

10312
wechat
- END -


以上是关于CSRF攻击和防护的主要内容,如果未能解决你的问题,请参考以下文章

CSRF攻击和防护

Go 语言安全编程系列:CSRF 攻击防护

前端安全之 CSRF 攻击原理和防护方法

WEB攻击之CSRF攻击与防护

SpringSecurity的csrf防护机制

CSRF攻击与防护讲解