2011-10-17 9 views
8

एएसपी.नेट एमवीसी के एंटीफोर्गेरी टोकन तंत्र वर्तमान HttpContext.User पर आधारित है। जब आप Html.AntiForgeryToken() पर कॉल करते हैं तो यह टोकन बनाने के लिए उस मान का उपयोग करता है। असल में यह ठीक है (last paragraph here में एक स्पष्टीकरण देखें) लेकिन जब आप अजाक्स कॉल के माध्यम से लॉग इन करते हैं तो समस्या उत्पन्न होती है।एमवीसी 3 एंटीफॉर्गेरी टोकन अजाक्स लॉगिन

मेरे कोड में, जब कोई उपयोगकर्ता में लॉग करता है, साख अजाक्स (AntiForgeryToken छिपी हुई फ़ील्ड मान भी Json अंदर भेज दिया जाता है), सर्वर, उपयोगकर्ता प्रमाणित करता है FormsAuthentication.SetAuthCookie लागू होता है में एक json वस्तु के रूप में भेजा जाता है() , और एक जेसन परिणाम देता है जिसमें कुछ उपयोगकर्ता-विशिष्ट डेटा होता है। इस तरह, मैं लॉगिन पर पूर्ण पृष्ठ रीफ्रेश से बच सकता हूं।

समस्या यह है कि सर्वर से बाद के हर Ajax अनुरोध अब ValidateAntiForgeryTokenAttribute पर विफल रहता है, क्योंकि यह अब एक विरोधी जालसाजी टोकन कि विरोधी जालसाजी कुकी के साथ असंगत है उम्मीद है।

क्लाइंट के छिपे हुए क्षेत्र में रखने के लिए मुझे एक वैध एंटी-जालसाजी टोकन कैसे मिल सकता है ताकि लॉगिन के बाद हर जेसन अनुरोध सफल हो जाए?

मैं टोकन मैन्युअल रूप से नया छिपा मैदान प्राप्त करने की कोशिश (कार्रवाई पर AntiForgery.GetHtml() का उपयोग कर, अपने आप टोकन स्ट्रिंग निकालने, Json में ग्राहक को लौटने और जावास्क्रिप्ट में मैन्युअल रूप से विरोधी जालसाजी छिपी हुई फ़ील्ड में रखने से) लेकिन यह काम नहीं करता है - बाद में अजाक्स कॉल सर्वर पर ValidateAntiForgeryTokenAttribute पर विफल रहता है। वास्तव में, AntiForgery.GetHtml() पर प्रत्येक कॉल (जो अनिवार्य रूप से Html.AntiForgeryToken() सहायक है) एक अलग टोकन उत्पन्न करता है, जो पिछले एक को अमान्य करता है।

मैंने HttpContext.User = new GenericPrincipal(new GenericIdentity(email), null); को विस्तृत here के रूप में सेट करने का भी प्रयास किया, लेकिन यह काम नहीं करता है।

नोट:This solution मेरी विशिष्ट स्थिति की वजह से, मेरे लिए काम नहीं करता है: एक अजाक्स लॉगिन जो सर्वर और इसलिए हर टोकन से पहले लॉगिन अमान्य है कि जेनरेट हुआ था उपयोगकर्ता पहचान नहीं बदलेगा; this solution भी लागू नहीं होता है क्योंकि यह एक अलग समस्या को संबोधित करता है।

+1

जब आप उपयोगकर्ता को अनधिकृत करते हैं, तो आप अपने लॉगिन पेज पर एंटीफ़ोर्गेरी टोकन का उपयोग क्यों कर रहे हैं। आप क्या रक्षा कर रहे हैं –

+2

लॉगिन सुविधा एक पृष्ठ नहीं है, यह साइट के टेम्पलेट के अंदर एक टुकड़ा है। वास्तव में लॉगिन सुविधा में इसकी आवश्यकता नहीं है, लेकिन बाद में समस्या उत्पन्न होती है - सर्वर पक्ष पर लॉगिन विधि के बाद वर्तमान उपयोगकर्ता (HttpContext.User) सेट करता है और लौटाता है। इस चरण में, अजाक्स कॉल की सेवा के लिए पृष्ठ में पहले से ही कुछ विरोधी जालसाजी टोकन छुपा क्षेत्र होना चाहिए। –

+0

फिल हैक ने कुछ दिन पहले इस लेख को पोस्ट किया था। क्या यह आपकी समस्या से संबंधित है? http://haacked.com/archive/2011/10/10/preventing-csrf-with-ajax.aspx ... "समस्या इस तथ्य में निहित है कि हुड के नीचे, कॉल स्टैक के भीतर गहरी, विशेषता peeks एंटी-फर्जी टोकन को पकड़ने के लिए Request.Form संग्रह में। लेकिन जब आप JSON एन्कोडेड डेटा पोस्ट करते हैं, तो बोलने के लिए कोई फॉर्म संग्रह नहीं होता है। " – JasperLamarCrabb

उत्तर

6

आपको लॉगिन पर मौजूद किसी भी मौजूदा फॉर्म टोकन को साफ़ और फिर से करने की आवश्यकता होगी। इसका मतलब है कि आपके लॉगिन कोड को या तो वर्तमान पृष्ठ को रीफ्रेश करना होगा (थोडा इसके AJAX भाग को मारता है), अपने स्वयं के टोकन कार्यान्वयन, या आपको अपना टोकन रीफ्रेश करना होगा। आंशिक दृश्य का अनुरोध करना, टोकन निकालना और अपना फॉर्म अपडेट करना संभव है। आप वास्तव में एक आरामदायक यूआरएल प्राप्त कर सकते हैं जो प्रमाणित उपयोगकर्ता को टोकन के अलावा कुछ भी नहीं देता है। कोई तर्क दे सकता है कि यह एक सुरक्षा मुद्दा है, लेकिन मुझे विश्वास नहीं है क्योंकि किसी भी दृश्य-पक्षीय या अन्यथा अनुरोध करने के बजाय यह टोकन प्राप्त करने का एक आसान तरीका है।

