Tornado框架08-應用安全

01-Cookie

普通cookie

1.設置

原型

self.set_cookie(name,value,domain=None,expires=None,path="/",expires_days=None,**kwargs)

參數

屬性 作用
name cookie的名稱
value cookie值
domain 提交cookie時匹配的域名
path 提交cookie時匹配的路徑
expires 設置cookie的有效期,可以是時間戳、事件元組、或者datetime類型對象。
expires_days 設置cookie的有效期天數,優先級低於expries

實例

class SetpCookieHandler(RequestHandler):
    def get(self, *args, **kwargs):
        self.set_cookie("sunck","good")
        self.set_header("Set-Cookie", "kaige=nice; Path=/")
        self.write("ok")

2.原理

設置cookie實際上是通過該設置header的Set-Cookie來實現的

3.獲取

原型:

self.get_cookie(name,default=None)

作用

獲取名爲name的cookie的值,如果name不存在且設置了default屬性,則返回default的值

實例

class GetCookieHandler(RequestHandler):
    def get(self, *args, **kwargs):
        cookie = self.get_cookie("sunck")
        self.write(cookie)

4.清除

清除名爲name,並同時匹配domain和path的cookie

self.clear_cookie(name,path="/",domain=None)

清除同時匹配domino的和path的cookie

self.clear_all_cookies(path='/',domain=None)

注意:

執行清除操作後,並不是立即刪除瀏覽器中的cookie,而是給cookie值設置爲空,並改變其有效期爲失效。真正的刪除是有瀏覽器去管理的

安全cookie

1.概述

Cookie是存儲在客戶端瀏覽器上,很容易被篡改。

Tornado提供了一種相對於安全的方案,對cookie進行簡易加密(用簽名的方法),防止cookie被隨意的篡改

2.設置

需要配置一個用來給Cookie進行混淆的祕鑰

"cookie_secret":"HTqWqcJpRA6Js2kPEQVIy9CvgddvPk1RhmsQMGmqzC8="

設置一個帶簽名和時間戳的cookie

self.set_secure_cookie(name,value,expires_days=30,version=None,**kwargs)

實例

class SetsCookieHandler(RequestHandler):
    def get(self, *args, **kwargs):
        self.set_secure_cookie("liudehua","buru sunck handsome")
        self.write("OK")

3.值

"2|1:0|10:1508307760|8:liudehua|28:YnVydSBzdW5jayBoYW5kc29tZQ==|057d78aa76d44b47636b96b7925323238a14778b1216e78297613689e3a47ac0"

安全cookie的版本,默認使用的第2版
默認爲0
時間戳
cookie名
base64編碼的cookie值
簽名值,不帶長度前綴

4.獲取

self.get_secure_cookie(name=,value=None,max_age_days=31,min_version=None)

功能:

如果cookie存在且驗證通過,返回cookie的值,否則返回None

參數:不同於expries_days,max_age_days是過濾安全cookie的時間戳

max_age_days

實例

class GetsCookieHandler(RequestHandler):
    def get(self, *args, **kwargs):
        cookie = self.get_secure_cookie("liudehua")
        self.write(cookie)

02-XSRF

跨站請求僞造

當訪問“搞事情”網站時,在我們不知道的情況下“計數器”網站的cookie被使用。以至於讓服務器認爲是“計數器”在訪問

在這裏使用的是GET方式模擬的跨站攻擊,爲了防範跨站攻擊,任何會產生副作用的HTTP請求(點擊添加購物車、編輯用戶信息、修改密碼等操作),都是用POST請求。有保護POST請求的策略

class CookieNumHandler(RequestHandler):
    def get(self, *args, **kwargs):
        count = self.get_cookie("count", "0")
        count = str(int(count) + 1)
        self.set_cookie("count", count)
        self.render('cookienum.html', count=count)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>搞事情</title>
</head>
<body>
    <img src="http://127.0.0.1:8000/cookienum" alt="">
    <h1>我在搞事情,去看看吧</h1>
</body>
</html>

XSRF保護

同源策略:所謂同源是指,域名,協議,端口相同。 不同源的客戶端腳本(javascript、ActionScript)在沒明確授權的情況下,不能讀寫對方的資源。
由於第三方站點沒有訪問cookie數據的權限(同源策略),所以我們可以要求每個請求包括一個特定的參數值作爲令牌來匹配存儲在cookie中的對應值,如果兩者匹配,我們的應用認定請求有效。而第三方站點無法在請求中包含令牌cookie值,這就有效地防止了不可信網站發送未授權的請求。

