The Internet can be a scary place.
Internet骞朵笉瀹夊叏銆
These days, high-profile security gaffes seem to crop up on a daily basis. Weve seen viruses spread with amazing speed, swarms of compromised computers wielded as weapons, a never-ending arms race against spammers, and many, many reports of identify theft from hacked Web sites.
鐜板浠婏紝姣忓ぉ閮戒細鍑虹幇鏂扮殑瀹夊叏闂銆傛垜浠洰鐫硅繃鐥呮瘨椋為熷湴钄撳欢锛屽ぇ閲忚鎺у埗鐨勮倝楦′綔涓烘鍣ㄦ潵鏀诲嚮鍏朵粬浜猴紝涓庡瀮鍦鹃偖浠剁殑姘告棤姝㈠鐨勫啗澶囩珵璧涳紝浠ュ強璁歌澶氬绔欑偣琚粦鐨勬姤鍛娿
As Web developers, we have a duty to do what we can to combat these forces of darkness. Every Web developer needs to treat security as a fundamental aspect of Web programming. Unfortunately, it turns out that implementing security is hard attackers need to find only a single vulnerability, but defenders have to protect every single one.
浣滀负web寮鍙戜汉鍛橈紝鎴戜滑鏈夎矗浠绘潵瀵规姉杩欎簺榛戞殫鐨勫姏閲忋傛瘡涓涓獁eb寮鍙戣呴兘搴旇鎶婂畨鍏ㄧ湅鎴愭槸web缂栫▼涓殑鍩虹閮ㄥ垎銆備笉骞哥殑鏄紝瑕佸疄鐜板畨鍏ㄦ槸鍥伴毦鐨勩傛敾鍑昏呭彧闇瑕佹壘鍒颁竴涓井灏忕殑钖勫急鐜妭锛岃岄槻瀹堟柟鍗磋淇濇姢寰楅潰闈勘鍒般
Django attempts to mitigate this difficulty. Its designed to automatically protect you from many of the common security mistakes that new (and even experienced) Web developers make. Still, its important to understand what these problems are, how Django protects you, and most important the steps you can take to make your code even more secure.
Django璇曞浘鍑忚交杩欑闅惧害銆傚畠琚璁′负鑷姩甯綘閬垮厤涓浜泈eb寮鍙戞柊鎵嬶紙鐢氳嚦鏄佹墜锛夌粡甯镐細鐘殑閿欒銆傚敖绠″姝わ紝闇瑕佸紕娓呮锛孌jango濡備綍淇濇姢鎴戜滑锛屼互鍙婃垜浠彲浠ラ噰鍙栧摢浜涢噸瑕佺殑鏂规硶鏉ヤ娇寰楁垜浠殑浠g爜鏇村姞瀹夊叏銆
First, though, an important disclaimer: We do not intend to present a definitive guide to every known Web security exploit, and so we wont try to explain each vulnerability in a comprehensive manner. Instead, well give a short synopsis of security problems as they apply to Django.
棣栧厛锛屼竴涓噸瑕佺殑鍓嶆彁锛氭垜浠苟涓嶆墦绠楃粰鍑簑eb瀹夊叏鐨勪竴涓灏界殑璇存槑锛屽洜姝ゆ垜浠篃涓嶄細璇︾粏鍦拌В閲婃瘡涓涓杽寮辩幆鑺傘傚湪杩欓噷锛屾垜浠細缁欏嚭Django鎵闈复鐨勫畨鍏ㄩ棶棰樼殑涓涓ぇ姒傘
If you learn only one thing from this chapter, let it be this:
濡傛灉浣犱粠杩欑珷涓彧瀛﹀埌浜嗕竴浠朵簨鎯咃紝閭d箞瀹冧細鏄細
Never under any circumstances trust data from the browser.
鍦ㄤ换浣曟潯浠朵笅閮戒笉瑕佺浉淇℃祻瑙堝櫒绔彁浜ょ殑鏁版嵁銆
You never know whos on the other side of that HTTP connection. It might be one of your users, but it just as easily could be a nefarious cracker looking for an opening.
浣犱粠涓嶄細鐭ラ亾HTTP杩炴帴鐨勫彟涓绔細鏄皝銆傚彲鑳芥槸涓涓甯哥殑鐢ㄦ埛锛屼絾鏄悓鏍峰彲鑳芥槸涓涓鎵炬紡娲炵殑閭伓鐨勯獓瀹€
Any data of any nature that comes from the browser needs to be treated with a healthy dose of paranoia. This includes data thats both in band (i.e., submitted from Web forms) and out of band (i.e., HTTP headers, cookies, and other request information). Its trivial to spoof the request metadata that browsers usually add automatically.
浠庢祻瑙堝櫒浼犺繃鏉ョ殑浠讳綍鎬ц川鐨勬暟鎹紝閮介渶瑕佽繎涔庣媯鐑湴鎺ュ彈妫鏌ャ傝繖鍖呮嫭鐢ㄦ埛鏁版嵁锛堟瘮濡倃eb琛ㄥ崟鎻愪氦鐨勫唴瀹癸級鍜屽甫澶栨暟鎹紙姣斿锛孒TTP澶淬乧ookies浠ュ強鍏朵粬淇℃伅锛夈傝淇敼閭d簺娴忚鍣ㄨ嚜鍔ㄦ坊鍔犵殑鍏冩暟鎹紝鏄竴浠跺緢瀹规槗鐨勪簨銆
Every one of the vulnerabilities discussed in this chapter stems directly from trusting data that comes over the wire and then failing to sanitize that data before using it. You should make it a general practice to continuously ask, Where does this data come from?
鍦ㄨ繖涓绔犳墍鎻愬埌鐨勬墍鏈夌殑瀹夊叏闅愭偅閮界洿鎺ユ簮鑷浼犲叆鏁版嵁鐨勪俊浠伙紝骞朵笖鍦ㄤ娇鐢ㄥ墠涓嶅姞澶勭悊銆備綘闇瑕佷笉鏂湴闂嚜宸憋紝杩欎簺鏁版嵁浠庝綍鑰屾潵銆
SQL娉ㄥ叆
SQL injection is a common exploit in which an attacker alters Web page parameters (such as GET /POST data or URLs) to insert arbitrary SQL snippets that a naive Web application executes in its database directly. Its probably the most dangerous and, unfortunately, one of the most common vulnerabilities out there.
SQL娉ㄥ叆 鏄竴涓緢甯歌鐨勫舰寮忥紝鍦⊿QL娉ㄥ叆涓紝鏀诲嚮鑰呮敼鍙榳eb缃戦〉鐨勫弬鏁帮紙渚嬪 GET /POST 鏁版嵁鎴栬匲RL鍦板潃锛夛紝鍔犲叆涓浜涘叾浠栫殑SQL鐗囨銆傛湭鍔犲鐞嗙殑缃戠珯浼氬皢杩欎簺淇℃伅鍦ㄥ悗鍙版暟鎹簱鐩存帴杩愯銆傝繖涔熻鏄渶鍗遍櫓鐨勪竴绉嶏紝鐒惰屼笉骞哥殑鏄紝涔熸槸鏈澶氱殑涓绉嶉殣鎮c
This vulnerability most commonly crops up when constructing SQL by hand from user input. For example, imagine writing a function to gather a list of contact information from a contact search page. To prevent spammers from reading every single email in our system, well force the user to type in someones username before providing her email address:
杩欑鍗遍櫓閫氬父鍦ㄧ敱鐢ㄦ埛杈撳叆鏋勯燬QL璇彞鏃朵骇鐢熴備緥濡傦紝鍋囪鎴戜滑瑕佸啓涓涓嚱鏁帮紝鐢ㄦ潵浠庨氫俊褰曟悳绱㈤〉闈㈡敹闆嗕竴绯诲垪鐨勮仈绯讳俊鎭備负闃叉鍨冨溇閭欢鍙戦佸櫒闃呰绯荤粺涓殑email锛屾垜浠皢鍦ㄦ彁渚沞mail鍦板潃浠ュ墠锛岄鍏堝己鍒剁敤鎴疯緭鍏ョ敤鎴峰悕銆
def user_contacts(request): user = request.GET['username'] sql = "SELECT * FROM user_contacts WHERE username = '%s';" % username # execute the SQL here...
Note
澶囨敞
In this example, and all similar dont do this examples that follow, weve deliberately left out most of the code needed to make the functions actually work. We dont want this code to work if someone accidentally takes it out of context.
鍦ㄨ繖涓緥瀛愪腑锛屼互鍙婂湪浠ヤ笅鎵鏈夌殑鈥滀笉瑕佽繖鏍峰仛鈥濈殑渚嬪瓙閲岋紝鎴戜滑閮藉幓闄や簡澶ч噺鐨勪唬鐮侊紝閬垮厤杩欎簺鍑芥暟鍙互姝e父宸ヤ綔銆傛垜浠彲涓嶆兂杩欎簺渚嬪瓙琚嬁鍑哄幓浣跨敤銆
Though at first this doesnt look dangerous, it really is.
灏界锛屼竴鐪肩湅涓婂幓锛岃繖涓鐐归兘涓嶅嵄闄╋紝瀹為檯涓婂嵈涓嶅敖鐒躲
First, our attempt at protecting our entire email list will fail with a cleverly constructed query. Think about what happens if an attacker types "' OR 'a'='a" into the query box. In that case, the query that the string interpolation will construct will be:
棣栧厛锛屾垜浠浜庝繚鎶mail鍒楄〃鎵閲囧彇鐨勬帾鏂斤紝閬囧埌绮惧績鏋勯犵殑鏌ヨ璇彞灏变細澶辨晥銆傛兂璞′竴涓嬶紝濡傛灉鏀诲嚮鑰呭湪鏌ヨ妗嗕腑杈撳叆 "' OR 'a'='a" 銆傛鏃讹紝鏌ヨ鐨勫瓧绗︿覆浼氭瀯閫犲涓嬶細
SELECT * FROM user_contacts WHERE username = '' OR 'a' = 'a';
Because we allowed unsecured SQL into the string, the attackers added OR clause ensures that every single row is returned.
鐢变簬鎴戜滑鍏佽涓嶅畨鍏ㄧ殑SQL璇彞鍑虹幇鍦ㄥ瓧绗︿覆涓紝鏀诲嚮鑰呭姞鍏 OR 瀛愬彞锛屼娇寰楁瘡涓琛屾暟鎹兘琚繑鍥炪
However, thats the least scary attack. Imagine what will happen if the attacker submits "'; DELETE FROM user_contacts WHERE 'a' = 'a'" . Well end up with this complete query:
浜嬪疄涓婏紝杩欐槸鏈娓╁拰鐨勬敾鍑绘柟寮忋傚鏋滄敾鍑昏呮彁浜や簡 "'; DELETE FROM user_contacts WHERE 'a' = 'a'" 锛屾垜浠渶缁堝皢寰楀埌杩欐牱鐨勬煡璇細
SELECT * FROM user_contacts WHERE username = ''; DELETE FROM user_contacts WHERE 'a' = 'a';
Yikes! Whered our contact list go?
鍝︼紒鎴戜滑鏁翠釜閫氫俊褰曞悕鍗曞幓鍝効浜嗭紵
Although this problem is insidious and sometimes hard to spot, the solution is simple: never trust user-submitted data, and always escape it when passing it into SQL.
灏界杩欎釜闂寰堥槾闄╋紝骞朵笖鏈夋椂寰堥毦鍙戠幇锛岃В鍐虫柟娉曞嵈寰堢畝鍗曪細 缁濅笉淇′换鐢ㄦ埛鎻愪氦鐨勬暟鎹紝骞朵笖鍦ㄤ紶閫掔粰SQL璇彞鏃讹紝鎬绘槸杞箟瀹冦
The Django database API does this for you. It automatically escapes all special SQL parameters, according to the quoting conventions of the database server youre using (e.g., PostgreSQL or MySQL).
20ILMD <a href=”http://ttrjghnexixr.com/“>ttrjghnexixr</a>, [url=http://uasrdouyximt.com/]uasrdouyximt[/url], [link=http://xhsyxhkdudmy.com/]xhsyxhkdudmy[/link], http://udcefujhrbii.com/
For example, in this API call:
涓句釜渚嬪瓙锛屽湪涓嬮潰杩欎釜API璋冪敤涓細
foo.get_list(bar__exact="' OR 1=1")
Django will escape the input accordingly, resulting in a statement like this:
Django浼氳嚜鍔ㄨ繘琛岃浆涔夛紝寰楀埌濡備笅琛ㄨ揪锛
SELECT * FROM foos WHERE bar = '\' OR 1=1'
Completely harmless.
瀹屽叏鏃犲銆
This applies to the entire Django database API, with a couple of exceptions:
杩欒杩愮敤鍒颁簡鏁翠釜Django鐨勬暟鎹簱API涓紝鍙湁涓浜涗緥澶栵細
The where argument to the extra() method (see Appendix C). That parameter accepts raw SQL by design.
浼犵粰 extra() 鏂规硶鐨 where 鍙傛暟锛堝弬瑙侀檮褰旵锛夈傝繖涓弬鏁版帴鍙楀師濮嬬殑SQL璇彞銆
Queries done by hand using the lower-level database API.
浣跨敤搴曞眰鏁版嵁搴揂PI鐨勬煡璇€
In each of these cases, its easy to keep yourself protected. In each case, avoid string interpolation in favor of passing in bind parameters . That is, the example we started this section with should be written as follows:
浠ヤ笂鍒椾妇鐨勬瘡涓涓ず渚嬮兘鑳藉寰堝鏄撶殑璁╂偍鐨勫簲鐢ㄥ緱鍒颁繚鎶ゃ傚湪姣忎竴涓ず渚嬩腑锛屼负浜嗛伩鍏嶅瓧绗︿覆琚鏀硅屼娇鐢 缁戝畾鍙傛暟 鏉ヤ唬鏇裤備篃灏辨槸璇达紝鍦ㄦ湰绔犱腑鎴戜滑浣跨敤鍒扮殑鎵鏈夌ず渚嬮兘搴旇鍐欐垚濡備笅鎵绀猴細
from django.db import connection def user_contacts(request): user = request.GET['username'] sql = "SELECT * FROM user_contacts WHERE username = %s;" cursor = connection.cursor() cursor.execute(sql, [user]) # ... do something with the results
The low-level execute method takes a SQL string with %s placeholders and automatically escapes and inserts parameters from the list passed as the second argument. You should always construct custom SQL this way.
搴曞眰 execute 鏂规硶閲囩敤浜嗕竴涓猄QL瀛楃涓蹭綔涓哄叾绗簩涓弬鏁帮紝杩欎釜SQL瀛楃涓插寘鍚嫢骞’%s’鍗犱綅绗︼紝execute鏂规硶鑳藉鑷姩瀵逛紶鍏ュ垪琛ㄤ腑鐨勫弬鏁拌繘琛岃浆涔夊拰鎻掑叆銆
Unfortunately, you cant use bind parameters everywhere in SQL; theyre not allowed as identifiers (i.e., table or column names). Thus, if you need to, say, dynamically construct a list of tables from a POST variable, youll need to escape that name in your code. Django provides a function, django.db.backend.quote_name , which will escape the identifier according to the current databases quoting scheme.
涓嶅垢鐨勬槸锛屾偍骞朵笉鏄湪SQL涓兘澶熷澶勯兘浣跨敤缁戝畾鍙傛暟锛岀粦瀹氬弬鏁颁笉鑳藉浣滀负鏍囪瘑绗︼紙濡傝〃鎴栧垪鍚嶇瓑锛夈傚洜姝わ紝濡傛灉鎮ㄩ渶瑕佽繖鏍峰仛—鎴戞槸璇—鍔ㄦ佹瀯寤 POST 鍙橀噺涓殑鏁版嵁搴撹〃鐨勫垪琛ㄧ殑璇濓紝鎮ㄩ渶瑕佸湪鎮ㄧ殑浠g爜涓潵瀵硅繖浜涙暟鎹簱琛ㄧ殑鍚嶅瓧杩涜杞箟銆侱jango鎻愪緵浜嗕竴涓嚱鏁帮紝 django.db.backend.quote_name 锛岃繖涓嚱鏁拌兘澶熸牴鎹綋鍓嶆暟鎹簱寮曠敤缁撴瀯瀵硅繖浜涙爣璇嗙杩涜杞箟銆
Cross-site scripting (XSS), is found in Web applications that fail to escape user-submitted content properly before rendering it into HTML. This allows an attacker to insert arbitrary HTML into your Web page, usually in the form of <script> tags.
鍦╓eb搴旂敤涓紝 璺ㄧ珯鐐硅剼鏈 (XSS)鏈夋椂鍦ㄨ娓叉煋鎴怘TML涔嬪墠锛屼笉鑳芥伆褰撳湴瀵圭敤鎴锋彁浜ょ殑鍐呭杩涜杞箟銆傝繖浣垮緱鏀诲嚮鑰呰兘澶熷悜浣犵殑缃戠珯椤甸潰鎻掑叆閫氬父浠 <script> 鏍囩褰㈠紡鐨勪换鎰廐TML浠g爜銆
Attackers often use XSS attacks to steal cookie and session information, or to trick users into giving private information to the wrong person (aka phishing ).
鏀诲嚮鑰呴氬父鍒╃敤XSS鏀诲嚮鏉ョ獌鍙朿ookie鍜屼細璇濅俊鎭紝鎴栬呰楠楃敤鎴峰皢鍏剁瀵嗕俊鎭忔紡缁欏埆浜猴紙鍙堢О 閽撻奔 锛夈
This type of attack can take a number of different forms and has almost infinite permutations, so well just look at a typical example. Consider this extremely simple Hello, World view:
杩欑绫诲瀷鐨勬敾鍑昏兘澶熼噰鐢ㄥ绉嶄笉鍚岀殑鏂瑰紡锛屽苟涓旀嫢鏈夊嚑涔庢棤闄愮殑鍙樹綋锛屽洜姝ゆ垜浠繕鏄彧鍏虫敞鏌愪釜鍏稿瀷鐨勪緥瀛愬惂銆傝鎴戜滑鏉ユ兂鎯宠繖鏍蜂竴涓瀬搴︾畝鍗曠殑Hello World瑙嗗浘锛
def say_hello(request): name = request.GET.get('name', 'world') return render_to_response("hello.html", {"name" : name})
This view simply reads a name from a GET parameter and passes that name to the hello.html template. We might write a template for this view as follows:
杩欎釜瑙嗗浘鍙槸绠鍗曠殑浠嶨ET鍙傛暟涓鍙栧鍚嶇劧鍚庡皢濮撳悕浼犻掔粰hello.html妯℃澘銆傛垜浠彲鑳戒細涓鸿繖涓鍥剧紪鍐欏涓嬫墍绀虹殑妯℃澘锛
<h1>Hello, {{ name }}!</h1>
So if we accessed http://example.com/hello/name=Jacob , the rendered page would contain this:
鍥犳锛屽鏋滄垜浠闂 http://example.com/hello/?name=Jacob 锛岃鍛堢幇鐨勯〉闈㈠皢浼氬寘鍚竴浠ヤ笅杩欎簺锛
<h1>Hello, Jacob!</h1>
But wait what happens if we access http://example.com/hello/name=<i>Jacob</i> ? Then we get this:
浣嗘槸锛岀瓑绛夛紝濡傛灉鎴戜滑璁块棶 http://example.com/hello/?name=<i>Jacob</i> 鏃跺張浼氬彂鐢熶粈涔堝憿锛熺劧鍚庢垜浠細寰楀埌锛
<h1>Hello, <i>Jacob</i>!</h1>
Of course, an attacker wouldnt use something as benign as <i> tags; he could include a whole set of HTML that hijacked your page with arbitrary content. This type of attack has been used to trick users into entering data into what looks like their banks Web site, but in fact is an XSS-hijacked form that submits their back account information to an attacker.
褰撶劧锛屼竴涓敾鍑昏呬笉浼氫娇鐢<i>鏍囩寮濮嬬殑绫讳技浠g爜锛屼粬鍙兘浼氱敤浠绘剰鍐呭鍘诲寘鍚竴涓畬鏁寸殑HTML闆嗘潵鍔寔鎮ㄧ殑椤甸潰銆傝繖绉嶇被鍨嬬殑鏀诲嚮宸茬粡杩愮敤浜庤櫄鍋囬摱琛岀珯鐐逛互璇遍獥鐢ㄦ埛杈撳叆涓汉淇℃伅锛屼簨瀹炰笂杩欏氨鏄竴绉嶅姭鎸乆SS鐨勫舰寮忥紝鐢ㄤ互浣跨敤鎴峰悜鏀诲嚮鑰呮彁渚涗粬浠殑閾惰甯愭埛淇℃伅銆
The problem gets worse if you store this data in the database and later display it it on your site. For example, MySpace was once found to be vulnerable to an XSS attack of this nature. A user inserted JavaScript into his profile that automatically added him as your friend when you visited his profile page. Within a few days, he had millions of friends.
濡傛灉鎮ㄥ皢杩欎簺鏁版嵁淇濆瓨鍦ㄦ暟鎹簱涓紝鐒跺悗灏嗗叾鏄剧ず鍦ㄦ偍鐨勭珯鐐逛笂锛岄偅涔堥棶棰樺氨鍙樺緱鏇翠弗閲嶄簡銆備緥濡傦紝涓鏃ySpace琚彂鐜拌繖鏍风殑鐗圭偣鑰岃兘澶熻交鏄撶殑琚玐SS鏀诲嚮锛屽悗鏋滀笉鍫鎯炽傛煇涓敤鎴峰悜浠栫殑绠浠嬩腑鎻掑叆JavaScript锛屼娇寰楁偍鍦ㄨ闂粬鐨勭畝浠嬮〉闈㈡椂鑷姩灏嗗叾鍔犱负鎮ㄧ殑濂藉弸锛岃繖鏍峰湪鍑犲ぉ涔嬪唴锛岃繖涓汉灏辫兘鎷ユ湁涓婄櫨涓囩殑濂藉弸銆
Now, this may sound relatively benign, but keep in mind that this attacker managed to get his code not MySpaces running on your computer. This violates the assumed trust that all the code on MySpace is actually written by MySpace.
鐜板湪锛岃繖绉嶅悗鏋滃惉璧锋潵杩樹笉閭d箞鎭跺姡锛屼絾鏄偍瑕佹竻妤氣斺旇繖涓敾鍑昏呮璁炬硶灏 浠 鐨勪唬鐮佽屼笉鏄疢ySpace鐨勪唬鐮佽繍琛屽湪 鎮 鐨勮绠楁満涓娿傝繖鏄剧劧杩濊儗浜嗗亣瀹氫俊浠烩斺旀墍鏈夎繍琛屽湪MySpace涓婄殑浠g爜搴旇閮芥槸MySpace缂栧啓鐨勶紝鑰屼簨瀹炰笂鍗翠笉濡傛銆
MySpace was extremely lucky that this malicious code didnt automatically delete viewers accounts, change their passwords, flood the site with spam, or any of the other nightmare scenarios this vulnerability unleashes.
MySpace鏄瀬搴﹀垢杩愮殑锛屽洜涓鸿繖浜涙伓鎰忎唬鐮佸苟娌℃湁鑷姩鍒犻櫎璁块棶鑰呯殑甯愭埛锛屾病鏈変慨鏀逛粬浠殑瀵嗙爜锛屼篃骞舵病鏈変娇鏁翠釜绔欑偣涓鍥㈢碂锛屾垨鑰呭嚭鐜板叾浠栧洜涓鸿繖涓急鐐硅屽鑷寸殑鍏朵粬鍣╂ⅵ銆
The solution is simple: always escape any content that might have come from a user. If we simply rewrite our template as follows:
瑙e喅鏂规鏄畝鍗曠殑锛氭绘槸杞箟鍙兘鏉ヨ嚜鏌愪釜鐢ㄦ埛鐨勪换浣曞唴瀹广傚鏋滄垜浠儚濡備笅浠g爜鏉ョ畝鍗曠殑閲嶅啓鎴戜滑鐨勬ā鏉匡細
<h1>Hello, {{ name|escape }}!</h1>
then were no longer vulnerable. You should always use the escape tag (or something equivalent) when displaying user-submitted content on your site.
杩欐牱涓鏉ュ氨涓嶆绘槸閭d箞鐨勫急涓嶇椋庝簡銆傚湪鎮ㄧ殑绔欑偣涓婃樉绀虹敤鎴锋彁浜ょ殑鍐呭鏃讹紝鎮ㄥ簲璇ユ绘槸浣跨敤escape鏍囩锛堟垨鍏朵粬绫讳技鐨勪笢瑗匡級銆
Why Doesnt Django Just Do This for You?
涓轰粈涔圖jango娌℃湁涓烘偍瀹屾垚杩欎簺鍛紵
Modifying Django to automatically escape all variables displayed in templates is a frequent topic of discussion on the Django developer mailing list.
鍦―jango寮鍙戣呴偖浠跺垪琛ㄤ腑锛屽皢Django淇敼鎴愪负鑳藉鑷姩杞箟鍦ㄦā鏉夸腑鏄剧ず鐨勬墍鏈夊彉閲忔槸涓涓佽瘽棰樹簡銆
So far, Djangos templates have avoided this behavior because it subtly changes what should be relatively straightforward behavior (displaying variables). Its a tricky issue and a difficult tradeoff to evaluate. Adding hidden implicit behavior is against Djangos core ideals (and Pythons, for that matter), but security is equally important.
杩勪粖涓烘锛孌jango妯℃澘閮介伩鍏嶈繖绉嶈涓猴紝鍥犱负杩欐牱灏辩暐寰敼鍙樹簡Django搴旇鐩稿鐩存帴鐨勮涓猴紙灞曠幇鍙橀噺锛夈傝繖鏄竴涓鎵嬬殑闂锛屽湪璇勪及涓婄殑涓绉嶈壈闅炬姌涓傚鍔犻殣钘忛殣寮忚涓鸿繚鍙嶄簡Django鐨勬牳蹇冪悊蹇碉紙瀵逛簬Pythons涔熸槸濡傛锛夛紝浣嗘槸瀹夊叏鎬ф槸鍚岀瓑鐨勯噸瑕併
All this is to say, then, that theres a fair chance Django will grow some form of auto-escaping (or nearly auto-escaping) behavior in the future. Its a good idea to check the official Django documentation for the latest in Django features; it will always be more up to date than this book, especially the print edition.
鎵鏈夎繖涓鍒囬兘琛ㄦ槑锛屽湪灏嗘潵鏌愪釜閫傚綋鐨勬椂鏈猴紝Django浼氬紑鍙戝嚭鏌愪簺褰㈠紡鐨勮嚜鍔ㄨ浆涔夛紙鎴栬呭緢澶х▼搴︿笂鐨勮嚜鍔ㄨ浆涔夛級銆傚湪Django鐗规ф渶鏂版秷鎭腑鏌ユ壘姝e紡瀹樻柟鏂囨。鏄竴涓笉閿欑殑涓绘剰锛岄偅閲岀殑涓滆タ鎬绘槸瑕佹瘮鏈功涓檲杩扮殑瑕佹洿鏂扮殑澶氾紝鐗瑰埆鏄墦鍗扮増鏈
Even if Django does add this feature, however, you should still be in the habit of asking yourself, at all times, Where does this data come from? No automatic solution will ever protect your site from XSS attacks 100% of the time.
鐢氳嚦锛屽鏋淒jango鐪熺殑鏂板浜嗚繖浜涚壒鎬э紝鎮ㄤ篃搴旇涔犳儻鎬х殑闂嚜宸憋紝涓鐩翠互鏉ワ紝杩欎簺鏁版嵁閮芥潵鑷簬鍝噷鍛紵娌℃湁鍝釜鑷姩瑙e喅鏂规鑳藉姘歌繙淇濇姢鎮ㄧ殑绔欑偣鐧惧垎涔嬬櫨鐨勪笉浼氬彈鍒癤SS鏀诲嚮銆
Cross-site request forgery (CSRF) happens when a malicious Web site tricks users into unknowingly loading a URL from a site at which theyre already authenticated hence taking advantage of their authenticated status.
浼犺法绔欑偣璇锋眰(CSRF)鍙戠敓鍦ㄥ綋鏌愪釜鎭舵剰Web绔欑偣璇遍獥鐢ㄦ埛涓嶇煡涓嶈鐨勪粠涓涓俊浠荤珯鐐逛笅杞芥煇涓猆RL涔嬫椂锛岃繖涓俊浠荤珯鐐瑰凡缁忚閫氳繃淇′换楠岃瘉锛屽洜姝ゆ伓鎰忕珯鐐瑰氨鍒╃敤浜嗚繖涓淇′换鐘舵併
Django has built-in tools to protect from this kind of attack. Both the attack itself and those tools are covered in great detail in Chapter 14.
Django鎷ユ湁鍐呭缓宸ュ叿鏉ラ槻姝㈣繖绉嶆敾鍑汇傝繖绉嶆敾鍑荤殑浠嬬粛鍜岃鍐呭缓宸ュ叿閮藉湪绗14绔犱腑杩涜杩涗竴姝ョ殑闃愯堪銆
This isnt a specific attack, but rather a general class of attacks on a users session data. It can take a number of different forms:
杩欎笉鏄煇涓壒瀹氱殑鏀诲嚮锛岃屾槸瀵圭敤鎴蜂細璇濇暟鎹殑閫氱敤绫绘敾鍑汇傝繖绉嶆敾鍑诲彲浠ラ噰鍙栧绉嶅舰寮忥細
A man-in-the-middle attack, where an attacker snoops on session data as it travels over the wire (or wireless) network.
涓棿浜 鏀诲嚮锛氬湪杩欑鏀诲嚮涓敾鍑昏呭湪鐩戝惉鏈夌嚎锛堟垨鑰呮棤绾匡級缃戠粶涓婄殑浼氳瘽鏁版嵁銆
Session forging , where an attacker uses a session ID (perhaps obtained through a man-in-the-middle attack) to pretend to be another user.
浼犱細璇 锛氭敾鍑昏呭埄鐢ㄤ細璇滻D锛堝彲鑳芥槸閫氳繃涓棿浜烘敾鍑绘潵鑾峰緱锛夊皢鑷繁浼鎴愬彟涓涓敤鎴枫
An example of these first two would be an attacker in a coffee shop using the shops wireless network to capture a session cookie. She could then use that cookie to impersonate the original user.
杩欎袱绉嶆敾鍑荤殑涓涓緥瀛愬彲浠ユ槸鍦ㄤ竴闂村挅鍟″簵閲岀殑鏌愪釜鏀诲嚮鑰呭埄鐢ㄥ簵鐨勬棤绾跨綉缁滄潵鎹曡幏鏌愪釜浼氳瘽cookie锛岀劧鍚庡ス灏卞彲浠ュ埄鐢ㄩ偅涓猚ookie鏉ュ亣鍐掑師濮嬬敤鎴枫
A cookie-forging attack, where an attacker overrides the supposedly read-only data stored in a cookie. Chapter 12 explains in detail how cookies work, and one of the salient points is that its trivial for browsers and malicious users to change cookies without your knowledge.
浼燾ookie 锛氬氨鏄寚鏌愪釜鏀诲嚮鑰呰鐩栦簡鍦ㄦ煇涓猚ookie涓湰搴旇鏄彧璇荤殑鏁版嵁銆傜12绔犺缁嗗湴瑙i噴浜哻ookie鐨勫伐浣滃師鐞嗭紝cookie鐨勪竴涓樉钁楃壒鐐瑰氨鏄祻瑙堣呭拰鎭舵剰鐢ㄦ埛鎯宠鑳岀潃鎮ㄥ仛浜涗慨鏀癸紝鏄竴浠跺緢绋鏉惧钩甯哥殑浜嬫儏銆
Theres a long history of Web sites that have stored a cookie like IsLoggedIn=1 or even LoggedInAsUser=jacob . Its dead simple to exploit these types of cookies.
Web绔欑偣浠 IsLoggedIn=1 鎴栬 LoggedInAsUser=jacob 杩欐牱鐨勬柟寮忔潵淇濆瓨cookie鐢辨潵宸蹭箙锛屼娇鐢ㄨ繖鏍风殑cookie鏄啀绠鍗曚笉杩囩殑浜嗐
On a more subtle level, though, its never a good idea to trust anything stored in cookies; you never know whos been poking at them.
浣嗘槸锛屼粠鏇村姞缁嗗井鐨勫眰闈㈡潵鐪嬶紝淇′换瀛樺偍鍦╟ookie涓殑浠讳綍涓滆タ閮戒粠鏉ヤ笉鏄竴涓ソ涓绘剰锛屽洜涓烘偍浠庢潵涓嶇煡閬撳灏戜汉宸茬粡瀵瑰畠涓娓呬簩妤氥
Session fixation , where an attacker tricks a user into setting or reseting the users session ID.
浼氳瘽婊炵暀 锛氭敾鍑昏呰楠楃敤鎴疯缃垨鑰呴噸璁剧疆璇ョ敤鎴风殑浼氳瘽ID銆
For example, PHP allows session identifiers to be passed in the URL (e.g., http://example.com/?PHPSESSID=fa90197ca25f6ab40bb1374c510d7a32 ). An attacker who tricks a user into clicking a link with a hard-coded session ID will cause the user to pick up that session.
渚嬪锛孭HP鍏佽鍦║RL锛堝 http://example.com/?PHPSESSID=fa90197ca25f6ab40bb1374c510d7a32 绛夛級涓紶閫掍細璇濇爣璇嗙銆傛敾鍑昏呰楠楃敤鎴风偣鍑绘煇涓甫鏈夌‖缂栫爜浼氳瘽ID鐨勯摼鎺ュ氨浼氬鑷磋鐢ㄦ埛鎭㈠閭d釜浼氳瘽銆
Session fixation has been used in phishing attacks to trick users into entering personal information into an account the attacker owns. He can later log into that account and retrieve the data.
浼氳瘽婊炵暀宸茬粡杩愮敤鍦ㄩ挀楸兼敾鍑讳腑锛屼互璇遍獥鐢ㄦ埛鍦ㄦ敾鍑昏呮嫢鏈夌殑璐﹀彿閲岃緭鍏ュ叾涓汉淇℃伅锛屼箣鍚庢敾鍑昏呭氨鑳藉鐧婚檰鑷繁鐨勫笎鎴锋潵鑾峰彇琚獥鐢ㄦ埛杈撳叆鐨勬暟鎹
Session poisoning , where an attacker injects potentially dangerous data into a users session usually through a Web form that the user submits to set session data.
浼氳瘽涓瘨 锛氭敾鍑昏呴氳繃鐢ㄦ埛鎻愪氦璁剧疆浼氳瘽鏁版嵁鐨刉eb琛ㄥ崟鍚戣鐢ㄦ埛浼氳瘽涓敞鍏ユ綔鍦ㄥ嵄闄╂暟鎹
A canonical example is a site that stores a simple user preference (like a pages background color) in a cookie. An attacker could trick a user into clicking a link to submit a color that actually contains an XSS attack; if that color isnt escaped, the user could again inject malicious code into the users environment.
涓涓粡鍏哥殑渚嬪瓙灏辨槸涓涓珯鐐瑰湪鏌愪釜cookie涓瓨鍌ㄤ簡绠鍗曠殑鐢ㄦ埛鍋忓ソ锛堟瘮濡備竴涓〉闈㈣儗鏅鑹诧級銆傛敾鍑昏呰兘澶熻楠楃敤鎴风偣鍑绘煇涓摼鎺ユ潵鎻愪氦鏌愮棰滆壊锛岃屽疄闄呬笂閾炬帴涓凡缁忓寘鍚簡鏌愪釜XXS鏀诲嚮锛屽鏋滆繖涓鑹叉病鏈夎杞箟锛屾敾鍑昏呭氨鍙互缁х画鍚戣鐢ㄦ埛鐜涓敞鍏ユ伓鎰忎唬鐮併
There are a number of general principles that can protect you from these attacks:
鏈夎澶氬熀鏈噯鍒欒兘澶熶繚鎶ゆ偍涓嶅彈鍒拌繖浜涙敾鍑伙細
Never allow session information to be contained in the URL.
涓嶈鍦║RL涓寘鍚换浣晄ession淇℃伅銆
Djangos session framework (see Chapter 12) simply doesnt allow sessions to be contained in the URL.
Django鐨剆ession妗嗘灦锛堣绗12绔狅級骞茶剢涓嶅厑璁窾RL涓寘鍚玸ession銆
Dont store data in cookies directly; instead, store a session ID that maps to session data stored on the back-end.
涓嶈鐩存帴鍦╟ookie涓瓨鍌ㄦ暟鎹紝鑰屾槸淇濆瓨涓涓槧灏勫悗鍙皊ession鏁版嵁鐨剆ession ID銆
If you use Djangos built-in session framework (i.e., request.session ), this is handled automatically for you. The only cookie that the session framework uses is a single session ID; all the session data is stored in the database.
濡傛灉浣跨敤Django鍐呯疆鐨剆ession妗嗘灦锛堝嵆 request.session 锛夛紝瀹冧細鑷姩杩涜澶勭悊銆傝繖涓猻ession妗嗘灦浠呭湪cookie涓瓨鍌ㄤ竴涓猻ession ID锛屾墍鏈夌殑session鏁版嵁灏嗕細琚瓨鍌ㄥ湪鏁版嵁搴撲腑銆
Remember to escape session data if you display it in the template. See the earlier XSS section, and remember that it applies to any user-created content as well as any data from the browser. You should treat session information as being user created.
濡傛灉闇瑕佸湪妯℃澘涓樉绀簊ession鏁版嵁锛岃璁板緱瀵瑰叾杩涜杞箟銆傚彲鍙傝冧箣鍓嶇殑XSS閮ㄥ垎锛屽鎵鏈夌敤鎴锋彁浜ょ殑鏁版嵁鍜屾祻瑙堝櫒鎻愪氦鐨勬暟鎹繘琛岃浆涔夈傚浜巗ession淇℃伅锛屽簲璇ュ儚鐢ㄦ埛鎻愪氦鐨勬暟鎹竴鏍峰鍏惰繘琛屽鐞嗐
Prevent attackers from spoofing session IDs whenever possible.
浠讳綍鍙兘鐨勫湴鏂归兘瑕侀槻姝㈡敾鍑昏呰繘琛宻ession娆洪獥銆
Although its nearly impossible to detect someone whos hijacked a session ID, Django does have built-in protection against a brute-force session attack. Session IDs are stored as hashes (instead of sequential numbers), which prevents a brute-force attack, and a user will always get a new session ID if she tries a nonexistent one, which prevents session fixation.
灏界鍘绘帰娴嬬┒绔熸槸璋佸姭鎸佷簡浼氳瘽ID鏄嚑涔庝笉鍙兘鐨勪簨鍎匡紝Django杩樻槸鍐呯疆浜嗕繚鎶ゆ帾鏂芥潵鎶靛尽鏆村姏浼氳瘽鏀诲嚮銆備細璇滻D琚瓨鍦ㄥ搱甯岃〃閲岋紙鍙栦唬浜嗗簭鍒楁暟瀛楋級锛岃繖鏍峰氨闃绘浜嗘毚鍔涙敾鍑伙紝骞朵笖濡傛灉涓涓敤鎴峰幓灏濊瘯涓涓笉瀛樺湪鐨勪細璇濋偅涔堝ス鎬绘槸浼氬緱鍒颁竴涓柊鐨勪細璇滻D锛岃繖鏍峰氨闃绘浜嗕細璇濇粸鐣欍
Notice that none of those principles and tools prevents man-in-the-middle attacks. These types of attacks are nearly impossible to detect. If your site allows logged-in users to see any sort of sensitive data, you should always serve that site over HTTPS. Additionally, if you have an SSL-enabled site, you should set the SESSION_COOKIE_SECURE setting to True ; this will make Django only send session cookies over HTTPS.
璇锋敞鎰忥紝浠ヤ笂娌℃湁涓绉嶅噯鍒欏拰宸ュ叿鑳藉闃绘涓棿浜烘敾鍑汇傝繖浜涚被鍨嬬殑鏀诲嚮鏄嚑涔庝笉鍙兘琚帰娴嬬殑銆傚鏋滀綘鐨勭珯鐐瑰厑璁哥櫥闄嗙敤鎴峰幓鏌ョ湅浠绘剰鏁忔劅鏁版嵁鐨勮瘽锛屼綘搴旇 鎬绘槸 閫氳繃HTTPS鏉ユ彁渚涚綉绔欐湇鍔°傛澶栵紝濡傛灉浣犵殑绔欑偣浣跨敤SSL锛屼綘搴旇灏 SESSION_COOKIE_SECURE 璁剧疆涓 True 锛岃繖鏍峰氨鑳藉浣緿jango鍙氳繃HTTPS鍙戦佷細璇漜ookie銆
SQL injections less well-known sibling, email header injection , hijacks Web forms that send email. An attacker can use this technique to send spam via your mail server. Any form that constructs email headers from Web form data is vulnerable to this kind of attack.
閭欢澶撮儴娉ㄥ叆 锛氫粎娆′簬SQL娉ㄥ叆锛屾槸涓绉嶉氳繃鍔寔鍙戦侀偖浠剁殑Web琛ㄥ崟鐨勬敾鍑绘柟寮忋傛敾鍑昏呰兘澶熷埄鐢ㄨ繖绉嶆妧鏈潵閫氳繃浣犵殑閭欢鏈嶅姟鍣ㄥ彂閫佸瀮鍦鹃偖浠躲傚湪杩欑鏀诲嚮闈㈠墠锛屼换浣曟柟寮忕殑鏉ヨ嚜Web琛ㄥ崟鏁版嵁鐨勯偖浠跺ご閮ㄦ瀯绛戦兘鏄潪甯歌剢寮辩殑銆
Lets look at the canonical contact form found on many sites. Usually this sends a message to a hard-coded email address and, hence, doesnt appear vulnerable to spam abuse at first glance.
璁╂垜浠湅鐪嬪湪鎴戜滑璁稿缃戠珯涓彂鐜扮殑杩欑鏀诲嚮鐨勫舰寮忋傞氬父杩欑鏀诲嚮浼氬悜纭紪鐮侀偖浠跺湴鍧鍙戦佷竴涓秷鎭紝鍥犳锛岀涓鐪肩湅涓婂幓骞朵笉鏄惧緱鍍忛潰瀵瑰瀮鍦鹃偖浠堕偅涔堣剢寮便
However, most of these forms also allow the user to type in his own subject for the email (along with a from address, body, and sometimes a few other fields). This subject field is used to construct the subject header of the email message.
浣嗘槸锛屽ぇ澶氭暟琛ㄥ崟閮藉厑璁哥敤鎴疯緭鍏ヨ嚜宸辩殑閭欢涓婚锛堝悓鏃惰繕鏈塮rom鍦板潃锛岄偖浠朵綋锛屾湁鏃惰繕鏈夐儴鍒嗗叾浠栧瓧娈碉級銆傝繖涓富棰樺瓧娈佃鐢ㄦ潵鏋勫缓閭欢娑堟伅鐨勪富棰樺ご閮ㄣ
If that header is unescaped when building the email message, an attacker could submit something like "hello\ncc:spamvictim@example.com" (where "\n is a newline character). That would make the constructed email headers turn into:
濡傛灉閭d釜閭欢澶撮儴鍦ㄦ瀯寤洪偖浠朵俊鎭椂娌℃湁琚浆涔夛紝閭d箞鏀诲嚮鑰呭彲浠ユ彁浜ょ被浼 "hello\ncc:spamvictim@example.com" 锛堣繖閲岀殑 "\n" 鏄崲琛岀锛夌殑涓滆タ銆傝繖鏈夊彲鑳戒娇寰楁墍鏋勫缓鐨勯偖浠跺ご閮ㄥ彉鎴愶細
To: hardcoded@example.com Subject: hello cc: spamvictim@example.com
Like SQL injection, if we trust the subject line given by the user, well allow him to construct a malicious set of headers, and he can use our contact form to send spam.
灏卞儚SQL娉ㄥ叆閭f牱锛屽鏋滄垜浠俊浠讳簡鐢ㄦ埛鎻愪緵鐨勪富棰樿锛岄偅鏍峰悓鏍蜂篃浼氬厑璁镐粬鏋勫缓涓涓ご閮ㄦ伓鎰忛泦锛屼粬涔熷氨鑳藉鍒╃敤鑱旂郴浜鸿〃鍗曟潵鍙戦佸瀮鍦鹃偖浠躲
We can prevent this attack in the same way we prevent SQL injection: always escape or validate user-submitted content.
鎴戜滑鑳藉閲囩敤涓庨樆姝QL娉ㄥ叆鐩稿悓鐨勬柟寮忔潵闃绘杩欑鏀诲嚮锛氭绘槸鏍¢獙鎴栬呰浆涔夌敤鎴锋彁浜ょ殑鍐呭銆
Djangos built-in mail functions (in django.core.mail ) simply do not allow newlines in any fields used to construct headers (the from and to addresses, plus the subject). If you try to use django.core.mail.send_mail with a subject that contains newlines, Django will raise a BadHeaderError exception.
Django鍐呭缓閭欢鍔熻兘锛堝湪 django.core.mail 涓級鏍规湰涓嶅厑璁稿湪鐢ㄦ潵鏋勫缓閭欢澶撮儴鐨勫瓧娈典腑瀛樺湪鎹㈣绗︼紙琛ㄥ崟锛宼o鍦板潃锛岃繕鏈変富棰橈級銆傚鏋滄偍璇曞浘浣跨敤 django.core.mail.send_mail 鏉ュ鐞嗗寘鍚崲琛岀鐨勪富棰樻椂锛孌jango灏嗕細鎶涘嚭BadHeaderError寮傚父銆
If you do not use Djangos built-in mail functions to send email, youll need to make sure that newlines in headers either cause an error or are stripped. You may want to examine the SafeMIMEText class in django.core.mail to see how Django does this.
濡傛灉浣犳病鏈変娇鐢―jango鍐呭缓閭欢鍔熻兘鏉ュ彂閫侀偖浠讹紝閭d箞浣犻渶瑕佺‘淇濆寘鍚湪閭欢澶撮儴鐨勬崲琛岀鑳藉寮曞彂閿欒鎴栬呰鍘绘帀銆備綘鎴栬鎯充粩缁嗛槄璇 django.core.mail 涓殑 SateMIMEText 绫绘潵鐪嬬湅Django鏄浣曞仛鍒拌繖涓鐐圭殑銆
Directory traversal is another injection-style attack, wherein a malicious user tricks filesystem code into reading and/or writing files that the Web server shouldnt have access to.
鐩綍閬嶅巻 锛氭槸鍙﹀涓绉嶆敞鍏ユ柟寮忕殑鏀诲嚮锛屽湪杩欑鏀诲嚮涓紝鎭舵剰鐢ㄦ埛璇遍獥鏂囦欢绯荤粺浠g爜瀵筗eb鏈嶅姟鍣ㄤ笉搴旇璁块棶鐨勬枃浠惰繘琛岃鍙栧拰/鎴栧啓鍏ユ搷浣溿
An example might be a view that reads files from the disk without carefully sanitizing the file name:
渚嬪瓙鍙互鏄繖鏍风殑锛屾煇涓鍥捐瘯鍥惧湪娌℃湁浠旂粏瀵规枃浠惰繘琛岄槻姣掑鐞嗙殑鎯呭喌涓嬩粠纾佺洏涓婅鍙栨枃浠讹細
def dump_file(request): filename = request.GET["filename"] filename = os.path.join(BASE_PATH, filename) content = open(filename).read() # ...
Though it looks like that view restricts file access to files beneath BASE_PATH (by using os.path.join ), if the attacker passes in a filename containing .. (thats two periods, a shorthand for the parent directory), she can access files above BASE_PATH . Its only a matter of time before she can discover the correct number of dots to successfully access, say, ../../../../../etc/passwd .
灏界涓鐪肩湅涓婂幓锛岃鍥鹃氳繃 BASE_PATH 锛堥氳繃浣跨敤 os.path.join 锛夐檺鍒朵簡瀵逛簬鏂囦欢鐨勮闂紝浣嗗鏋滄敾鍑昏呬娇鐢ㄤ簡鍖呭惈 .. 锛堜袱涓彞鍙凤紝鐖剁洰褰曠殑涓绉嶇畝鍐欏舰寮忥級鐨勬枃浠跺悕锛屽ス灏辫兘澶熻闂埌 BASE_PATH 鐩綍缁撴瀯浠ヤ笂鐨勬枃浠躲傝鑾峰彇鏉冮檺锛屽彧鏄竴涓椂闂翠笂鐨勯棶棰橈紙 ../../../../../etc/passwd 锛夈
Anything that reads files without proper escaping is vulnerable to this problem. Views that write files are just as vulnerable, but the consequences are doubly dire.
浠讳綍涓嶅仛閫傚綋杞箟鍦拌鍙栨枃浠舵搷浣滐紝閮藉彲鑳藉鑷磋繖鏍风殑闂銆傚厑璁 鍐 鎿嶄綔鐨勮鍥惧悓鏍峰鏄撳彂鐢熼棶棰橈紝鑰屼笖缁撴灉寰寰鏇村姞鍙曘
Another permutation of this problem lies in code that dynamically loads modules based on the URL or other request information. A well-publicized example came from the world of Ruby on Rails. Prior to mid-2006, Rails used URLs like http://example.com/person/poke/1 directly to load modules and call methods. The result was that a carefully constructed URL could automatically load arbitrary code, including a database reset script!
杩欎釜闂鐨勫彟涓绉嶈〃鐜板舰寮忥紝鍑虹幇鍦ㄦ牴鎹甎RL鍜屽叾浠栫殑璇锋眰淇℃伅鍔ㄦ佸湴鍔犺浇妯″潡銆備竴涓紬鎵鍛ㄧ煡鐨勪緥瀛愭潵鑷簬Ruby on Rails銆傚湪2006骞翠笂鍗婂勾涔嬪墠锛孯ails浣跨敤绫讳技浜 http://example.com/person/poke/1 杩欐牱鐨刄RL鐩存帴鍔犺浇妯″潡鍜岃皟鐢ㄥ嚱鏁般傜粨鏋滄槸锛岀簿蹇冩瀯閫犵殑URL锛屽彲浠ヨ嚜鍔ㄥ湴璋冪敤浠绘剰鐨勪唬鐮侊紝鍖呮嫭鏁版嵁搴撶殑娓呯┖鑴氭湰銆
If your code ever needs to read or write files based on user input, you need to sanitize the requested path very carefully to ensure that an attacker isnt able to escape from the base directory youre restricting access to.
濡傛灉浣犵殑浠g爜闇瑕佹牴鎹敤鎴风殑杈撳叆鏉ヨ鍐欐枃浠讹紝浣犲氨闇瑕佺‘淇濓紝鏀诲嚮鑰呬笉鑳借闂綘鎵绂佹璁块棶鐨勭洰褰曘
Note
澶囨敞
Needless to say, you should never write code that can read from any area of the disk!
涓嶇敤澶氳锛屼綘 姘歌繙 涓嶈鍦ㄥ彲浠ヨ鐢ㄦ埛璇诲彇鐨勬枃浠朵綅缃笂缂栧啓浠g爜锛
A good example of how to do this escaping lies in Djangos built-in static content-serving view (in django.views.static ). Heres the relevant code:
Django鍐呯疆鐨勯潤鎬佸唴瀹硅鍥炬槸鍋氳浆涔夌殑涓涓ソ鐨勭ず渚嬶紙鍦 django.views.static 涓級銆備笅闈㈡槸鐩稿叧鐨勪唬鐮侊細
import os import posixpath # ... path = posixpath.normpath(urllib.unquote(path)) newpath = '' for part in path.split('/'): if not part: # strip empty path components continue drive, part = os.path.splitdrive(part) head, part = os.path.split(part) if part in (os.curdir, os.pardir): # strip '.' and '..' in path continue newpath = os.path.join(newpath, part).replace('\\', '/')
Django doesnt read files (unless you use the static.serve function, but thats protected with the code just shown), so this vulnerability doesnt affect the core code much.
Django涓嶈鍙栨枃浠讹紙闄ら潪浣犱娇鐢 static.serve 鍑芥暟锛屼絾涔熷彈鍒颁簡涓婇潰杩欐浠g爜鐨勪繚鎶わ級锛屽洜姝よ繖绉嶅嵄闄╁浜庢牳蹇冧唬鐮佺殑褰卞搷灏辫灏忓緱澶氥
In addition, the use of the URLconf abstraction means that Django will never load code youve not explicitly told it to load. Theres no way to create a URL that causes Django to load something not mentioned in a URLconf.
鏇磋繘涓姝ワ紝URLconf鎶借薄灞傜殑浣跨敤锛屾剰鍛崇潃涓嶇粡杩囦綘鏄庣‘鐨勬寚瀹氾紝Django 鍐充笉浼 瑁呰浇浠g爜銆傞氳繃鍒涘缓涓涓猆RL鏉ヨDjango瑁呰浇娌℃湁鍦║RLconf涓嚭鐜扮殑涓滆タ锛屾槸涓嶅彲鑳藉彂鐢熺殑銆
During development, being able to see tracebacks and errors live in your browser is extremely useful. Django has pretty and informative debug messages specifically to make debugging easier.
鍦ㄥ紑鍙戣繃绋嬩腑锛岄氳繃娴忚鍣ㄦ鏌ラ敊璇拰璺熻釜寮傚父鏄潪甯告湁鐢ㄧ殑銆侱jango鎻愪緵浜嗘紓浜笖璇︾粏鐨刣ebug淇℃伅锛屼娇寰楄皟璇曡繃绋嬫洿鍔犲鏄撱
However, if these errors get displayed once the site goes live, they can reveal aspects of your code or configuration that could aid an attacker.
鐒惰岋紝涓鏃﹀湪绔欑偣涓婄嚎浠ュ悗锛岃繖浜涙秷鎭粛鐒惰鏄剧ず锛屽畠浠氨鍙兘鏆撮湶浣犵殑浠g爜鎴栬呮槸閰嶇疆鏂囦欢鍐呭缁欐敾鍑昏呫
Furthermore, errors and tracebacks arent at all useful to end users. Djangos philosophy is that site visitors should never see application-related error messages. If your code raises an unhandled exception, a site visitor should not see the full traceback or any hint of code snippets or Python (programmer-oriented) error messages. Instead, the visitor should see a friendly This page is unavailable message.
杩樻湁锛岄敊璇拰璋冭瘯娑堟伅瀵逛簬鏈缁堢敤鎴疯岃█鏄鏃犵敤澶勭殑銆侱jango鐨勭悊蹇垫槸锛岀珯鐐圭殑璁块棶鑰呮案杩滀笉搴旇鐪嬪埌涓庡簲鐢ㄧ浉鍏崇殑鍑洪敊娑堟伅銆傚鏋滀綘鐨勪唬鐮佹姏鍑轰簡涓涓病鏈夊鐞嗙殑寮傚父锛岀綉绔欒闂呬笉搴旇鐪嬪埌璋冭瘯淇℃伅鎴栬 浠讳綍 浠g爜鐗囨鎴栬匬ython锛堥潰鍚戝紑鍙戣咃級鍑洪敊娑堟伅銆傝闂呭簲璇ュ彧鐪嬪埌鍙嬪ソ鐨勬棤娉曡闂殑椤甸潰銆
Naturally, of course, developers need to see tracebacks to debug problems in their code. So the framework should hide all error messages from the public, but it should display them to the trusted site developers.
褰撶劧锛屽紑鍙戣呴渶瑕佸湪debug鏃剁湅鍒拌皟璇曚俊鎭傚洜姝わ紝妗嗘灦灏辫灏嗚繖浜涘嚭閿欐秷鎭樉绀虹粰鍙椾俊浠荤殑缃戠珯寮鍙戣咃紝鑰岃鍚戝叕浼楅殣钘忋
Django has a simple flag that controls the display of these error messages. If the DEBUG setting is set to True , error messages will be displayed in the browser. If not, Django will render return an HTTP 500 (Internal server error) message and render an error template that you provide. This error template is called 500.html and should live in the root of one of your template directories.
Django鏈変竴涓畝鍗曠殑鏍囧織绗︼紝鏉ユ帶鍒惰繖浜涘嚭閿欎俊鎭樉绀轰笌鍚︺傚鏋 DEBUG 琚缃负 True 锛岄敊璇秷鎭氨浼氭樉绀哄湪娴忚鍣ㄤ腑銆傚惁鍒欙紝Django浼氳繑鍥炰竴涓 HTTP 500锛堝唴閮ㄦ湇鍔″櫒閿欒锛夌殑娑堟伅锛 骞舵樉绀轰綘鎵鎻愪緵鐨勫嚭閿欓〉闈€傝繖涓敊璇殑妯℃澘鍙 500.html 锛屽苟涓旇繖涓枃浠堕渶瑕佷繚瀛樺湪浣犵殑鏌愪釜妯℃澘鐩綍鐨勬牴鐩綍涓
Because developers still need to see errors generated on a live site, any errors handled this way will send an email with the full traceback to any addresses given in the ADMINS setting.
鐢变簬寮鍙戣呬粛鐒堕渶瑕佸湪涓婄嚎鐨勭珯鐐逛笂鐪嬪埌鍑洪敊娑堟伅锛岃繖鏍风殑鍑洪敊淇℃伅浼氬悜 ADMINS 璁惧畾閫夐」鑷姩鍙戦乪mail銆
Users deploying under Apache and mod_python should also make sure they have PythonDebug Off in their Apache conf files; this will suppress any errors that occur before Django has had a chance to load.
鍦ˋpache鍜宮od_python涓嬪紑鍙戠殑浜哄憳锛岃繕瑕佷繚璇佸湪Apache鐨勯厤缃枃浠朵腑鍏抽棴 PythonDebug Off 閫夐」锛岃繖涓細鍦―jango琚姞杞戒互鍓嶅幓闄ゅ嚭閿欐秷鎭
We hope all this talk of security problems isnt too intimidating. Its true that the Web can be a wild and wooly world, but with a little bit of foresight, you can have a secure Web site.
鎴戜滑甯屾湜鍏充簬瀹夊叏闂鐨勮璁猴紝涓嶄細澶浣犳劅鍒版亹鎱屻俉eb鏄竴涓澶勫竷婊¢櫡闃辩殑涓栫晫锛屼絾鏄彧瑕佹湁涓浜涜繙瑙侊紝浣犲氨鑳芥嫢鏈夊畨鍏ㄧ殑绔欑偣銆
Keep in mind that Web security is a constantly changing field; if youre reading the dead-tree version of this book, be sure to check more up to date security resources for any new vulnerabilities that have been discovered. In fact, its always a good idea to spend some time each week or month researching and keeping current on the state of Web application security. Its a small investment to make, but the protection youll get for your site and your users is priceless.
姘歌繙璁颁綇锛學eb瀹夊叏鏄竴涓笉鏂彂灞曠殑棰嗗煙銆傚鏋滀綘姝e湪闃呰杩欐湰涔︾殑鍋滄缁存姢鐨勯偅浜涚増鏈紝璇烽槄璇绘渶鏂扮増鏈殑杩欎釜閮ㄥ垎鏉ユ鏌ユ渶鏂板彂鐜扮殑婕忔礊銆備簨瀹炰笂锛屾瘡鍛ㄦ垨鑰呮瘡鏈堣姳鐐规椂闂存寲鎺榳eb搴旂敤瀹夊叏锛屽苟涓旇窡涓婃渶鏂扮殑鍔ㄦ佹槸涓涓緢濂界殑涓绘剰銆傚皬灏忕殑鎶曞叆锛屽嵈鑳芥敹鑾蜂繚鎶や綘鐨勭珯鐐瑰拰鐢ㄦ埛鐨勬棤浠风殑鍥炴姤銆
In the next chapter, well finally cover the subtleties of deploying Django: how to launch a production site and how to set it up for scalability.
涓嬩竴绔犱腑锛屾垜浠細璋堣鍒颁竴浜涗娇鐢―jango鐨勭粏鑺傞棶棰橈細濡備綍閮ㄧ讲涓涓珯鐐癸紝骞跺叿鏈夎壇濂界殑浼哥缉鎬с
鍏充簬鏈瘎娉ㄧ郴缁
鏈珯浣跨敤涓婁笅鏂囧叧鑱旂殑璇勬敞绯荤粺鏉ユ敹闆嗗弽棣堜俊鎭備笉鍚屼簬涓鑸鏁寸珷鍋氳瘎娉ㄧ殑鍋氭硶锛 鎴戜滑鍏佽浣犲姣忎竴涓嫭绔嬬殑鈥滄枃鏈潡鈥濆仛璇勬敞銆備竴涓滄枃鏈潡鈥濈湅璧锋潵鏄繖鏍风殑锛
涓涓滄枃鏈潡鈥濇槸涓涓钀斤紝涓涓垪琛ㄩ」锛屼竴娈典唬鐮侊紝鎴栬呭叾浠栦竴灏忔鍐呭銆 浣犻変腑瀹冧細楂樹寒搴︽樉绀:
瑕佸鏂囨湰鍧楀仛璇勬敞锛屼綘鍙渶瑕佺偣鍑诲畠鏃佽竟鐨勬爣璇嗗潡:
鎴戜滑浼氫粩缁嗛槄璇绘瘡涓瘎璁猴紝濡傛灉鍙兘鐨勮瘽鎴戜滑涔熶細鎶婅瘎娉ㄨ冭檻鍒版湭鏉ョ殑鐗堟湰涓幓:
濡傛灉浣犳効鎰忎綘鐨勮瘎娉ㄨ閲囩敤锛岃纭繚鐣欎笅浣犵殑鍏ㄥ悕 (娉ㄦ剰涓嶆槸鏄电О鎴栫畝绉帮級
Many, many thanks to Jack Slocum; the inspiration and much of the code for the comment system comes from Jack's blog, and this site couldn't have been built without his wonderful
YAHOO.ext
library. Thanks also to Yahoo for YUI itself.