<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## 模板繼承 用前面的方法,已經能夠很順利地編寫模板了。讀者如果留心一下,會覺得每個模板都有相同的部分內容。在python中,有一種被稱之為“繼承”的機制(請閱讀本教程第貳季第肆章中的[類(4)(./209.md)中有關“繼承”講述]),它的作用之一就是能夠讓代碼重用。 在tornado的模板中,也能這樣。 先建立一個文件,命名為base.html,代碼如下: ~~~ <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>Learning Python</title> </head> <body> <header> {% block header %}{% end %} </header> <content> {% block body %}{% end %} </content> <footer> {% set website = "<a href='http://www.itdiffer.com'>welcome to my website</a>" %} {% raw website %} </footer> <script src="{{static_url("js/jquery.min.js")}}"></script> <script src="{{static_url("js/script.js")}}"></script> </body> </html> ~~~ 接下來就以base.html為父模板,依次改寫已經有的index.html和user.html模板。 index.html代碼如下: ~~~ {% extends "base.html" %} {% block header %} <h2>登錄頁面</h2> <p>用用戶名為:{{user}}登錄</p> {% end %} {% block body %} <form method="POST"> <p><span>UserName:</span><input type="text" id="username"/></p> <p><span>Password:</span><input type="password" id="password" /></p> <p><input type="BUTTON" value="登錄" id="login" /></p> </form> {% end %} ~~~ user.html的代碼如下: ~~~ {% extends "base.html" %} {% block header %} <h2>Your informations are:</h2> {% end %} {% block body %} <ul> {% for one in users %} <li>username:{{one[1]}}</li> <li>password:{{one[2]}}</li> <li>email:{{one[3]}}</li> {% end %} </ul> {% end %} ~~~ 看以上代碼,已經沒有以前重復的部分了。`{% extends "base.html" %}`意味著以base.html為父模板。在base.html中規定了形式如同`{% block header %}{% end %}`這樣的塊語句。在index.html和user.html中,分別對塊語句中的內容進行了重寫(或者說填充)。這就相當于在base.html中做了一個結構,在子模板中按照這個結構填內容。 ## [](https://github.com/qiwsir/StarterLearningPython/blob/master/307.md#css)CSS 基本上的流程已經差不多了,如果要美化前端,還需要使用css,它的使用方法跟js類似,也是在靜態目錄中建立文件即可。然后把下面這句加入到base.html的`<head></head>`中: ~~~ <link rel="stylesheet" type="text/css" href="{{static_url("css/style.css")}}"> ~~~ 當然,要在style.css中寫一個樣式,比如: ~~~ body { color:red; } ~~~ 然后看看前端顯示什么樣子了,我這里是這樣的: [![](https://box.kancloud.cn/2015-09-07_55ed5dc7da395.png)](https://github.com/qiwsir/StarterLearningPython/blob/master/3images/30701.png) 關注字體顏色。 至于其它關于CSS方面的內容,本教程就不重點講解了。讀者可以參考關于CSS的資料。 至此,一個簡單的基于tornado的網站就做好了,雖然它很丑,但是它很有前途。因為讀者只要按照上述的討論,可以在里面增加各種自己認為可以增加的內容。 建議讀者在上述學習基礎上,可以繼續完成下面的幾個功能: * 用戶注冊 * 用戶發表文章 * 用戶文章列表,并根據文章標題查看文章內容 * 用戶重新編輯文章 在后續教程內容中,也會涉及到上述功能。 ## [](https://github.com/qiwsir/StarterLearningPython/blob/master/307.md#cookie和安全)cookie和安全 cookie是現在網站重要的內容,特別是當有用戶登錄的時候。所以,要了解cookie。維基百科如是說: > Cookie(復數形態Cookies),中文名稱為小型文字檔案或小甜餅,指某些網站為了辨別用戶身份而儲存在用戶本地終端(Client Side)上的數據(通常經過加密)。定義於RFC2109。是網景公司的前雇員Lou Montulli在1993年3月的發明。 關于cookie的作用,維基百科已經說的非常詳細了(讀者還能正常訪問這么偉大的網站嗎?): > 因為HTTP協議是無狀態的,即服務器不知道用戶上一次做了什么,這嚴重阻礙了交互式Web應用程序的實現。在典型的網上購物場景中,用戶瀏覽了幾個頁面,買了一盒餅干和兩瓶飲料。最后結帳時,由于HTTP的無狀態性,不通過額外的手段,服務器并不知道用戶到底買了什么。 所以Cookie就是用來繞開HTTP的無狀態性的“額外手段”之一。服務器可以設置或讀取Cookies中包含信息,借此維護用戶跟服務器會話中的狀態。 > > 在剛才的購物場景中,當用戶選購了第一項商品,服務器在向用戶發送網頁的同時,還發送了一段Cookie,記錄著那項商品的信息。當用戶訪問另一個頁面,瀏覽器會把Cookie發送給服務器,于是服務器知道他之前選購了什么。用戶繼續選購飲料,服務器就在原來那段Cookie里追加新的商品信息。結帳時,服務器讀取發送來的Cookie就行了。 > > Cookie另一個典型的應用是當登錄一個網站時,網站往往會請求用戶輸入用戶名和密碼,并且用戶可以勾選“下次自動登錄”。如果勾選了,那么下次訪問同一網站時,用戶會發現沒輸入用戶名和密碼就已經登錄了。這正是因為前一次登錄時,服務器發送了包含登錄憑據(用戶名加密碼的某種加密形式)的Cookie到用戶的硬盤上。第二次登錄時,(如果該Cookie尚未到期)瀏覽器會發送該Cookie,服務器驗證憑據,于是不必輸入用戶名和密碼就讓用戶登錄了。 和任何別的事物一樣,cookie也有缺陷,比如來自偉大的維基百科也列出了三條: 1. cookie會被附加在每個HTTP請求中,所以無形中增加了流量。 2. 由于在HTTP請求中的cookie是明文傳遞的,所以安全性成問題。(除非用HTTPS) 3. Cookie的大小限制在4KB左右。對于復雜的存儲需求來說是不夠用的。 對于用戶來講,可以通過改變瀏覽器設置,來禁用cookie,也可以刪除歷史的cookie。但就目前而言,禁用cookie的可能不多了,因為她總要在網上買點東西吧。 Cookie最讓人擔心的還是由于它存儲了用戶的個人信息,并且最終這些信息要發給服務器,那么它就會成為某些人的目標或者工具,比如有cookie盜賊,就是搜集用戶cookie,然后利用這些信息進入用戶賬號,達到個人的某種不可告人之目的;還有被稱之為cookie投毒的說法,是利用客戶端的cookie傳給服務器的機會,修改傳回去的值。這些行為常常是通過一種被稱為“跨站指令腳本(Cross site scripting)”(或者跨站指令碼)的行為方式實現的。偉大的維基百科這樣解釋了跨站腳本: > 跨網站腳本(Cross-site scripting,通常簡稱為XSS或跨站腳本或跨站腳本攻擊)是一種網站應用程序的安全漏洞攻擊,是代碼注入的一種。它允許惡意用戶將代碼注入到網頁上,其他用戶在觀看網頁時就會受到影響。這類攻擊通常包含了HTML以及用戶端腳本語言。 > > XSS攻擊通常指的是通過利用網頁開發時留下的漏洞,通過巧妙的方法注入惡意指令代碼到網頁,使用戶加載并執行攻擊者惡意制造的網頁程序。這些惡意網頁程序通常是JavaScript,但實際上也可以包括Java, VBScript, ActiveX, Flash 或者甚至是普通的HTML。攻擊成功后,攻擊者可能得到更高的權限(如執行一些操作)、私密網頁內容、會話和cookie等各種內容。 cookie是好的,被普遍使用。在tornado中,也提供對cookie的讀寫函數。 `set_cookie()`和`get_cookie()`是默認提供的兩個方法,但是它是明文不加密傳輸的。 在index.py文件的IndexHandler類的post()方法中,當用戶登錄,驗證用戶名和密碼后,將用戶名和密碼存入cookie,代碼如下: def post(self): username = self.get_argument("username") password = self.get_argument("password") user_infos = mrd.select_table(table="users",column="*",condition="username",value=username) if user_infos: db_pwd = user_infos[0][2] if db_pwd == password: self.set_cookie(username,db_pwd) #設置cookie self.write(username) else: self.write("your password was not right.") else: self.write("There is no thi user.") 上面代碼中,較以前只增加了一句`self.set_cookie(username,db_pwd)`,在回到登錄頁面,等候之后就成為: [![](https://box.kancloud.cn/2015-09-07_55ed5dca71b85.png)](https://github.com/qiwsir/StarterLearningPython/blob/master/3images/30702.png) 看圖中箭頭所指,從左開始的第一個是用戶名,第二個是存儲的該用戶密碼。將我在登錄是的密碼就以明文的方式存儲在cookie里面了。 明文存儲,顯然不安全。 tornado提供另外一種安全的方法:set_secure_cookie()和get_secure_cookie(),稱其為安全cookie,是因為它以明文加密方式傳輸。此外,跟set_cookie()的區別還在于, set_secure_cookie()執行后的cookie保存在磁盤中,直到它過期為止。也是因為這個原因,即使關閉瀏覽器,在失效時間之間,cookie都一直存在。 要是用set_secure_cookie()方法設置cookie,要先在application.py文件的setting中進行如下配置: ~~~ setting = dict( template_path = os.path.join(os.path.dirname(__file__), "templates"), static_path = os.path.join(os.path.dirname(__file__), "statics"), cookie_secret = "bZJc2sWbQLKos6GkHn/VB9oXwQt8S0R0kRvJ5/xJ89E=", ) ~~~ 其中`cookie_secret = "bZJc2sWbQLKos6GkHn/VB9oXwQt8S0R0kRvJ5/xJ89E="`是為此增加的,但是,它并不是這正的加密,僅僅是一個障眼法罷了。 因為tornado會將cookie值編碼為Base-64字符串,并增加一個時間戳和一個cookie內容的HMAC簽名。所以,cookie_secret的值,常常用下面的方式生成(這是一個隨機的字符串): ~~~ >>> import base64, uuid >>> base64.b64encode(uuid.uuid4().bytes) 'w8yZud+kRHiP9uABEXaQiA==' ~~~ 如果嫌棄上面的簽名短,可以用`base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes)`獲取。這里得到的是一個隨機字符串,用它作為 cookie_secret值。 然后修改index.py中設置cookie那句話,變成: ~~~ self.set_secure_cookie(username,db_pwd) ~~~ 從新跑一個,看看效果。 [![](https://box.kancloud.cn/2015-09-07_55ed5dd48cf15.png)](https://github.com/qiwsir/StarterLearningPython/blob/master/3images/30703.png) 啊哈,果然“密”了很多。 如果要獲取此cookie,用`self.get_secure_cookie(username)`即可。 這是不是就安全了。如果這樣就安全了,你太低估黑客們的技術實力了,甚至于用戶自己也會修改cookie值。所以,還不安全。所以,又有了httponly和secure屬性,用來防范cookie投毒。設置方法是: ~~~ self.set_secure_cookie(username, db_pwd, httponly=True, secure=True) ~~~ 要獲取cookie,可以使用`self.set_secure_cookie(username)`方法,將這句放在user.py中某個適合的位置,并且可以用print語句打印出結果,就能看到變量username對應的cookie了。這時候已經不是那個“密”過的,是明文顯示。 用這樣的方法,瀏覽器通過SSL連接傳遞cookie,能夠在一定程度上防范跨站腳本攻擊。 ## [](https://github.com/qiwsir/StarterLearningPython/blob/master/307.md#xsrf)XSRF XSRF的含義是Cross-site request forgery,即跨站請求偽造,也稱之為"one click attack",通常縮寫成CSRF或者XSRF,可以讀作"sea surf"。這種對網站的攻擊方式跟上面的跨站腳本(XSS)似乎相像,但攻擊方式不一樣。XSS利用站點內的信任用戶,而XSRF則通過偽裝來自受信任用戶的請求來利用受信任的網站。與XSS攻擊相比,XSRF攻擊往往不大流行(因此對其 進行防范的資源也相當稀少)和難以防范,所以被認為比XSS更具危險性。 讀者要詳細了解XSRF,推薦閱讀:[CSRF | XSRF 跨站請求偽造](http://www.cnblogs.com/lsk/archive/2008/05/26/1207467.html) 對于防范XSRF的方法,上面推薦閱讀的文章中有明確的描述。還有一點需要提醒讀者,就是在開發應用時需要深謀遠慮。任何會產生副作用的HTTP請求,比如點擊購買按鈕、編輯賬戶設置、改變密碼或刪除文檔,都應該使用post()方法。這是良好的RESTful做法。 > 又一個新名詞:REST。這是一種web服務實現方案。偉大的維基百科中這樣描述: > > 表徵性狀態傳輸(英文:Representational State Transfer,簡稱REST)是Roy Fielding博士在2000年他的博士論文中提出來的一種軟件架構風格。目前在三種主流的Web服務實現方案中,因為REST模式與復雜的SOAP和XML-RPC相比更加簡潔,越來越多的web服務開始采用REST風格設計和實現。例如,Amazon.com提供接近REST風格的Web服務進行圖書查找;雅虎提供的Web服務也是REST風格的。 > > 更詳細的內容,讀者可網上搜索來了解。 此外,在tornado中,還提供了XSRF保護的方法。 在application.py文件中,使用xsrf_cookies參數開啟XSRF保護。 ~~~ setting = dict( template_path = os.path.join(os.path.dirname(__file__), "templates"), static_path = os.path.join(os.path.dirname(__file__), "statics"), cookie_secret = "bZJc2sWbQLKos6GkHn/VB9oXwQt8S0R0kRvJ5/xJ89E=", xsrf_cookies = True, ) ~~~ 這樣設置之后,Tornado將拒絕請求參數中不包含正確的`_xsrf`值的post/put/delete請求。tornado會在后面悄悄地處理`_xsrf`?cookies,所以,在表單中也要包含XSRF令牌以卻表請求合法。比如index.html的表單,修改如下: ~~~ {% extends "base.html" %} {% block header %} <h2>登錄頁面</h2> <p>用用戶名為:{{user}}登錄</p> {% end %} {% block body %} <form method="POST"> {% raw xsrf_form_html() %} <p><span>UserName:</span><input type="text" id="username"/></p> <p><span>Password:</span><input type="password" id="password" /></p> <p><input type="BUTTON" value="登錄" id="login" /></p> </form> {% end %} ~~~ `{% raw xsrf_form_html() %}`是新增的,目的就在于實現上面所說的授權給前端以合法請求。 前端向后端發送的請求是通過ajax(),所以,在ajax請求中,需要一個_xsrf參數。 以下是script.js的代碼 ~~~ function getCookie(name){ var x = document.cookie.match("\\b" + name + "=([^;]*)\\b"); return x ? x[1]:undefined; } $(document).ready(function(){ $("#login").click(function(){ var user = $("#username").val(); var pwd = $("#password").val(); var pd = {"username":user, "password":pwd, "_xsrf":getCookie("_xsrf")}; $.ajax({ type:"post", url:"/", data:pd, cache:false, success:function(data){ window.location.href = "/user?user="+data; }, error:function(){ alert("error!"); }, }); }); }); ~~~ 函數getCookie()的作用是得到cookie值,然后將這個值放到向后端post的數據中`var pd = {"username":user, "password":pwd, "_xsrf":getCookie("_xsrf")};`。運行的結果: [![](https://box.kancloud.cn/2015-09-07_55ed5ddfc2940.png)](https://github.com/qiwsir/StarterLearningPython/blob/master/3images/30704.png) 這是tornado提供的XSRF防護方法。是不是這樣做就高枕無憂了呢?**沒這么簡單。要做好一個網站,需要考慮的事情還很多**。特別推薦閱讀[WebAppSec/Secure Coding Guidelines](https://wiki.mozilla.org/WebAppSec/Secure_Coding_Guidelines) 常常聽到人說做個網站怎么怎么簡單,客戶用這種說辭來壓低價格,老板用這種說辭來縮短工時成本,從上面的簡單敘述中,你覺得網站還是隨便幾個頁面就完事了嗎?除非那個網站不是給人看的,是在那里擺著的。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看