開啓XSRF

在配置中添加‘xsrf_cookie’:True

"xsrf_cookie":True,

應用

模板中:
爲瀏覽器設置的_xsrf的cookie(注意:該cookie會在瀏覽器關閉後失效)

爲模板的表達式中添加了一個隱藏的輸入域,name屬性爲_xsrf,value屬性爲名爲_xsrf的cookie的值

<body>
    <form action="/postfile" method="post">
        {% module xsrf_form_html() %}
        姓名:<input type="text" name="username"/>
        <hr/>
        密碼:<input type="password" name="passwd"/>
        <input type="submit" value="登陸"/>
    </form>
</body>

非模板中

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" charset="utf-8" src="{{static_url('js/jquery.min.js')}}"></script>
</head>
<body>
    姓名:<input id="name" type="text" name="username"/>
    <hr/>
    密碼:<input id="pass" type="password" name="passwd"/>
    <button onclick="login()">登陸</button>

    <script>
        function getCookie(name){
            var cook = document.cookie.match("\\b"+name+"=([^;]*\\b)")
            return cook ? cook[1] : undefined
        }
        function login(){
            $.post("/postfile", "_xsrf=" + getCookie("_xsrf")+"&username=sunck&passwd=123", function(data){
                alert("OK")
            })
        }
    </script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" charset="utf-8" src="{{static_url('js/jquery.min.js')}}"></script>
</head>
<body>
    姓名:<input id="name" type="text" name="username"/>
    <hr/>
    密碼:<input id="pass" type="password" name="passwd"/>
    <button onclick="login()">登陸</button>

    <script>
        function getCookie(name){
            var cook = document.cookie.match("\\b"+name+"=([^;]*\\b)")
            return cook ? cook[1] : undefined
        }
        function login(){
            info = {
                "username":"kaige",
                "age":19
            }
            jsonInfo = JSON.stringify(info)
            $.ajax({
                url:"/postfile",
                method:"POST",
                data:jsonInfo,
                success:function(data){
                    alert("OK2")
                },
                headers:{
                    "X-XSRFToken":getCookie("_xsrf")
                }
            })
        }
    </script>
</body>
</html>

需要在進入主頁時就自動設置_xsrf的cookie,可以通過定義tornado.web.StaticFileHandler子類而實現

class StaticFileHandler(tornado.web.StaticFileHandler):
    def __init__(self, *args, **kwargs):
        super(StaticFileHandler,self).__init__(*args, **kwargs)
        self.xsrf_token

03-用戶驗證

在受到用戶的請求後進行預處理驗證用戶的登陸狀態,通過驗證正常處理,否則強制用戶跳轉到登錄界面

確保修飾的方法只有在驗證合法纔可以被調用

@tornado.web.authenticated裝飾器

驗證用戶的邏輯寫在該方法中,如果返回True說明驗證成功
如果返回False,說明驗證失敗。驗證失敗會重定向到配置文件中login_url所指定的路由上

get_current_user()方法
"login_url":"/login"

實例

class HomeHandler(RequestHandler):
    def get_current_user(self):
        flag = self.get_argument("flag", None)
        return flag
    @tornado.web.authenticated
    def get(self, *args, **kwargs):
        self.render('home.html')
class CartHandler(RequestHandler):
    def get_current_user(self):
        flag = self.get_argument("flag", None)
        return flag
    @tornado.web.authenticated
    def get(self, *args, **kwargs):
        self.render('cart.html')
class loginHandler(RequestHandler):
    def get(self, *args, **kwargs):
        next = self.get_argument("next", "/")
        url = "/login?next=" + next
        self.render('login.html', url=url)
    def post(self, *args, **kwargs):
        name = self.get_argument("username")
        pswd = self.get_argument("passwd")
        if name == "sunck" and pswd == "1234567890a":
            #登陸成功,哪裏來哪裏去
            next = self.get_argument("next", "/")
            self.redirect(next+"?flag=logined")
        else:
            #登陸失敗,還嘚瑟啥
            next = self.get_argument("next", "/")
            self.redirect('/login?next='+next)
發佈了48 篇原創文章 · 獲贊 4 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章