ลำดับการหลีกเลี่ยงคู่ภายใน url: โมดูลการกรองการร้องขอถูกกำหนดค่าให้ปฏิเสธคำขอที่มีลำดับการหลีกเลี่ยงคู่


86

ในแอปพลิเคชัน ASP.NET MVC ของฉันฉันกำลังพยายามใช้ URL ดังต่อไปนี้:

/ product / tags / for + family

เมื่อฉันพยายามเรียกใช้แอปพลิเคชันของฉันด้วยการกำหนดค่าเริ่มต้นฉันได้รับข้อความนี้พร้อมรหัสตอบกลับ 404.11:

ข้อผิดพลาด HTTP 404.11 - ไม่พบ

โมดูลการกรองการร้องขอถูกกำหนดค่าให้ปฏิเสธคำขอที่มีลำดับการหลีกเลี่ยงคู่

ฉันสามารถแก้ไขข้อผิดพลาดนี้ได้โดยการติดตั้งโค้ดด้านล่างใน web.config ของฉัน:

  <system.webServer>
    <security>
      <requestFiltering allowDoubleEscaping="true" />
    </security>
  </system.webServer>

ตอนนี้ฉันไม่ได้รับอะไร404.11เลย

สิ่งที่ฉันสงสัยคือฉันกำลังเปิดช่องโหว่ด้านความปลอดภัยประเภทใดด้วยการใช้งานนี้

BTW ใบสมัครของฉันอยู่ภายใต้การและทำงานภายใต้.Net Framework 4.0IIS 7.5


เป็นไปได้ไหมที่จะเข้าถึงทรัพยากรที่ต้องการโดยใช้/product/tags/for%20familiesแทน จากนั้นคุณมีวิธีแก้ปัญหาสำหรับรหัสที่มีช่องว่าง หรือฉันอยู่ที่นี่โดยสมบูรณ์?
Anders Tornblad

@atornblad ฉันเดาว่าเล็กน้อย คำถามของฉัน: สิ่งที่ฉันสงสัยคือฉันกำลังเปิดช่องโหว่ด้านความปลอดภัยประเภทใดด้วยการใช้งานนี้
tugberk

คำตอบ:


57

ช่องโหว่ด้านความปลอดภัยที่คุณอาจเปิดขึ้นเกี่ยวข้องกับการแทรกโค้ด - การแทรก HTML, การแทรก JavaScript หรือการแทรก SQL

การตั้งค่าเริ่มต้นปกป้องคุณจากการโจมตีแบบกึ่งมีประสิทธิภาพโดยไม่อนุญาตให้กลยุทธ์การฉีดทั่วไปทำงานได้ ยิ่งคุณลบการรักษาความปลอดภัยเริ่มต้นมากเท่าไหร่คุณก็ยิ่งต้องคิดถึงสิ่งที่คุณทำกับข้อมูลที่ป้อนผ่าน URL, GET request querystrings, POST request data, HTTP headers เป็นต้น ...

ตัวอย่างเช่นหากคุณกำลังสร้างแบบสอบถาม SQL แบบไดนามิกตามidพารามิเตอร์ของวิธีการดำเนินการของคุณเช่นนี้:

public ActionResult Tags(string id)
{
    var sql = "SELECT * FROM Tags Where tagName = '" + id + "'";
    // DO STUFF...
}

(... ซึ่งไม่ใช่ความคิดที่ดี) การป้องกันเริ่มต้นที่วางไว้โดย. NET framework อาจหยุดสถานการณ์ที่อันตรายกว่าเช่นผู้ใช้ที่ร้องขอ URL นี้:

/product/tags/1%27;drop%20table%20Tags;%20--

แนวคิดทั้งหมดคือการปฏิบัติต่อทุกส่วนของ URL และปัจจัยการผลิตอื่น ๆ ในการดำเนินการตามวิธีการคุกคามที่เป็นไปได้ การตั้งค่าความปลอดภัยเริ่มต้นให้การป้องกันบางอย่างแก่คุณ การตั้งค่าความปลอดภัยเริ่มต้นแต่ละรายการที่คุณเปลี่ยนจะเปิดขึ้นสำหรับความเลวร้ายที่อาจเกิดขึ้นเล็กน้อยซึ่งคุณต้องจัดการด้วยตนเอง