आप आसानी से के माध्यम से बदलने के लिए टोकन उदाहरणों प्राप्त करने के लिए सक्षम होना चाहिए:

 
var token = $('input[name=""__RequestVerificationToken""]'); 

संपादित फिर से पढ़ने के लिए कुछ और समय के बाद - तुम क्यों पर एक टोकन के लिए होता है मैं

सवाल फॉर्म यदि उपयोगकर्ता लॉग इन नहीं है। आप लॉग इन नहीं होने और लॉग इन करते समय उसी फॉर्म को 'संचालित' होने की अनुमति देते हैं? इस मामले में नेट पर भी अधिकांश साइटें लॉगिन के लिए रीडायरेक्ट होंगी। क्या मुझे ये ठीक तरह से समझ आ रहा है? यदि ऐसा है, तो आप यहां टोकन को छोड़ने या अनधिकृत उपयोगकर्ताओं के लिए दूसरे प्रकार के टोकन का उपयोग करने पर विचार करना चाहेंगे।आप मानते हैं कि एक अनधिकृत उपयोगकर्ता पहले से ही एप्लिकेशन में कुछ सबमिट कर सकता है - फिर अगर मैं इसे सही ढंग से समझता हूं - प्रमाणीकृत किए बिना।

+0

आपके अंतिम प्रश्न के लिए, मुझे अनधिकृत उपयोगकर्ताओं के लिए टोकन की आवश्यकता क्यों है, कृपया बेन की टिप्पणी का मेरा उत्तर देखें। मैं टोकन के साथ आंशिक दृश्य बनाने और परिणामों के साथ अपडेट करने का प्रयास करूंगा। एक अच्छे विचार की तरह लगता है! –

+0

अभी तक यह नहीं मिला, लेकिन मैं आपका जवाब स्वीकार करूंगा क्योंकि यह वादा करता है :-) –

3

ठीक है, मैंने जो किया वह जवाब यहां से आया था: jQuery Ajax calls and the Html.AntiForgeryToken() आंशिक के साथ। मैं नॉकआउट का उपयोग कर रहा हूं लेकिन आप में से उन लोगों के लिए परिचित नहीं हैं जिन्हें आप अभी भी आसानी से पालन करने में सक्षम होना चाहिए।

सबसे पहले मेरी एचटीएमएल:

<form id="__AjaxAntiForgeryForm" action="#" method="post">@{Html.RenderPartial("AntiForgeryToken");}</form> 
<div id="loginTestView"> 
    <button data-bind="visible: signedIn() == false,click: signIn">Sign In</button> 
    <button data-bind="visible: signedIn, click: signOut">Sign Out</button> 

    <form> 
     <button data-bind="click: testToken">Test Token</button> 
    </form> 
</div> 

मुख्य अंतर यह जा रहा है कि बजाय @ Html.AntiForgeryToken की() मैं एक आंशिक AntiForgeryToken कि @ Html.AntiForgeryToken() शामिल है।

तो सच में मैं अब बस के साथ एक AntiForgeryToken.cshtml फ़ाइल है स्पष्ट करने के लिए:

@Html.AntiForgeryToken() 

अब जब आप प्रवेश करेंगे/बाहर आप टोकन अद्यतन करने के लिए इतना जावास्क्रिप्ट/jQuery की तरह दिखता है की जरूरत है:

$(document).ready(function() { 
    AddAntiForgeryToken = function (data) { 
     data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val(); 
     return data; 
    }; 

    var viewmodel = function() { 
     var vm = this; 

     vm.signedIn = ko.observable(false); 

     vm.signIn = function() { 
      $.post('Home/SignIn', function() { 
       vm.signedIn(true); 
       $.get('Home/GetAuthToken', function (newToken) { 
        $('#__AjaxAntiForgeryForm').html(newToken); 
       }); 
      }); 

     }; 
     vm.signOut = function() { 
      $.post('Home/SignOut', function() { 
       vm.signedIn(false); 
       $.get('Home/GetAuthToken', function (newToken) { 
        $('#__AjaxAntiForgeryForm').html(newToken); 
       }); 
      }); 
     }; 
     vm.testToken = function() { 
      $.post('Home/TestToken', AddAntiForgeryToken({ stuff: 'stuff' })); 
     }; 
    }; 

    ko.applyBindings(new viewmodel(), $('#loginTestView')[0]); 
}); 

यहां ध्यान देने की मुख्य बात यह है कि $ .get को साइन इन/आउट करने के लिए $। पोस्ट के बाद होने की आवश्यकता है। इस कोड को थोड़ा साफ किया जा सकता है, लेकिन यह मुख्य ले जाया गया है। यदि आप तब से नहीं हैं क्योंकि अनुरोध अतुल्यकालिक हैं। $ .get वास्तव में साइन इन करने से पहले वापस आ सकता है (और शायद होगा)।

ऐसा करना चाहिए। जब टोकन अपडेट किया जाता है तो मैंने किसी अन्य समय में भाग नहीं लिया है, लेकिन आंशिक अपडेट करने के लिए केवल एक और कॉल की आवश्यकता होगी।

+0

अच्छा समाधान @rball, मैं इसे आज़मा दूंगा (हालांकि कुछ समय लगेगा)। –

संबंधित मुद्दे