في كل مرة ينشر فيها المستخدم شيئًا ما يحتوي على <
أو >
في صفحة في تطبيق الويب الخاص بي ، أحصل على هذا الاستثناء.
لا أريد الخوض في مناقشة حول ذكاء طرح استثناء أو تعطل تطبيق ويب بأكمله لأن شخصًا ما أدخل شخصية في مربع نص ، لكنني أبحث عن طريقة أنيقة للتعامل مع هذا.
تعويض اللون الاستثناء والعرض
لقد حدث خطأ ، يرجى العودة وإعادة كتابة النموذج بالكامل مرة أخرى ، لكن هذه المرة ، يرجى عدم استخدام <
لا يبدو المهنية بما فيه الكفاية بالنسبة لي.
سيؤدي تعطيل التحقق من الصحة للنشر (validateRequest="false"
) بالتأكيد إلى تجنب هذا الخطأ ، ولكنه سيترك الصفحة عرضة لعدد من الهجمات.
من الناحية المثالية: عند حدوث إعادة نشر تحتوي على أحرف مقيدة بتنسيق HTML ، سيتم تلقائيًا تشفير تلك القيمة المنشورة في مجموعة النماذج. وبالتالي فإن خاصية .Text
الخاصة بمربع النص الخاص بي ستكون something & lt; html & gt;
هل هناك طريقة يمكنني القيام بذلك من معالج؟
أعتقد أنك تهاجمها من الزاوية الخطأ بمحاولة تشفير جميع البيانات المنشورة.
لاحظ أن "<
" قد يأتي أيضًا من مصادر خارجية أخرى ، مثل حقل قاعدة البيانات ، والتكوين ، وملف ، وموجز وما إلى ذلك.
علاوة على ذلك ، "<
" ليست خطيرة بطبيعتها. إنه أمر خطير فقط في سياق محدد: عند كتابة السلاسل التي لم يتم تشفيرها لإخراج HTML (بسبب XSS).
في سياقات أخرى ، تكون السلاسل الفرعية المختلفة خطيرة ، على سبيل المثال ، إذا كتبت عنوان URL مقدم من المستخدم في رابط ، فقد تكون السلسلة الفرعية "javascript:
" خطيرة. حرف الاقتباس الفردي من ناحية أخرى أمر خطير عند تقريب السلاسل في استعلامات SQL ، ولكنه آمن تمامًا إذا كان جزءًا من اسم مقدم من نموذج أو تمت قراءته من حقل قاعدة بيانات.
خلاصة القول هي: لا يمكنك تصفية الإدخال العشوائي للأحرف الخطرة ، لأن أي حرف قد يكون خطيرًا في الظروف المناسبة. يجب أن تشفر عند النقطة التي قد تصبح فيها بعض الشخصيات المحددة خطرة لأنها تعبر إلى لغة فرعية مختلفة يكون لها فيها معنى خاص. عند كتابة سلسلة إلى HTML ، يجب عليك ترميز الأحرف التي لها معنى خاص في HTML ، باستخدام Server.HtmlEncode. إذا قمت بتمرير سلسلة إلى عبارة SQL ديناميكية ، فيجب عليك ترميز أحرف مختلفة (أو الأفضل ، دع إطار العمل يقوم بذلك نيابة عنك باستخدام عبارات معدة أو ما شابه) ..
عندما أنت متأكد من أنك تقوم بترميز HTML في كل مكان تقوم بتمرير سلاسل إلى HTML ، ثم قم بتعيين validateRequest="false"
في توجيه <%@ Page ... %>
في ملف (ملفات) .aspx
الخاص بك.
في .NET 4 ، قد تحتاج إلى عمل المزيد. في بعض الأحيان يكون من الضروري أيضًا إضافة <httpRuntime requestValidationMode="2.0" />
إلى web.config ( reference ).
يوجد حل مختلف لهذا الخطأ إذا كنت تستخدم ASP.NET MVC:
ج # عينة:
[HttpPost, ValidateInput(false)]
public ActionResult Edit(FormCollection collection)
{
// ...
}
نموذج Visual Basic:
<AcceptVerbs(HttpVerbs.Post), ValidateInput(False)> _
Function Edit(ByVal collection As FormCollection) As ActionResult
...
End Function
في ASP.NET MVC (يبدأ في الإصدار 3) ، يمكنك إضافة AllowHtml
السمة إلى خاصية على النموذج الخاص بك.
يسمح طلب بتضمين علامة HTML أثناء ربط النموذج عن طريق تخطي التحقق من صحة الطلب للخاصية.
[AllowHtml]
public string Description { get; set; }
إذا كنت على .NET 4.0 ، فتأكد من إضافة هذا في web.config ملف داخل علامات <system.web>
:
<httpRuntime requestValidationMode="2.0" />
في .NET 2.0 ، طلب التحقق من الصحة المطبق فقط على طلبات aspx
. في. NET 4.0 تم توسيع هذا ليشمل جميع الطلبات. يمكنك الرجوع إلى فقط إجراء التحقق من صحة XSS عند معالجة .aspx
عن طريق تحديد:
requestValidationMode="2.0"
يمكنك تعطيل طلب التحقق من الصحة بالكامل عن طريق تحديد:
validateRequest="false"
بالنسبة لـ ASP.NET 4.0 ، يمكنك السماح بالعلامة كمدخلات لصفحات محددة بدلاً من الموقع بأكمله من خلال وضعه كله في عنصر <location>
. سيضمن هذا أن تكون جميع صفحاتك الأخرى آمنة. لا تحتاج إلى وضع ValidateRequest="false"
في صفحة .aspx الخاصة بك.
<configuration>
...
<location path="MyFolder/.aspx">
<system.web>
<pages validateRequest="false" />
<httpRuntime requestValidationMode="2.0" />
</system.web>
</location>
...
</configuration>
يمكنك التحكم في هذا داخل web.config ، لأنه يمكنك أن ترى على مستوى الموقع الصفحات التي تسمح بالترميز كمدخلات.
لا تزال بحاجة إلى التحقق من صحة الإدخال على الصفحات التي يتم فيها تعطيل التحقق من صحة الطلب.
الإجابات السابقة رائعة ، ولكن لم يقل أي أحد كيفية استبعاد حقل واحد من أن يتم التحقق من صحة لحقن HTML/JavaScript. لا أعرف الإصدارات السابقة ، ولكن في MVC3 Beta يمكنك القيام بذلك:
[HttpPost, ValidateInput(true, Exclude = "YourFieldName")]
public virtual ActionResult Edit(int id, FormCollection collection)
{
...
}
لا يزال هذا يتحقق من صحة جميع الحقول باستثناء الحقل المستبعد. الشيء الجميل في هذا الأمر هو أن سمات التحقق من الصحة ما زالت تتحقق من الحقل ، لكنك لا تحصل على استثناءات "طلب خطير محتمل. تم اكتشاف قيمة من العميل".
لقد استخدمت هذا للتحقق من صحة التعبير العادي. لقد صنعت ValidationAttribute الخاص بي لمعرفة ما إذا كان التعبير العادي صالحًا أم لا. نظرًا لأن التعبيرات العادية يمكن أن تحتوي على شيء يشبه البرنامج النصي ، قمت بتطبيق الرمز أعلاه - لا يزال يتم التحقق من التعبير العادي إذا كان صحيحًا أم لا ، ولكن ليس إذا كان يحتوي على برامج نصية أو HTML.
في ASP.NET MVC تحتاج إلى تعيين requestValidationMode = "2.0" و validateRequest = "false" في web.config ، وتطبيق سمة ValidateInput على إجراء وحدة التحكم الخاصة بك:
<httpRuntime requestValidationMode="2.0"/>
<configuration>
<system.web>
<pages validateRequest="false" />
</system.web>
</configuration>
و
[Post, ValidateInput(false)]
public ActionResult Edit(string message) {
...
}
يمكنك تشفير HTML مربع نص المحتوى ، ولكن للأسف لن يمنع هذا الاستثناء من الحدوث. في تجربتي لا توجد طريقة للتغلب عليها ، وعليك تعطيل التحقق من صحة الصفحة. من خلال القيام بذلك ، فأنت تقول: "سأكون حذرًا ، وأعدكم".
بالنسبة إلى MVC ، تجاهل التحقق من صحة الإدخال عن طريق الإضافة
[ValidateInput (كاذبة)]
فوق كل عمل في المراقب المالي.
يمكنك التقاط هذا الخطأ في Global.asax. ما زلت أرغب في التحقق من الصحة ، ولكنني أعرض رسالة مناسبة. على المدونة المدرجة أدناه ، كانت عينة مثل هذه متاحة.
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if (ex is HttpRequestValidationException)
{
Response.Clear();
Response.StatusCode = 200;
Response.Write(@"[html]");
Response.End();
}
}
يبدو أن إعادة التوجيه إلى صفحة أخرى استجابة معقولة للاستثناء.
http://www.romsteady.net/blog/2007/06/how-to-catch-httprequestvalidationexcep.html
يرجى الأخذ في الاعتبار أن بعض عناصر تحكم .NET ستعمل تلقائيًا على ترميز HTML للإخراج. على سبيل المثال ، سيؤدي تعيين الخاصية Text. في عنصر تحكم TextBox إلى ترميزها تلقائيًا. هذا يعني بالتحديد تحويل <
إلى <
و >
إلى >
و &
إلى &
. لذلك كن حذرا من القيام بذلك ...
myTextBox.Text = Server.HtmlEncode(myStringFromDatabase); // Pseudo code
ومع ذلك ، فإن خاصية .Text الخاصة بـ HyperLink و Literal و Label لن تقوم بتشفير HTML ، لذا فإن التفاف Server.HtmlEncode ()؛ حول أي شيء يتم تعيينه على هذه الخصائص أمر لا بد منه إذا كنت ترغب في منع <script> window.location = "http://www.google.com"; </script>
من الإخراج إلى صفحتك وتنفيذها فيما بعد.
قم بإجراء بعض التجارب لمعرفة ما الذي يتم ترميزه وما لا يتم ترميزه.
والجواب على هذا السؤال بسيط:
var varname = Request.Unvalidated["parameter_name"];
هذا من شأنه تعطيل التحقق من الصحة لطلب معين.
في ملف web.config ، ضمن العلامات ، أدخل عنصر httpRuntime مع السمة requestValidationMode = "2.0". إضافة السمة validateRequest = "false" أيضًا في عنصر الصفحات.
مثال:
<configuration>
<system.web>
<httpRuntime requestValidationMode="2.0" />
</system.web>
<pages validateRequest="false">
</pages>
</configuration>
إذا كنت لا ترغب في تعطيل ValidateRequest ، فستحتاج إلى تنفيذ وظيفة JavaScript لتجنب الاستثناء. إنه ليس الخيار الأفضل ، لكنه يعمل.
function AlphanumericValidation(evt)
{
var charCode = (evt.charCode) ? evt.charCode : ((evt.keyCode) ? evt.keyCode :
((evt.which) ? evt.which : 0));
// User type Enter key
if (charCode == 13)
{
// Do something, set controls focus or do anything
return false;
}
// User can not type non alphanumeric characters
if ( (charCode < 48) ||
(charCode > 122) ||
((charCode > 57) && (charCode < 65)) ||
((charCode > 90) && (charCode < 97))
)
{
// Show a message or do something
return false;
}
}
ثم في التعليمات البرمجية الخلفية ، في حدث PageLoad ، أضف السمة إلى عنصر التحكم الخاص بك مع الكود التالي:
Me.TextBox1.Attributes.Add("OnKeyPress", "return AlphanumericValidation(event);")
يبدو أن أحداً لم يذكر ما يلي أدناه ، ولكنه يعمل على حل المشكلة بالنسبة لي. وقبل أن يقول أي شخص نعم ، إنه Visual Basic ... يوك.
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Example.aspx.vb" Inherits="Example.Example" **ValidateRequest="false"** %>
لا أعرف إذا كان هناك أي سلبيات ، لكن بالنسبة لي كان هذا رائعًا.
حل آخر هو:
protected void Application_Start()
{
...
RequestValidator.Current = new MyRequestValidator();
}
public class MyRequestValidator: RequestValidator
{
protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
{
bool result = base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);
if (!result)
{
// Write your validation here
if (requestValidationSource == RequestValidationSource.Form ||
requestValidationSource == RequestValidationSource.QueryString)
return true; // Suppress error message
}
return result;
}
}
إذا كنت تستخدم Framework 4.0 ، فسيكون الإدخال في web.config (<pages validateRequest = "false" />)
<configuration>
<system.web>
<pages validateRequest="false" />
</system.web>
</configuration>
إذا كنت تستخدم Framework 4.5 ، فقم بإدخال الإدخال في web.config (requestValidationMode = "2.0")
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" requestValidationMode="2.0"/>
</system.web>
إذا كنت تريد صفحة واحدة فقط بعد ذلك ، في ملف aspx ، يجب أن تضع السطر الأول كما يلي:
<%@ Page EnableEventValidation="false" %>
إذا كان لديك بالفعل شيء مثل <٪ @ Page ، فقم فقط بإضافة الباقي => EnableEventValidation="false"
٪>
أوصي بعدم القيام بذلك.
في ASP.NET ، يمكنك التقاط الاستثناء والقيام بشيء حيال ذلك ، مثل عرض رسالة مألوفة أو إعادة توجيه إلى صفحة أخرى ... هناك أيضًا إمكانية أن تتمكن من معالجة التحقق من صحة نفسك ...
عرض رسالة ودية:
protected override void OnError(EventArgs e)
{
base.OnError(e);
var ex = Server.GetLastError().GetBaseException();
if (ex is System.Web.HttpRequestValidationException)
{
Response.Clear();
Response.Write("Invalid characters."); // Response.Write(HttpUtility.HtmlEncode(ex.Message));
Response.StatusCode = 200;
Response.End();
}
}
أعتقد أنك يمكن أن تفعل ذلك في وحدة نمطية ؛ لكن هذا يترك بعض الأسئلة مفتوحة ؛ ماذا لو كنت تريد حفظ المدخلات في قاعدة البيانات؟ فجأة لأنك تقوم بحفظ البيانات المشفرة في قاعدة البيانات ، ينتهي بك الأمر إلى الوثوق في المدخلات منه والتي ربما تكون فكرة سيئة. من المثالي أن تقوم بتخزين البيانات غير المشفرة الخام في قاعدة البيانات والتشفير في كل مرة.
يعد تعطيل الحماية على مستوى الصفحة ثم الترميز في كل مرة خيارًا أفضل.
بدلاً من استخدام Server.HtmlEncode ، يجب أن تنظر إلى الأحدث والأكمل مكتبة Anti-XSS من فريق Microsoft ACE.
الحلول الأخرى هنا لطيفة ، ومع ذلك ، فإنه من الألم الملكي في الجزء الخلفي أن تضطر إلى تطبيق [AllowHtml] على كل خاصية طراز واحد ، خاصة إذا كان لديك أكثر من 100 نموذج في موقع مناسب الحجم.
إذا كنت مثلي ، فأنت تريد إيقاف تشغيل هذه الميزة (بدون جدوى إلى حد كبير من IMHO) خارج الموقع ، ويمكنك تخطي طريقة Execute () في وحدة التحكم الأساسية (إذا لم يكن لديك بالفعل وحدة تحكم أساسية ، أقترح عليك إنشاء واحدة ، يمكن أن تكون مفيدة جدا لتطبيق وظيفة مشتركة).
protected override void Execute(RequestContext requestContext)
{
// Disable requestion validation (security) across the whole site
ValidateRequest = false;
base.Execute(requestContext);
}
فقط تأكد من قيامك بتشفير HTML لكل شيء يتم ضخه إلى طرق العرض التي تأتي من إدخال المستخدم (إنه السلوك الافتراضي في ASP.NET MVC 3 مع Razor على أي حال ، لذلك ما لم يكن سببًا غريبًا أنك تستخدم Html.Raw () لك لا ينبغي أن تتطلب هذه الميزة.
لقد وجدت حلاً يستخدم JavaScript لتشفير البيانات ، والتي تم فك تشفيرها في .NET (ولا تتطلب jQuery).
أضف وظيفة JavaScript التالية إلى رأسك.
function boo () {targetText = document.getElementById ("HiddenField1")؛ sourceText = document.getElementById ("userbox")؛ targetText.value = escape (sourceText.innerText)؛ }في textarea الخاص بك ، قم بتضمين onchange يستدعي boo ():
<textarea id="userbox" onchange="boo();"></textarea>
أخيرًا ، في .NET ، استخدم
string val = Server.UrlDecode(HiddenField1.Value);
أدرك أن هذا اتجاه واحد - إذا كنت بحاجة إلى اتجاهين ، فسيتعين عليك أن تكون مبدعًا ، ولكن هذا يوفر حلاً إذا لم تتمكن من تحرير web.config
إليكم مثالًا توصلت إليه (MC9000) واستخدمه عبر jQuery:
$(document).ready(function () {
$("#txtHTML").change(function () {
var currentText = $("#txtHTML").text();
currentText = escape(currentText); // Escapes the HTML including quotations, etc
$("#hidHTML").val(currentText); // Set the hidden field
});
// Intercept the postback
$("#btnMyPostbackButton").click(function () {
$("#txtHTML").val(""); // Clear the textarea before POSTing
// If you don't clear it, it will give you
// the error due to the HTML in the textarea.
return true; // Post back
});
});
والترميز:
<asp:HiddenField ID="hidHTML" runat="server" />
<textarea id="txtHTML"></textarea>
<asp:Button ID="btnMyPostbackButton" runat="server" Text="Post Form" />
هذا يعمل بشكل رائع. إذا حاول أحد المتطفلين نشر جافا سكريبت عبر تجاوزه ، فسوف يرون الخطأ فقط. يمكنك حفظ كل هذه البيانات المشفرة في قاعدة بيانات أيضًا ، ثم إلغاء تحديدها (من جانب الخادم) ، وتحليلها والتحقق من وجود هجمات قبل عرضها في أي مكان آخر.
قم بتعطيل التحقق من صحة الصفحة إذا كنت حقًا بحاجة إلى أحرف خاصة مثل >
و <
، إلخ. ثم تأكد من أنه عند عرض إدخال المستخدم ، تكون البيانات مشفرة بتنسيق HTML.
هناك ثغرة أمنية في التحقق من صحة الصفحة ، لذلك يمكن تجاوزها. أيضا لا ينبغي الاعتماد على التحقق من صحة الصفحة.
السبب
يقوم ASP.NET افتراضيًا بالتحقق من صحة جميع عناصر التحكم في الإدخال للمحتويات التي قد تكون غير آمنة والتي يمكن أن تؤدي إلى برمجة نصية عبر المواقع (XSS) و حقن SQL . وبالتالي ، لا يسمح بهذا المحتوى عن طريق طرح الاستثناء أعلاه. بشكل افتراضي ، يوصى بالسماح بهذا الاختيار في كل إعادة النشر.
الحل
في العديد من المناسبات ، تحتاج إلى إرسال محتوى HTML إلى صفحتك من خلال Rich TextBoxes أو Rich Text Editors. في هذه الحالة ، يمكنك تجنب هذا الاستثناء عن طريق تعيين علامة ValidateRequest في توجيه @Page
إلى false.
<%@ Page Language="C#" AutoEventWireup="true" ValidateRequest = "false" %>
سيؤدي هذا إلى تعطيل التحقق من صحة طلبات الصفحة التي قمت بتعيين علامة ValidateRequest على "خطأ". إذا كنت ترغب في تعطيل هذا ، تحقق من تطبيق الويب الخاص بك ؛ ستحتاج إلى تعيينه على "خطأ" في قسم web.config <system.web>
<pages validateRequest ="false" />
بالنسبة إلى .NET 4.0 أو الأطر الأعلى ، ستحتاج أيضًا إلى إضافة السطر التالي في قسم <system.web> لجعل العمل أعلاه.
<httpRuntime requestValidationMode = "2.0" />
هذا هو. آمل أن يكون هذا يساعدك في التخلص من القضية المذكورة أعلاه.
المرجع بواسطة: خطأ ASP.Net: تم اكتشاف قيمة Request.Form يحتمل أن تكون خطرة من العميل
كنت أتلقى هذا الخطأ أيضًا.
في حالتي ، أدخل المستخدم حرفًا مشددًا á
في اسم الدور (فيما يتعلق بموفر عضوية ASP.NET).
أقوم بتمرير اسم الدور إلى طريقة لمنح المستخدمين لهذا الدور وكان فشل طلب النشر $.ajax
فشلاً ذريعًا ...
فعلت هذا لحل المشكلة:
بدلا من
data: { roleName: '@Model.RoleName', users: users }
افعل هذا
data: { roleName: '@Html.Raw(@Model.RoleName)', users: users }
@Html.Raw
فعلت الحيلة.
كنت أحصل على اسم الدور كقيمة HTML roleName="Cadastro bás"
. تم حظر هذه القيمة مع كيان HTML á
بواسطة ASP.NET MVC. الآن أحصل على قيمة المعلمة roleName
بالطريقة التي ينبغي أن تكون: roleName="Cadastro Básico"
و ASP.NET MVC Engine لن يمنع الطلب بعد الآن.
يمكنك أيضًا استخدام دالة JavaScript { Escape (string) لاستبدال الحروف الخاصة. ثم استخدم جانب الخادم Server . URLDecode (string) للتبديل مرة أخرى.
وبهذه الطريقة ، لا يتعين عليك إيقاف تشغيل التحقق من صحة الإدخال ، وسيكون من الواضح أكثر للمبرمجين الآخرين أن السلسلة قد تحتوي على محتوى HTML.
انتهى بي الأمر باستخدام JavaScript قبل كل إعادة بحث للتحقق من الأحرف التي لا تريدها ، مثل:
<asp:Button runat="server" ID="saveButton" Text="Save" CssClass="saveButton" OnClientClick="return checkFields()" />
function checkFields() {
var tbs = new Array();
tbs = document.getElementsByTagName("input");
var isValid = true;
for (i=0; i<tbs.length; i++) {
if (tbs(i).type == 'text') {
if (tbs(i).value.indexOf('<') != -1 || tbs(i).value.indexOf('>') != -1) {
alert('<> symbols not allowed.');
isValid = false;
}
}
}
return isValid;
}
منحت صفحتي في الغالب إدخال البيانات ، وهناك عدد قليل جدًا من العناصر التي تقوم بإعادة النشر ، ولكن على الأقل يتم الاحتفاظ ببياناتها.
طالما أن هذه فقط "<" و ">" (وليس الاقتباس المزدوج نفسه) أحرف وتستخدمها في سياق مثل <input value = "this" /> ، أنت آمن (أثناء استخدام <textarea> هذا واحد </textarea> ستكون عرضة بالطبع). قد يؤدي ذلك إلى تبسيط الموقف لديك ، ولكن مع أي شيء استخدم أكثر من أحد الحلول المنشورة الأخرى.
إذا كنت تبحث فقط لإخبار المستخدمين بأن <و> لن يتم استخدامهما ولكن ، لن ترغب في إعادة معالجة النموذج بالكامل/إعادة نشره (وفقدان جميع المدخلات) قبل ذلك ، هل يمكنك ببساطة عدم وضع المدقق في جميع أنحاء الميدان للكشف عن تلك الشخصيات (وربما غيرها من الشخصيات التي يحتمل أن تكون خطرة)؟
يمكنك استخدام شيء مثل:
var nvc = Request.Unvalidated().Form;
في وقت لاحق ، يجب أن تعمل nvc["yourKey"]
.
لا شيء من الاقتراحات عملت بالنسبة لي. لم أكن أرغب في إيقاف تشغيل هذه الميزة لموقع الويب بالكامل على أي حال لأن 99٪ من الوقت لا أريد للمستخدمين وضع HTML على نماذج الويب. لقد قمت للتو بإنشاء عملي الخاص حول الطريقة لأنني الوحيد الذي يستخدم هذا التطبيق المحدد. أقوم بتحويل الإدخال إلى HTML في الكود الموجود خلفه وأدخله في قاعدة البيانات الخاصة بي.
يمكنك تلقائيًا ترميز HTML في حقل Model Binder المخصص. حل بلدي مختلفة ، لقد وضعت خطأ في ModelState وعرض رسالة خطأ بالقرب من الميدان. من السهل تعديل هذا الرمز للتشفير تلقائيًا
public class AppModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
try
{
return base.CreateModel(controllerContext, bindingContext, modelType);
}
catch (HttpRequestValidationException e)
{
HandleHttpRequestValidationException(bindingContext, e);
return null; // Encode here
}
}
protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext,
PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
{
try
{
return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
}
catch (HttpRequestValidationException e)
{
HandleHttpRequestValidationException(bindingContext, e);
return null; // Encode here
}
}
protected void HandleHttpRequestValidationException(ModelBindingContext bindingContext, HttpRequestValidationException ex)
{
var valueProviderCollection = bindingContext.ValueProvider as ValueProviderCollection;
if (valueProviderCollection != null)
{
ValueProviderResult valueProviderResult = valueProviderCollection.GetValue(bindingContext.ModelName, skipValidation: true);
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
}
string errorMessage = string.Format(CultureInfo.CurrentCulture, "{0} contains invalid symbols: <, &",
bindingContext.ModelMetadata.DisplayName);
bindingContext.ModelState.AddModelError(bindingContext.ModelName, errorMessage);
}
}
في Application_Start:
ModelBinders.Binders.DefaultBinder = new AppModelBinder();
لاحظ أنه يعمل فقط لحقول النموذج. لا يتم تمرير القيمة الخطرة إلى طراز وحدة التحكم ، ولكن يتم تخزينها في ModelState ويمكن إعادة عرضها على النموذج مع ظهور رسالة خطأ.
قد يتم التعامل مع الأحرف الخطرة في URL بهذه الطريقة:
private void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
HttpContext httpContext = HttpContext.Current;
HttpException httpException = exception as HttpException;
if (httpException != null)
{
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Error");
var httpCode = httpException.GetHttpCode();
switch (httpCode)
{
case (int)HttpStatusCode.BadRequest /* 400 */:
if (httpException.Message.Contains("Request.Path"))
{
httpContext.Response.Clear();
RequestContext requestContext = new RequestContext(new HttpContextWrapper(Context), routeData);
requestContext.RouteData.Values["action"] ="InvalidUrl";
requestContext.RouteData.Values["controller"] ="Error";
IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
IController controller = factory.CreateController(requestContext, "Error");
controller.Execute(requestContext);
httpContext.Server.ClearError();
Response.StatusCode = (int)HttpStatusCode.BadRequest /* 400 */;
}
break;
}
}
}
ErrorController:
public class ErrorController : Controller
{
public ActionResult InvalidUrl()
{
return View();
}
}
كما هو موضح في تعليقي على إجابة Sel ، هذا هو امتدادنا لمدقق الطلب المخصص.
public class SkippableRequestValidator : RequestValidator
{
protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex)
{
if (collectionKey != null && collectionKey.EndsWith("_NoValidation"))
{
validationFailureIndex = 0;
return true;
}
return base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);
}
}
بالنسبة لأولئك الذين لا يستخدمون ربط النموذج ، والذين يستخرجون كل معلمة من Request.Form ، والذين يتأكدون من أن نص الإدخال لن يسبب أي ضرر ، فهناك طريقة أخرى. ليس حلاً رائعًا ولكنه سيؤدي المهمة.
من جانب العميل ، قم بترميزه كـ uri ثم أرسله.
منها مثلا:
encodeURIComponent($("#MsgBody").val());
من جانب الخادم ، قم بقبوله وفك تشفيره كـ uri.
منها مثلا:
string temp = !string.IsNullOrEmpty(HttpContext.Current.Request.Form["MsgBody"]) ?
System.Web.HttpUtility.UrlDecode(HttpContext.Current.Request.Form["MsgBody"]) :
null;
أو
string temp = !string.IsNullOrEmpty(HttpContext.Current.Request.Form["MsgBody"]) ?
System.Uri.UnescapeDataString(HttpContext.Current.Request.Form["MsgBody"]) :
null;
الرجاء البحث عن الاختلافات بين UrlDecode
و UnescapeDataString
يجب عليك استخدام أسلوب Server.HtmlEncode لحماية موقعك من الإدخال الخطير.
في حالتي ، باستخدام asp: عنصر تحكم مربع نص (Asp.net 4.5) ، بدلاً من تعيين الصفحة بالكامل لـ validateRequest="false"
التي استخدمتها
<asp:TextBox runat="server" ID="mainTextBox"
ValidateRequestMode="Disabled"
></asp:TextBox>
على مربع النص الذي تسبب في الاستثناء.
أخيرًا وليس آخرًا ، يرجى ملاحظة عناصر تحكم ربط بيانات ASP.NET تلقائيًا ترميز قيم أثناء ربط البيانات. هذا يغير السلوك الافتراضي لجميع عناصر تحكم ASP.NET (TextBox ، Label الخ) الموجودة في ItemTemplate
. يوضح النموذج التالي (ValidateRequest
معيَّنة إلى false):
aspx
<%@ Page Language="C#" ValidateRequest="false" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication17._Default" %> <html> <body>
<form runat="server">
<asp:FormView ID="FormView1" runat="server" ItemType="WebApplication17.S" SelectMethod="FormView1_GetItem">
<ItemTemplate>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
<asp:Label ID="Label1" runat="server" Text="<%#: Item.Text %>"></asp:Label>
<asp:TextBox ID="TextBox2" runat="server" Text="<%#: Item.Text %>"></asp:TextBox>
</ItemTemplate>
</asp:FormView>
</form>
الكود خلف
public partial class _Default : Page
{
S s = new S();
protected void Button1_Click(object sender, EventArgs e)
{
s.Text = ((TextBox)FormView1.FindControl("TextBox1")).Text;
FormView1.DataBind();
}
public S FormView1_GetItem(int? id)
{
return s;
}
}
public class S
{
public string Text { get; set; }
}
'
قيمة Label1.Text
: '
قيمة TextBox2.Text
: &#39;
<script>alert('attack!');</script>
قيمة Label1.Text
: <script>alert('attack!');</script>
قيمة TextBox2.Text
: <script>alert('attack!');</script>
حل
لا أحب إيقاف تشغيل التحقق من صحة النشر (validateRequest = "false"). من ناحية أخرى ، من غير المقبول أن يتعطل التطبيق لمجرد أن المستخدم البريء يحدث لكتابة <x
أو شيء ما.
لذلك كتبت وظيفة جافا سكريبت من جانب العميل (xssCheckValidates) التي تجعل الاختيار الأولي. تسمى هذه الوظيفة عندما تكون هناك محاولة لنشر بيانات النموذج ، مثل هذا:
<form id="form1" runat="server" onsubmit="return xssCheckValidates();">
الوظيفة بسيطة للغاية ويمكن تحسينها ولكنها تقوم بعملها.
يرجى ملاحظة أن الغرض من ذلك ليس حماية النظام من القرصنة ، بل يهدف إلى حماية المستخدمين من تجربة سيئة. لا يزال تشغيل التحقق من صحة الطلب على الخادم ، وهو (جزء من) حماية النظام (إلى الحد الذي يمكنه القيام به).
السبب في أنني أقول "جزء من" هنا هو أنني سمعت أن التحقق من صحة الطلب المدمج قد لا يكون كافياً ، لذلك قد تكون هناك حاجة إلى وسائل تكميلية أخرى للحصول على حماية كاملة. ولكن ، مرة أخرى ، فإن وظيفة javascript التي أقدمها هنا لها لا شيء تتعلق بحماية النظام. إنه فقط يعني التأكد من أن المستخدمين لن يتمتعوا بتجربة سيئة.
يمكنك تجربتها هنا:
function xssCheckValidates() {
var valid = true;
var inp = document.querySelectorAll(
"input:not(:disabled):not([readonly]):not([type=hidden])" +
",textarea:not(:disabled):not([readonly])");
for (var i = 0; i < inp.length; i++) {
if (!inp[i].readOnly) {
if (inp[i].value.indexOf('<') > -1) {
valid = false;
break;
}
if (inp[i].value.indexOf('&#') > -1) {
valid = false;
break;
}
}
}
if (valid) {
return true;
} else {
alert('In one or more of the text fields, you have typed\r\nthe character "<" or the character sequence "&#".\r\n\r\nThis is unfortunately not allowed since\r\nit can be used in hacking attempts.\r\n\r\nPlease edit the field and try again.');
return false;
}
}
<form onsubmit="return xssCheckValidates();" >
Try to type < or &# <br/>
<input type="text" /><br/>
<textarea></textarea>
<input type="submit" value="Send" />
</form>
بالنسبة لأولئك منا الذين ما زالوا عالقين في نماذج الويب ، وجدت الحل التالي الذي يمكنك من تعطيل التحقق من الصحة في حقل واحد فقط! (أكره تعطيله للصفحة بأكملها.)
VB.NET:
Public Class UnvalidatedTextBox
Inherits TextBox
Protected Overrides Function LoadPostData(postDataKey As String, postCollection As NameValueCollection) As Boolean
Return MyBase.LoadPostData(postDataKey, System.Web.HttpContext.Current.Request.Unvalidated.Form)
End Function
End Class
C #:
public class UnvalidatedTextBox : TextBox
{
protected override bool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
return base.LoadPostData(postDataKey, System.Web.HttpContext.Current.Request.Unvalidated.Form);
}
}
الآن فقط استخدم <prefix:UnvalidatedTextBox id="test" runat="server" />
بدلاً من <asp:TextBox
، ويجب أن يسمح لجميع الأحرف (هذا مثالي لحقول كلمة المرور!)
أعلم أن هذا السؤال يتعلق بنشر النموذج ، لكنني أود أن أضيف بعض التفاصيل للأشخاص الذين تلقوا هذا الخطأ في ظروف الآخرين. يمكن أن تحدث أيضًا على معالج يستخدم لتنفيذ خدمة ويب.
افترض أن عميل الويب الخاص بك يرسل POST أو طلبات PUT باستخدام ajax ويرسل إما json أو xml نصًا أو بيانات أولية (محتوى ملف) إلى خدمة الويب الخاصة بك. نظرًا لأن خدمة الويب الخاصة بك لا تحتاج إلى الحصول على أي معلومات من رأس Content-Type ، فإن شفرة JavaScript الخاصة بك لم تقم بتعيين هذا الرأس على طلب ajax الخاص بك. ولكن إذا لم تقم بتعيين هذا الرأس على طلب أجاكس POST/PUT ، فقد تضيف Safari هذا العنوان: "Content-Type: application/x-www-form-urlencoded". لاحظت أنه في Safari 6 على iPhone ، ولكن قد تعمل إصدارات Safari الأخرى/OS أو Chrome على نفس الشيء. لذلك ، عند تلقي جزء Content-Type هذا ، يفترض جزء من .NET Framework أن بنية بيانات نص الطلب تتوافق مع نشر نموذج html بينما لا تقوم بذلك وتصدر استثناء HttpRequestValidationException. من الواضح أن أول ما يجب فعله هو تعيين رأس Content-Type دائمًا على أي شيء ما عدا نوع MIME للنموذج على طلب POST/PUT ajax حتى وإن كان غير مفيد لخدمة الويب الخاصة بك.
لقد اكتشفت هذه التفاصيل أيضًا:
في هذه الظروف ، يتم رفع استثناء HttpRequestValidationException عندما تحاول التعليمة البرمجية الوصول إلى مجموعة HttpRequest.Params. ولكن من المستغرب أن هذا الاستثناء لا يتم رفعه عندما يصل إلى مجموعة HttpRequest.ServerVariables. هذا يدل على أنه في حين أن هاتين المجموعتين يبدو أنهما متطابقتان تقريبًا ، يصل أحدهما إلى بيانات الطلب من خلال اختبارات الأمان والآخر لا يقوم بذلك.
في .Net 4.0 وما بعده ، وهو الحالة المعتادة ، ضع الإعداد التالي في system.web
<system.web>
<httpRuntime requestValidationMode="2.0" />
استخدم Server.HtmlEncode("yourtext");
أرى أن هناك الكثير مكتوب حول هذا ... ولم أجد هذا مذكورًا. كان هذا متاحًا منذ .NET Framework 4.5
يعد ValidateRequestMode إعداد عنصر تحكم خيارًا رائعًا. بهذه الطريقة ، لا تزال عناصر التحكم الأخرى في الصفحة محمية. لا web.config التغييرات اللازمة.
protected void Page_Load(object sender, EventArgs e)
{
txtMachKey.ValidateRequestMode = ValidateRequestMode.Disabled;
}