ฉันคิดว่าคุณไม่ได้สร้างแบบสอบถาม SQL ด้วยวิธีนี้ แต่สิ่งที่ส่อเสียดเกิดขึ้นเมื่อคุณเก็บข้อมูลของผู้ใช้ไว้ในฐานข้อมูลของคุณจากนั้นจึงแสดงข้อมูลเหล่านั้นในภายหลัง ผู้ใช้ที่ไม่ประสงค์ดีสามารถจัดเก็บ JavaScript หรือ HTML ไว้ในฐานข้อมูลของคุณที่ไม่มีการเข้ารหัสซึ่งจะคุกคามผู้ใช้ระบบของคุณรายอื่น


6

ความเสี่ยงด้านความปลอดภัย

การตั้งค่าที่allowDoubleEscapingจะใช้กับpath(CS-Uri ก้าน) และจะมีการอธิบายที่ดีที่สุดโดยOWASP ดับเบิลเข้ารหัส เทคนิคนี้ใช้เพื่อหลีกเลี่ยงการควบคุมความปลอดภัยโดยการเข้ารหัส URL คำขอสองครั้ง โดยใช้ URL ของคุณเป็นตัวอย่าง:

/product/tags/for+families --> /product/tags/for%2Bfamilies --> /product/tags/for%252Bfamilies

/product/tags/for+familiesสมมติว่ามีการควบคุมการรักษาความปลอดภัยโดยเฉพาะสำหรับ คำขอมาถึง/product/tags/for%252Bfamiliesซึ่งเป็นทรัพยากรเดียวกันแม้ว่าจะไม่ถูกตรวจสอบโดยการควบคุมความปลอดภัยดังกล่าวข้างต้น ฉันใช้คำทั่วไปของการควบคุมความปลอดภัยเพราะอาจเป็นอะไรก็ได้เช่นต้องการผู้ใช้ที่พิสูจน์ตัวตนการตรวจสอบ SQLi เป็นต้น

ทำไม IIS จึงบล็อก

เครื่องหมายบวก (+) เป็นอักขระสงวนต่อRFC2396 :

URI จำนวนมากมีส่วนประกอบที่ประกอบด้วยหรือคั่นด้วยอักขระพิเศษบางตัว อักขระเหล่านี้เรียกว่า "สงวน" เนื่องจากการใช้งานภายในคอมโพเนนต์ URI ถูก จำกัด ไว้ตามวัตถุประสงค์ที่สงวนไว้ หากข้อมูลสำหรับคอมโพเนนต์ URI ขัดแย้งกับวัตถุประสงค์ที่สงวนไว้ข้อมูลที่ขัดแย้งนั้นจะต้องถูกหลบหนีก่อนที่จะสร้าง URI

  reserved    = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
                "$" | ","

Wade Hilmo มีโพสต์ที่ยอดเยี่ยมที่ชื่อว่าIIS บล็อกอักขระใน URLอย่างไร มีข้อมูลและภูมิหลังมากมายให้ ส่วนเฉพาะสำหรับเครื่องหมายบวกมีดังนี้:

ดังนั้น allowDoubleEscaping / VerifyNormalization จึงค่อนข้างตรงไปตรงมา ทำไมฉันถึงบอกว่ามันทำให้เกิดความสับสน? ปัญหาคือเมื่ออักขระ "+" ปรากฏใน URL อักขระ '+' ดูเหมือนจะไม่ถูกหลีกเลี่ยงเนื่องจากไม่มีส่วนเกี่ยวข้องกับ '%' นอกจากนี้ RFC 2396 ยังบันทึกว่าเป็นอักขระสงวนที่สามารถรวมไว้ใน URL เมื่ออยู่ในรูปแบบ Escape (% 2b) แต่ด้วยการตั้งค่า allowDoubleEscaping เป็นค่าเริ่มต้นเป็นเท็จเราจะบล็อกแม้ในรูปแบบที่ใช้ Escape เหตุผลนี้เป็นไปตามประวัติศาสตร์: ย้อนกลับไปในยุคแรก ๆ ของ HTTP อักขระ "+" ถือเป็นชวเลขสำหรับอักขระเว้นวรรค ผู้บัญญัติศัพท์บางตัวเมื่อกำหนด URL ที่มีเครื่องหมาย "+" จะแปลงเป็นช่องว่าง ด้วยเหตุนี้เราจึงถือว่า "+" ไม่ใช่รูปแบบบัญญัติใน URL ฉันไม่พบข้อมูลอ้างอิงใด ๆ เกี่ยวกับ RFC ที่เรียกการรักษานี้ว่า '+'

