1九、Flask實戰第19天:CSRF攻擊與防護

CSRF攻擊原理

網站是經過cookie來實現登陸功能的。而cookie只要存在瀏覽器中,那麼瀏覽器在訪問這個cookie的服務器的時候,就會自動的攜帶cookie信息到服務器上去。那麼這時候就存在一個漏洞了。若是你訪問了一個惡意網站,這個網站能夠在網頁源碼中插入JS代碼,使用JS代碼給其餘服務器發送請求。由於在發送請求的時候,瀏覽器會自動把cookie發送給對應的服務器,這時候相應的服務器就不知道這個請求是僞造的。從而達到在用戶不知情的狀況下,給某個服務器發送了一個請求。css

 防護CSRF攻擊原理

CSRF攻擊的要點就是在向服務器發送請求的時候,相應的cookie會自動的發送給對應的服務器。形成服務器不知道這個請求是用戶發起的仍是僞造的。這時候,咱們能夠在用戶每次訪問有表單頁面的時候,在網頁源碼中加一個隨機的字符串叫作csrf_token在cookie中也加入一個相同值的csrf_token字符串。之後給服務器發送請求的時候,必須在body中以及cookie中都攜帶 csrf_token,服務器只有檢測到cookie中的csrf_token和body中的csrf_token都相同,才認爲這個請求是正常的。不然就是僞造的,那麼黑客就沒辦法僞造請求了。html

 

Flask防護CSRF攻擊

使用flask_wtf.CSRFProtect來包裹appjquery

 

import os
from flask_wtf import CSRFProtect
app.config['SECRET_KEY'] = os.urandom(24) #和session同樣,必需要配置一個secret key參與加密
CSRFProtect(app)

 

而後在模板form表單中添加一個input標籤,加載csrf_tokenajax

<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>

 以上配置就可以在,用戶在提交表單後一併把表單中的csrf_token提交到服務器,並和服務器上的csrf_token作對比,這樣就可以識別請求是不是僞造的,從而避免CSRF攻擊flask

 

AJAX處理CSRF漏洞

若是咱們的表單是經過AJAX提交處理的。示例以下瀏覽器

<head>
    ...
    <!--咱們這裏的AJAX代碼是用JQuery寫的,所以要引入Jquery-->
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <!--AJAX代碼在login.js文件中-->
    <script src="{{ url_for('static', filename='login.js') }}"></script>
</head>


<body>
    <form action="" method="post">
        <table>
            <tr>
                <td>郵箱:</td>
                <td><input name="email" type="text" /></td>
            </tr>

            <tr>
                <td>密碼:</td>
                <td><input name="password" type="text" /></td>
            </tr>

            <tr>
                <td></td>
                <td><input type="submit" value="提交"  id="submit"/></td>
            </tr>
        </table>
    </form>
</body>
login.html

 login.js緩存

...

class LoginView(views.MethodView):
    def get(self):
        return render_template('login.html')

    def post(self):
        email = request.form.get('email')
        password = request.form.get('password')
        if email == 'heboan@qq.com' and password == '123456':
            return '登陸成功'
        else:
            return '登陸失敗'


app.add_url_rule('/login/', view_func=LoginView.as_view('login'))
login視圖

以上咱們已經成功使用了AJAX處理表單。如今咱們啓用CSRF,主程序中代碼以下:服務器

import os
from flask_wtf import CSRFProtect
app.config['SECRET_KEY'] = os.urandom(24) #和session同樣,必需要配置一個secret key參與加密
CSRFProtect(app)

而後咱們再次用正確的帳號密碼登陸,發現出現錯誤,由於咱們啓用防csrf攻擊,可是AJAX那裏並無攜帶csrf_token,因此請求失敗cookie

所以,咱們須要在login.html中添加一個表單用來存放tokensession

<form action="" method="post">
    <!--添加一個隱藏input用來放置csrf_token-->
    <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
    <table>
        <tr>
            <td>郵箱:</td>
            <td><input name="email" type="text" /></td>
        </tr>

        <tr>
            <td>密碼:</td>
            <td><input name="password" type="text" /></td>
        </tr>

        <tr>
            <td></td>
            <td><input type="submit" value="提交"  id="submit"/></td>
        </tr>
    </table>
</form>

編輯AJAX代碼段,把表單中的csrf_token傳給服務器做比對

再次登陸(強制刷新瀏覽器,由於js有緩存)

 

AJAX處理CSRF漏洞--優化代碼 

csrf_token能夠放置的head中。在實際項目中,咱們通常也是放在頭部,這樣作有個好處就是:當多處須要用到csrf_token,咱們就不須要屢次寫一個隱藏的csrf_token表單。特別是在模板繼承的時候,咱們只要在父模板中的head中加入csrf配置,其子模板就能夠直接繼承了。

編輯login.html

<head>
    <!--在head中加上此配置-->
    <meta name="csrf-token" content="{{ csrf_token() }}">
    ...
</head>


<!--表單中就不須要添加一個csrf_token表單了-->
<form action="" method="post">
    <table>
        <tr>
            <td>郵箱:</td>
            <td><input name="email" type="text" /></td>
        </tr>

        <tr>
            <td>密碼:</td>
            <td><input name="password" type="text" /></td>
        </tr>

        <tr>
            <td></td>
            <td><input type="submit" value="提交"  id="submit"/></td>
        </tr>
    </table>
</form>

 新建一個heboan_ajax.js, 來封裝

修改login.js

最後在login.html中要引入封裝的js

<head>
    ...
    <meta name="csrf_token" content="{{ csrf_token() }}">
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script src="{{ url_for('static', filename='heboan_ajax.js') }}"></script>
    <script src="{{ url_for('static', filename='login.js') }}"></script>

</head>

 

這樣實現的好處就是之後在其餘地方處理CSRF的時候,咱們直接把咱們封裝好的heboan_ajax拿來用就能夠了,模板那邊能夠經過繼承實現避免重複定義csrf_token表單和js引入

相關文章
相關標籤/搜索