จากประสบการณ์ของฉันเองฉันรู้ว่าเมื่อ IIS บันทึกช่องว่างคำขอจะถูกแทนที่ด้วยเครื่องหมายบวก การมีเครื่องหมายบวกในชื่ออาจทำให้เกิดความสับสนเมื่อแยกวิเคราะห์บันทึก

วิธีการแก้

มีสามวิธีในการแก้ไขปัญหานี้และสองวิธีในการใช้เครื่องหมายบวก

  1. allowDoubleEscaping=true- สิ่งนี้จะช่วยให้สามารถหลบหนีได้สองเท่าสำหรับเว็บไซต์ / แอปพลิเคชันทั้งหมดของคุณ สิ่งนี้อาจเป็นสิ่งที่ไม่พึงปรารถนาที่จะพูดอย่างน้อยที่สุดทั้งนี้ขึ้นอยู่กับเนื้อหา allowDoubleEscaping=trueคำสั่งต่อไปจะตั้ง

    appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /allowDoubleEscaping:True
    
  2. alwaysAllowedUrls- การกรองคำขอเสนอแนวทางการอนุญาตพิเศษ โดยการเพิ่มเส้นทาง URL นั้นไปที่ alwaysAllowedUrls คำขอจะไม่ถูกตรวจสอบโดยการตั้งค่าการกรองคำขออื่น ๆ และดำเนินการต่อในไปป์ไลน์คำขอ IIS ข้อกังวลที่นี่คือการกรองคำขอจะไม่ตรวจสอบคำขอสำหรับ:

    • ขีด จำกัด การร้องขอ: maxContentLength, maxUrl, maxQueryString
    • กริยา
    • แบบสอบถาม - พารามิเตอร์สตริงการสืบค้นจะไม่ถูกตรวจสอบ
    • การหลบหนีสองครั้ง
    • อักขระบิตสูง
    • ขอกฎการกรอง
    • ขอขีด จำกัด ส่วนหัว

    คำสั่งต่อไปจะเพิ่ม/product/tags/for+familiesการalwaysAllowedUrlsบนเว็บไซต์เริ่มต้น

    appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /+"alwaysAllowedUrls.[url='/product/tags/for+families']"
    
  3. เปลี่ยนชื่อ - ใช่เพียงเปลี่ยนชื่อไฟล์ / โฟลเดอร์ / คอนโทรลเลอร์ / ฯลฯ ถ้าเป็นไปได้. นี่เป็นวิธีแก้ปัญหาที่ง่ายที่สุด


ในการ AllowDoubleEscaping ระหว่างการพัฒนาด้วย IIS Express นี่คือสิ่งที่ฉันทำ: stackoverflow.com/q/56463044/381082
DeveloperDan

5

ฉันได้เตรียมงานสำหรับสิ่งนี้แล้ว ดังนั้นเมื่อคุณต้องการใส่สตริงที่เข้ารหัสไว้ใน url สำหรับ (IIS) คุณต้องทำความสะอาดไม่ให้สกปรก: {";", "/", "?", ":", "@", "&", " = "," + "," $ ",", "}; และเมื่อคุณต้องการถอดรหัสและใช้อีกครั้งคุณต้องทำให้สกปรกอีกครั้งก่อนที่จะถอดรหัส (เพื่อให้ได้ผลลัพธ์ที่ต้องการ)

นี่คือรหัสของฉันฉันหวังว่ามันจะช่วยใครสักคน:

 public static string cleanUpEncription(string encriptedstring)
        {
            string[] dirtyCharacters = { ";", "/", "?", ":", "@", "&", "=", "+", "$", "," };
            string[] cleanCharacters = { "p2n3t4G5l6m","s1l2a3s4h","q1e2st3i4o5n" ,"T22p14nt2s", "a9t" , "a2n3nd","e1q2ua88l","p22l33u1ws","d0l1ar5","c0m8a1a"};

            foreach (string dirtyCharacter in dirtyCharacters)
            {
                encriptedstring=encriptedstring.Replace(dirtyCharacter, cleanCharacters[Array.IndexOf(dirtyCharacters, dirtyCharacter)]);
            }
            return encriptedstring;
        }

        public static string MakeItDirtyAgain(string encriptedString)
        {
            string[] dirtyCharacters = { ";", "/", "?", ":", "@", "&", "=", "+", "$", "," };
            string[] cleanCharacters = { "p2n3t4G5l6m", "s1l2a3s4h", "q1e2st3i4o5n", "T22p14nt2s", "a9t", "a2n3nd", "e1q2ua88l", "p22l33u1ws", "d0l1ar5", "c0m8a1a" };
            foreach (string symbol in cleanCharacters)
            {
                encriptedString = encriptedString.Replace(symbol, dirtyCharacters[Array.IndexOf(cleanCharacters,symbol)]);
            }
            return encriptedString;
        }

pntGlm คืออะไร?
StuperUser

@StuperUser สุ่มตัวละคร
Mark Dibeh

1
ควรbase64เข้ารหัสสตริงแทนที่จะใช้เทคนิคการทดแทนนี้ ตัวอย่างเช่นการรับรองความถูกต้องพื้นฐานใช้base64ในการเข้ารหัสข้อมูลประจำตัวที่ส่งเนื่องจากอาจมีอักขระพิเศษ / สงวนไว้
user2320464

ปัญหาเกี่ยวกับ base64 คือ / เป็นอักขระ base64 และสามารถทำลายเส้นทางได้
Garr Godfrey

1

ดังนั้นฉันจึงพบสิ่งนี้เมื่อฉันเรียก API จากแอป MVC แทนที่จะเปิดช่องโหว่ฉันได้แก้ไขเส้นทางของฉัน

ก่อนอื่นขอแนะนำว่าอย่าปิดการตั้งค่านี้ การปรับเปลี่ยนการออกแบบแอปพลิเคชัน / ทรัพยากรจะเหมาะสมกว่า (เช่นเข้ารหัสเส้นทางส่งผ่านข้อมูลในส่วนหัวหรือในเนื้อหา)

แม้ว่านี่จะเป็นโพสต์เก่าผมคิดว่าฉันจะแบ่งปันวิธีการที่คุณสามารถแก้ไขข้อผิดพลาดนี้ถ้าคุณได้รับจากการโทรไปยัง API โดยใช้HttpUtility.UrlPathEncodeวิธีการในSystem.Web

ฉันใช้RestSharpในการโทรออกดังนั้นตัวอย่างของฉันจึงใช้ RestRequest:

var tags = new[] { "for", "family" };
var apiRequest = new RestRequest($"product/tags/{HttpUtility.UrlPathEncode(string.Join("+", tags))}");

สิ่งนี้สร้างเส้นทางที่เท่ากับ:

/ product / tags / สำหรับ% 2Bfamilies

ในหมายเหตุอื่นอย่าสร้างแบบสอบถามแบบไดนามิกตามอินพุตของผู้ใช้ คุณควรใช้SqlParameterเสมอ นอกจากนี้สิ่งสำคัญอย่างยิ่งจากมุมมองด้านความปลอดภัยในการคืนค่าด้วยการเข้ารหัสที่เหมาะสมเพื่อป้องกันการโจมตีด้วยการฉีด

~ ไชโย


0

เข้ารหัสสตริงที่เข้ารหัสแยกออกจากกัน:

return HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes("string"));

ถอดรหัสสตริงที่เข้ารหัสแยกออกจากกัน:

string x = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(id));
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.